001    /*
002     * Copyright 2010-2015 JetBrains s.r.o.
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License");
005     * you may not use this file except in compliance with the License.
006     * You may obtain a copy of the License at
007     *
008     * http://www.apache.org/licenses/LICENSE-2.0
009     *
010     * Unless required by applicable law or agreed to in writing, software
011     * distributed under the License is distributed on an "AS IS" BASIS,
012     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     * See the License for the specific language governing permissions and
014     * limitations under the License.
015     */
016    
017    package org.jetbrains.kotlin.codegen;
018    
019    import com.google.common.collect.Lists;
020    import com.intellij.util.ArrayUtil;
021    import kotlin.KotlinPackage;
022    import kotlin.Unit;
023    import kotlin.jvm.functions.Function1;
024    import org.jetbrains.annotations.NotNull;
025    import org.jetbrains.annotations.Nullable;
026    import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
027    import org.jetbrains.kotlin.codegen.context.ClosureContext;
028    import org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil;
029    import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
030    import org.jetbrains.kotlin.codegen.state.GenerationState;
031    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
032    import org.jetbrains.kotlin.descriptors.*;
033    import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
034    import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
035    import org.jetbrains.kotlin.load.java.JvmAbi;
036    import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
037    import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
038    import org.jetbrains.kotlin.psi.JetElement;
039    import org.jetbrains.kotlin.resolve.BindingContext;
040    import org.jetbrains.kotlin.resolve.DescriptorUtils;
041    import org.jetbrains.kotlin.resolve.scopes.JetScope;
042    import org.jetbrains.kotlin.serialization.DescriptorSerializer;
043    import org.jetbrains.kotlin.serialization.ProtoBuf;
044    import org.jetbrains.kotlin.serialization.jvm.BitEncoding;
045    import org.jetbrains.kotlin.types.JetType;
046    import org.jetbrains.kotlin.types.expressions.OperatorConventions;
047    import org.jetbrains.kotlin.utils.UtilsPackage;
048    import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
049    import org.jetbrains.org.objectweb.asm.MethodVisitor;
050    import org.jetbrains.org.objectweb.asm.Type;
051    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
052    import org.jetbrains.org.objectweb.asm.commons.Method;
053    
054    import java.util.ArrayList;
055    import java.util.Collections;
056    import java.util.List;
057    
058    import static org.jetbrains.kotlin.codegen.AsmUtil.*;
059    import static org.jetbrains.kotlin.codegen.ExpressionCodegen.generateClassLiteralReference;
060    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConst;
061    import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLOSURE;
062    import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass;
063    import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass;
064    import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns;
065    import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
066    import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.OtherOrigin;
067    import static org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.NO_ORIGIN;
068    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
069    
070    public class ClosureCodegen extends MemberCodegen<JetElement> {
071        private final FunctionDescriptor funDescriptor;
072        private final ClassDescriptor classDescriptor;
073        private final SamType samType;
074        private final JetType superClassType;
075        private final List<JetType> superInterfaceTypes;
076        private final FunctionDescriptor functionReferenceTarget;
077        private final FunctionGenerationStrategy strategy;
078        private final CalculatedClosure closure;
079        private final Type asmType;
080        private final int visibilityFlag;
081        private final KotlinSyntheticClass.Kind syntheticClassKind;
082    
083        private Method constructor;
084        private Type superClassAsmType;
085    
086        public ClosureCodegen(
087                @NotNull GenerationState state,
088                @NotNull JetElement element,
089                @Nullable SamType samType,
090                @NotNull ClosureContext context,
091                @NotNull KotlinSyntheticClass.Kind syntheticClassKind,
092                @Nullable FunctionDescriptor functionReferenceTarget,
093                @NotNull FunctionGenerationStrategy strategy,
094                @NotNull MemberCodegen<?> parentCodegen,
095                @NotNull ClassBuilder classBuilder
096        ) {
097            super(state, parentCodegen, context, element, classBuilder);
098    
099            this.funDescriptor = context.getFunctionDescriptor();
100            this.classDescriptor = context.getContextDescriptor();
101            this.samType = samType;
102            this.syntheticClassKind = syntheticClassKind;
103            this.functionReferenceTarget = functionReferenceTarget;
104            this.strategy = strategy;
105    
106            if (samType == null) {
107                this.superInterfaceTypes = new ArrayList<JetType>();
108    
109                JetType superClassType = null;
110                for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
111                    ClassifierDescriptor classifier = supertype.getConstructor().getDeclarationDescriptor();
112                    if (DescriptorUtils.isTrait(classifier)) {
113                        superInterfaceTypes.add(supertype);
114                    }
115                    else {
116                        assert superClassType == null : "Closure class can't have more than one superclass: " + funDescriptor;
117                        superClassType = supertype;
118                    }
119                }
120                assert superClassType != null : "Closure class should have a superclass: " + funDescriptor;
121    
122                this.superClassType = superClassType;
123            }
124            else {
125                this.superInterfaceTypes = Collections.singletonList(samType.getType());
126                this.superClassType = getBuiltIns(funDescriptor).getAnyType();
127            }
128    
129            this.closure = bindingContext.get(CLOSURE, classDescriptor);
130            assert closure != null : "Closure must be calculated for class: " + classDescriptor;
131    
132            this.asmType = typeMapper.mapClass(classDescriptor);
133    
134            visibilityFlag = AsmUtil.getVisibilityAccessFlagForAnonymous(classDescriptor);
135        }
136    
137        @Override
138        protected void generateDeclaration() {
139            BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS);
140            if (samType != null) {
141                typeMapper.writeFormalTypeParameters(samType.getType().getConstructor().getParameters(), sw);
142            }
143            sw.writeSuperclass();
144            superClassAsmType = typeMapper.mapSupertype(superClassType, sw);
145            sw.writeSuperclassEnd();
146            String[] superInterfaceAsmTypes = new String[superInterfaceTypes.size()];
147            for (int i = 0; i < superInterfaceTypes.size(); i++) {
148                JetType superInterfaceType = superInterfaceTypes.get(i);
149                sw.writeInterface();
150                superInterfaceAsmTypes[i] = typeMapper.mapSupertype(superInterfaceType, sw).getInternalName();
151                sw.writeInterfaceEnd();
152            }
153    
154            v.defineClass(element,
155                          V1_6,
156                          ACC_FINAL | ACC_SUPER | visibilityFlag,
157                          asmType.getInternalName(),
158                          sw.makeJavaGenericSignature(),
159                          superClassAsmType.getInternalName(),
160                          superInterfaceAsmTypes
161            );
162    
163            InlineCodegenUtil.initDefaultSourceMappingIfNeeded(context, this, state);
164    
165            v.visitSource(element.getContainingFile().getName(), null);
166        }
167    
168        @Nullable
169        @Override
170        protected ClassDescriptor classForInnerClassRecord() {
171            return JvmCodegenUtil.isArgumentWhichWillBeInlined(bindingContext, funDescriptor) ? null : classDescriptor;
172        }
173    
174        @Override
175        protected void generateBody() {
176            FunctionDescriptor erasedInterfaceFunction;
177            if (samType == null) {
178                erasedInterfaceFunction = getErasedInvokeFunction(funDescriptor);
179            }
180            else {
181                erasedInterfaceFunction = samType.getAbstractMethod().getOriginal();
182            }
183    
184            generateBridge(
185                    typeMapper.mapSignature(erasedInterfaceFunction).getAsmMethod(),
186                    typeMapper.mapSignature(funDescriptor).getAsmMethod()
187            );
188    
189            functionCodegen.generateMethod(OtherOrigin(element, funDescriptor), funDescriptor, strategy);
190    
191            //TODO: rewrite cause ugly hack
192            if (samType != null) {
193                SimpleFunctionDescriptorImpl descriptorForBridges = SimpleFunctionDescriptorImpl
194                        .create(funDescriptor.getContainingDeclaration(), funDescriptor.getAnnotations(),
195                                erasedInterfaceFunction.getName(),
196                                CallableMemberDescriptor.Kind.DECLARATION, funDescriptor.getSource());
197    
198                descriptorForBridges
199                        .initialize(null, erasedInterfaceFunction.getDispatchReceiverParameter(), erasedInterfaceFunction.getTypeParameters(),
200                                    erasedInterfaceFunction.getValueParameters(), erasedInterfaceFunction.getReturnType(),
201                                    Modality.OPEN, erasedInterfaceFunction.getVisibility(), false);
202    
203                descriptorForBridges.addOverriddenDescriptor(erasedInterfaceFunction);
204                functionCodegen.generateBridges(descriptorForBridges);
205            }
206    
207            if (functionReferenceTarget != null) {
208                generateFunctionReferenceMethods(functionReferenceTarget);
209            }
210    
211            this.constructor = generateConstructor();
212    
213            if (isConst(closure)) {
214                generateConstInstance(asmType, asmType, UtilsPackage.<InstructionAdapter>doNothing());
215            }
216    
217            genClosureFields(closure, v, typeMapper);
218    
219            functionCodegen.generateDefaultIfNeeded(
220                    context.intoFunction(funDescriptor), funDescriptor, context.getContextKind(), DefaultParameterValueLoader.DEFAULT, null
221            );
222        }
223    
224        @Override
225        protected void generateKotlinAnnotation() {
226            writeKotlinSyntheticClassAnnotation(v, syntheticClassKind);
227    
228            DescriptorSerializer serializer =
229                    DescriptorSerializer.createTopLevel(new JvmSerializerExtension(v.getSerializationBindings(), typeMapper));
230    
231            ProtoBuf.Callable callableProto = serializer.callableProto(funDescriptor).build();
232    
233            AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_CALLABLE), true);
234            JvmCodegenUtil.writeAbiVersion(av);
235            AnnotationVisitor array = av.visitArray(JvmAnnotationNames.DATA_FIELD_NAME);
236            for (String string : BitEncoding.encodeBytes(serializer.serialize(callableProto))) {
237                array.visit(null, string);
238            }
239            array.visitEnd();
240            av.visitEnd();
241        }
242    
243        @Override
244        protected void done() {
245            writeOuterClassAndEnclosingMethod();
246            super.done();
247        }
248    
249        @NotNull
250        public StackValue putInstanceOnStack(@NotNull final ExpressionCodegen codegen) {
251            return StackValue.operation(
252                    functionReferenceTarget != null ? K_FUNCTION : asmType,
253                    new Function1<InstructionAdapter, Unit>() {
254                        @Override
255                        public Unit invoke(InstructionAdapter v) {
256                            if (isConst(closure)) {
257                                v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
258                            }
259                            else {
260                                v.anew(asmType);
261                                v.dup();
262    
263                                codegen.pushClosureOnStack(classDescriptor, true, codegen.defaultCallGenerator);
264                                v.invokespecial(asmType.getInternalName(), "<init>", constructor.getDescriptor(), false);
265                            }
266    
267                            if (functionReferenceTarget != null) {
268                                v.invokestatic(REFLECTION, "function", Type.getMethodDescriptor(K_FUNCTION, FUNCTION_REFERENCE), false);
269                            }
270    
271                            return Unit.INSTANCE$;
272                        }
273                    }
274            );
275        }
276    
277        private void generateBridge(@NotNull Method bridge, @NotNull Method delegate) {
278            if (bridge.equals(delegate)) return;
279    
280            MethodVisitor mv =
281                    v.newMethod(OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE,
282                                bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY);
283    
284            if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
285    
286            mv.visitCode();
287    
288            InstructionAdapter iv = new InstructionAdapter(mv);
289            ImplementationBodyCodegen.markLineNumberForSyntheticFunction(DescriptorUtils.getParentOfType(funDescriptor, ClassDescriptor.class), iv);
290    
291            iv.load(0, asmType);
292    
293            Type[] myParameterTypes = bridge.getArgumentTypes();
294    
295            List<ParameterDescriptor> calleeParameters = KotlinPackage.plus(
296                    UtilsPackage.<ParameterDescriptor>singletonOrEmptyList(funDescriptor.getExtensionReceiverParameter()),
297                    funDescriptor.getValueParameters()
298            );
299    
300            int slot = 1;
301            for (int i = 0; i < calleeParameters.size(); i++) {
302                Type type = myParameterTypes[i];
303                StackValue.local(slot, type).put(typeMapper.mapType(calleeParameters.get(i)), iv);
304                slot += type.getSize();
305            }
306    
307            iv.invokevirtual(asmType.getInternalName(), delegate.getName(), delegate.getDescriptor(), false);
308            StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv);
309    
310            iv.areturn(bridge.getReturnType());
311    
312            FunctionCodegen.endVisit(mv, "bridge", element);
313        }
314    
315        // TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction?
316        private void generateFunctionReferenceMethods(@NotNull FunctionDescriptor descriptor) {
317            int flags = ACC_PUBLIC | ACC_FINAL;
318            boolean generateBody = state.getClassBuilderMode() == ClassBuilderMode.FULL;
319    
320            {
321                MethodVisitor mv =
322                        v.newMethod(NO_ORIGIN, flags, "getOwner", Type.getMethodDescriptor(K_DECLARATION_CONTAINER_TYPE), null, null);
323                if (generateBody) {
324                    mv.visitCode();
325                    InstructionAdapter iv = new InstructionAdapter(mv);
326                    generateCallableReferenceDeclarationContainer(iv, descriptor, typeMapper);
327                    iv.areturn(K_DECLARATION_CONTAINER_TYPE);
328                    FunctionCodegen.endVisit(iv, "function reference getOwner", element);
329                }
330            }
331    
332            {
333                MethodVisitor mv =
334                        v.newMethod(NO_ORIGIN, flags, "getName", Type.getMethodDescriptor(JAVA_STRING_TYPE), null, null);
335                if (generateBody) {
336                    mv.visitCode();
337                    InstructionAdapter iv = new InstructionAdapter(mv);
338                    iv.aconst(descriptor.getName().asString());
339                    iv.areturn(JAVA_STRING_TYPE);
340                    FunctionCodegen.endVisit(iv, "function reference getName", element);
341                }
342            }
343    
344            {
345                MethodVisitor mv = v.newMethod(NO_ORIGIN, flags, "getSignature", Type.getMethodDescriptor(JAVA_STRING_TYPE), null, null);
346                if (generateBody) {
347                    mv.visitCode();
348                    InstructionAdapter iv = new InstructionAdapter(mv);
349                    Method method = typeMapper.mapSignature(descriptor.getOriginal()).getAsmMethod();
350                    iv.aconst(method.getName() + method.getDescriptor());
351                    iv.areturn(JAVA_STRING_TYPE);
352                    FunctionCodegen.endVisit(iv, "function reference getSignature", element);
353                }
354            }
355        }
356    
357        public static void generateCallableReferenceDeclarationContainer(
358                @NotNull InstructionAdapter iv,
359                @NotNull CallableDescriptor descriptor,
360                @NotNull JetTypeMapper typeMapper
361        ) {
362            DeclarationDescriptor container = descriptor.getContainingDeclaration();
363            if (container instanceof ClassDescriptor) {
364                // TODO: getDefaultType() here is wrong and won't work for arrays
365                StackValue value = generateClassLiteralReference(typeMapper, ((ClassDescriptor) container).getDefaultType());
366                value.put(K_CLASS_TYPE, iv);
367            }
368            else if (container instanceof PackageFragmentDescriptor) {
369                String packageClassInternalName = PackageClassUtils.getPackageClassInternalName(
370                        ((PackageFragmentDescriptor) container).getFqName()
371                );
372                iv.getstatic(packageClassInternalName, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, K_PACKAGE_TYPE.getDescriptor());
373            }
374            else if (container instanceof ScriptDescriptor) {
375                // TODO: correct container for scripts (KScript?)
376                StackValue value = generateClassLiteralReference(
377                        typeMapper, ((ScriptDescriptor) container).getClassDescriptor().getDefaultType()
378                );
379                value.put(K_CLASS_TYPE, iv);
380            }
381            else {
382                iv.aconst(null);
383            }
384        }
385    
386        @NotNull
387        private Method generateConstructor() {
388            List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType);
389    
390            Type[] argTypes = fieldListToTypeArray(args);
391    
392            Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes);
393            MethodVisitor mv = v.newMethod(OtherOrigin(element, funDescriptor), visibilityFlag, "<init>", constructor.getDescriptor(), null,
394                                            ArrayUtil.EMPTY_STRING_ARRAY);
395            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
396                mv.visitCode();
397                InstructionAdapter iv = new InstructionAdapter(mv);
398    
399                int k = 1;
400                for (FieldInfo fieldInfo : args) {
401                    k = genAssignInstanceFieldFromParam(fieldInfo, k, iv);
402                }
403    
404                iv.load(0, superClassAsmType);
405    
406                if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE)) {
407                    int arity = funDescriptor.getValueParameters().size();
408                    if (funDescriptor.getExtensionReceiverParameter() != null) arity++;
409                    if (funDescriptor.getDispatchReceiverParameter() != null) arity++;
410                    iv.iconst(arity);
411                    iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "(I)V", false);
412                }
413                else {
414                    iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false);
415                }
416    
417                iv.visitInsn(RETURN);
418    
419                FunctionCodegen.endVisit(iv, "constructor", element);
420            }
421            return constructor;
422        }
423    
424        @NotNull
425        public static List<FieldInfo> calculateConstructorParameters(
426                @NotNull JetTypeMapper typeMapper,
427                @NotNull CalculatedClosure closure,
428                @NotNull Type ownerType
429        ) {
430            BindingContext bindingContext = typeMapper.getBindingContext();
431            List<FieldInfo> args = Lists.newArrayList();
432            ClassDescriptor captureThis = closure.getCaptureThis();
433            if (captureThis != null) {
434                Type type = typeMapper.mapType(captureThis);
435                args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD));
436            }
437            JetType captureReceiverType = closure.getCaptureReceiverType();
438            if (captureReceiverType != null) {
439                args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), CAPTURED_RECEIVER_FIELD));
440            }
441    
442            for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
443                if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
444                    Type sharedVarType = typeMapper.getSharedVarType(descriptor);
445    
446                    Type type = sharedVarType != null
447                                      ? sharedVarType
448                                      : typeMapper.mapType((VariableDescriptor) descriptor);
449                    args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString()));
450                }
451                else if (DescriptorUtils.isLocalFunction(descriptor)) {
452                    Type classType = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
453                    args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString()));
454                }
455                else if (descriptor instanceof FunctionDescriptor) {
456                    assert captureReceiverType != null;
457                }
458            }
459            return args;
460        }
461    
462        private static Type[] fieldListToTypeArray(List<FieldInfo> args) {
463            Type[] argTypes = new Type[args.size()];
464            for (int i = 0; i != argTypes.length; ++i) {
465                argTypes[i] = args.get(i).getFieldType();
466            }
467            return argTypes;
468        }
469    
470        @NotNull
471        public static FunctionDescriptor getErasedInvokeFunction(@NotNull FunctionDescriptor elementDescriptor) {
472            int arity = elementDescriptor.getValueParameters().size();
473            ClassDescriptor elementClass = elementDescriptor.getExtensionReceiverParameter() == null
474                                       ? getBuiltIns(elementDescriptor).getFunction(arity)
475                                       : getBuiltIns(elementDescriptor).getExtensionFunction(arity);
476            JetScope scope = elementClass.getDefaultType().getMemberScope();
477            return scope.getFunctions(OperatorConventions.INVOKE, NoLookupLocation.FROM_BACKEND).iterator().next();
478        }
479    }