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