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