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