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