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