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