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.Function1;
022    import kotlin.Unit;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
026    import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
027    import org.jetbrains.kotlin.codegen.context.ClosureContext;
028    import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
029    import org.jetbrains.kotlin.codegen.state.GenerationState;
030    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
031    import org.jetbrains.kotlin.descriptors.*;
032    import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl;
033    import org.jetbrains.kotlin.load.java.JvmAbi;
034    import org.jetbrains.kotlin.name.Name;
035    import org.jetbrains.kotlin.psi.JetElement;
036    import org.jetbrains.kotlin.resolve.BindingContext;
037    import org.jetbrains.kotlin.resolve.DescriptorUtils;
038    import org.jetbrains.kotlin.types.JetType;
039    import org.jetbrains.org.objectweb.asm.MethodVisitor;
040    import org.jetbrains.org.objectweb.asm.Type;
041    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
042    import org.jetbrains.org.objectweb.asm.commons.Method;
043    
044    import java.util.ArrayList;
045    import java.util.Collections;
046    import java.util.List;
047    
048    import static org.jetbrains.kotlin.codegen.AsmUtil.*;
049    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isConst;
050    import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
051    import static org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass;
052    import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.OtherOrigin;
053    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
054    
055    public class ClosureCodegen extends MemberCodegen<JetElement> {
056        private final FunctionDescriptor funDescriptor;
057        private final ClassDescriptor classDescriptor;
058        private final SamType samType;
059        private final JetType superClassType;
060        private final List<JetType> superInterfaceTypes;
061        private final FunctionGenerationStrategy strategy;
062        private final CalculatedClosure closure;
063        private final Type asmType;
064        private final int visibilityFlag;
065        private final KotlinSyntheticClass.Kind syntheticClassKind;
066    
067        private Method constructor;
068        private Type superClassAsmType;
069    
070        public ClosureCodegen(
071                @NotNull GenerationState state,
072                @NotNull JetElement element,
073                @Nullable SamType samType,
074                @NotNull ClosureContext context,
075                @NotNull KotlinSyntheticClass.Kind syntheticClassKind,
076                @NotNull FunctionGenerationStrategy strategy,
077                @NotNull MemberCodegen<?> parentCodegen,
078                @NotNull ClassBuilder classBuilder
079        ) {
080            super(state, parentCodegen, context, element, classBuilder);
081    
082            this.funDescriptor = context.getFunctionDescriptor();
083            this.classDescriptor = context.getContextDescriptor();
084            this.samType = samType;
085            this.syntheticClassKind = syntheticClassKind;
086            this.strategy = strategy;
087    
088            if (samType == null) {
089                this.superInterfaceTypes = new ArrayList<JetType>();
090    
091                JetType superClassType = null;
092                for (JetType supertype : classDescriptor.getTypeConstructor().getSupertypes()) {
093                    ClassifierDescriptor classifier = supertype.getConstructor().getDeclarationDescriptor();
094                    if (DescriptorUtils.isTrait(classifier)) {
095                        superInterfaceTypes.add(supertype);
096                    }
097                    else {
098                        assert superClassType == null : "Closure class can't have more than one superclass: " + funDescriptor;
099                        superClassType = supertype;
100                    }
101                }
102                assert superClassType != null : "Closure class should have a superclass: " + funDescriptor;
103    
104                this.superClassType = superClassType;
105            }
106            else {
107                this.superInterfaceTypes = Collections.singletonList(samType.getType());
108                this.superClassType = KotlinBuiltIns.getInstance().getAnyType();
109            }
110    
111            this.closure = bindingContext.get(CLOSURE, classDescriptor);
112            assert closure != null : "Closure must be calculated for class: " + classDescriptor;
113    
114            this.asmType = typeMapper.mapClass(classDescriptor);
115    
116            visibilityFlag = AsmUtil.getVisibilityAccessFlagForAnonymous(classDescriptor);
117        }
118    
119        @Override
120        protected void generateDeclaration() {
121            BothSignatureWriter sw = new BothSignatureWriter(BothSignatureWriter.Mode.CLASS);
122            if (samType != null) {
123                typeMapper.writeFormalTypeParameters(samType.getType().getConstructor().getParameters(), sw);
124            }
125            sw.writeSuperclass();
126            superClassAsmType = typeMapper.mapSupertype(superClassType, sw);
127            sw.writeSuperclassEnd();
128            String[] superInterfaceAsmTypes = new String[superInterfaceTypes.size()];
129            for (int i = 0; i < superInterfaceTypes.size(); i++) {
130                JetType superInterfaceType = superInterfaceTypes.get(i);
131                sw.writeInterface();
132                superInterfaceAsmTypes[i] = typeMapper.mapSupertype(superInterfaceType, sw).getInternalName();
133                sw.writeInterfaceEnd();
134            }
135    
136            v.defineClass(element,
137                          V1_6,
138                          ACC_FINAL | ACC_SUPER | visibilityFlag,
139                          asmType.getInternalName(),
140                          sw.makeJavaGenericSignature(),
141                          superClassAsmType.getInternalName(),
142                          superInterfaceAsmTypes
143            );
144            v.visitSource(element.getContainingFile().getName(), null);
145        }
146    
147        @Nullable
148        @Override
149        protected ClassDescriptor classForInnerClassRecord() {
150            return JvmCodegenUtil.isLambdaWhichWillBeInlined(bindingContext, funDescriptor) ? null : classDescriptor;
151        }
152    
153        @Override
154        protected void generateBody() {
155            FunctionDescriptor erasedInterfaceFunction;
156            if (samType == null) {
157                erasedInterfaceFunction = getErasedInvokeFunction(funDescriptor);
158            }
159            else {
160                erasedInterfaceFunction = samType.getAbstractMethod().getOriginal();
161            }
162    
163            generateBridge(
164                    typeMapper.mapSignature(erasedInterfaceFunction).getAsmMethod(),
165                    typeMapper.mapSignature(funDescriptor).getAsmMethod()
166            );
167    
168            functionCodegen.generateMethod(OtherOrigin(element, funDescriptor), funDescriptor, strategy);
169    
170            //TODO: rewrite cause ugly hack
171            if (samType != null) {
172                SimpleFunctionDescriptorImpl descriptorForBridges = SimpleFunctionDescriptorImpl
173                        .create(funDescriptor.getContainingDeclaration(), funDescriptor.getAnnotations(),
174                                erasedInterfaceFunction.getName(),
175                                CallableMemberDescriptor.Kind.DECLARATION, funDescriptor.getSource());
176    
177                descriptorForBridges
178                        .initialize(null, erasedInterfaceFunction.getDispatchReceiverParameter(), erasedInterfaceFunction.getTypeParameters(),
179                                    erasedInterfaceFunction.getValueParameters(), erasedInterfaceFunction.getReturnType(), Modality.OPEN,
180                                    erasedInterfaceFunction.getVisibility());
181    
182                descriptorForBridges.addOverriddenDescriptor(erasedInterfaceFunction);
183                functionCodegen.generateBridges(descriptorForBridges);
184            }
185    
186            this.constructor = generateConstructor(superClassAsmType);
187    
188            if (isConst(closure)) {
189                generateConstInstance();
190            }
191    
192            genClosureFields(closure, v, typeMapper);
193    
194            functionCodegen.generateDefaultIfNeeded(
195                    context.intoFunction(funDescriptor), funDescriptor, context.getContextKind(), DefaultParameterValueLoader.DEFAULT, null
196            );
197        }
198    
199        @Override
200        protected void generateKotlinAnnotation() {
201            writeKotlinSyntheticClassAnnotation(v, syntheticClassKind);
202        }
203    
204        @Override
205        protected void done() {
206            writeOuterClassAndEnclosingMethod();
207            super.done();
208        }
209    
210        @NotNull
211        public StackValue putInstanceOnStack(@NotNull final ExpressionCodegen codegen) {
212            return StackValue.operation(asmType, new Function1<InstructionAdapter, Unit>() {
213                @Override
214                public Unit invoke(InstructionAdapter v) {
215                    if (isConst(closure)) {
216                        v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
217                    }
218                    else {
219                        v.anew(asmType);
220                        v.dup();
221    
222                        codegen.pushClosureOnStack(classDescriptor, true, codegen.defaultCallGenerator);
223                        v.invokespecial(asmType.getInternalName(), "<init>", constructor.getDescriptor(), false);
224                    }
225                    return Unit.INSTANCE$;
226                }
227            });
228        }
229    
230    
231        private void generateConstInstance() {
232            MethodVisitor mv = v.newMethod(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null, ArrayUtil.EMPTY_STRING_ARRAY);
233            InstructionAdapter iv = new InstructionAdapter(mv);
234    
235            v.newField(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), null, null);
236    
237            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
238                mv.visitCode();
239                iv.anew(asmType);
240                iv.dup();
241                iv.invokespecial(asmType.getInternalName(), "<init>", "()V", false);
242                iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
243                mv.visitInsn(RETURN);
244                FunctionCodegen.endVisit(mv, "<clinit>", element);
245            }
246        }
247    
248        private void generateBridge(@NotNull Method bridge, @NotNull Method delegate) {
249            if (bridge.equals(delegate)) return;
250    
251            MethodVisitor mv =
252                    v.newMethod(OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE, bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY);
253    
254            if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
255    
256            mv.visitCode();
257    
258            InstructionAdapter iv = new InstructionAdapter(mv);
259            ImplementationBodyCodegen.markLineNumberForSyntheticFunction(DescriptorUtils.getParentOfType(funDescriptor, ClassDescriptor.class), iv);
260    
261            iv.load(0, asmType);
262    
263            ReceiverParameterDescriptor receiver = funDescriptor.getExtensionReceiverParameter();
264            int count = 1;
265            if (receiver != null) {
266                StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(receiver.getType()), iv);
267                count++;
268            }
269    
270            List<ValueParameterDescriptor> params = funDescriptor.getValueParameters();
271            for (ValueParameterDescriptor param : params) {
272                StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(param.getType()), iv);
273                count++;
274            }
275    
276            iv.invokevirtual(asmType.getInternalName(), delegate.getName(), delegate.getDescriptor(), false);
277            StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv);
278    
279            iv.areturn(bridge.getReturnType());
280    
281            FunctionCodegen.endVisit(mv, "bridge", element);
282        }
283    
284        @NotNull
285        private Method generateConstructor(@NotNull Type superClassAsmType) {
286            List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType);
287    
288            Type[] argTypes = fieldListToTypeArray(args);
289    
290            Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes);
291            MethodVisitor mv = v.newMethod(OtherOrigin(element, funDescriptor), visibilityFlag, "<init>", constructor.getDescriptor(), null,
292                                            ArrayUtil.EMPTY_STRING_ARRAY);
293            if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
294                mv.visitCode();
295                InstructionAdapter iv = new InstructionAdapter(mv);
296    
297                int k = 1;
298                for (FieldInfo fieldInfo : args) {
299                    k = genAssignInstanceFieldFromParam(fieldInfo, k, iv);
300                }
301    
302                iv.load(0, superClassAsmType);
303                iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false);
304    
305                iv.visitInsn(RETURN);
306    
307                FunctionCodegen.endVisit(iv, "constructor", element);
308            }
309            return constructor;
310        }
311    
312        @NotNull
313        public static List<FieldInfo> calculateConstructorParameters(
314                @NotNull JetTypeMapper typeMapper,
315                @NotNull CalculatedClosure closure,
316                @NotNull Type ownerType
317        ) {
318            BindingContext bindingContext = typeMapper.getBindingContext();
319            List<FieldInfo> args = Lists.newArrayList();
320            ClassDescriptor captureThis = closure.getCaptureThis();
321            if (captureThis != null) {
322                Type type = typeMapper.mapType(captureThis);
323                args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD));
324            }
325            JetType captureReceiverType = closure.getCaptureReceiverType();
326            if (captureReceiverType != null) {
327                args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), CAPTURED_RECEIVER_FIELD));
328            }
329    
330            for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) {
331                if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) {
332                    Type sharedVarType = typeMapper.getSharedVarType(descriptor);
333    
334                    Type type = sharedVarType != null
335                                      ? sharedVarType
336                                      : typeMapper.mapType((VariableDescriptor) descriptor);
337                    args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString()));
338                }
339                else if (isLocalNamedFun(descriptor)) {
340                    Type classType = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
341                    args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString()));
342                }
343                else if (descriptor instanceof FunctionDescriptor) {
344                    assert captureReceiverType != null;
345                }
346            }
347            return args;
348        }
349    
350        private static Type[] fieldListToTypeArray(List<FieldInfo> args) {
351            Type[] argTypes = new Type[args.size()];
352            for (int i = 0; i != argTypes.length; ++i) {
353                argTypes[i] = args.get(i).getFieldType();
354            }
355            return argTypes;
356        }
357    
358        @NotNull
359        public static FunctionDescriptor getErasedInvokeFunction(@NotNull FunctionDescriptor elementDescriptor) {
360            int arity = elementDescriptor.getValueParameters().size();
361            ClassDescriptor elementClass = elementDescriptor.getExtensionReceiverParameter() == null
362                                       ? KotlinBuiltIns.getInstance().getFunction(arity)
363                                       : KotlinBuiltIns.getInstance().getExtensionFunction(arity);
364            return elementClass.getDefaultType().getMemberScope().getFunctions(Name.identifier("invoke")).iterator().next();
365        }
366    }