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