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