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