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.signature.JvmSignatureWriter; 032 import org.jetbrains.kotlin.codegen.state.GenerationState; 033 import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; 034 import org.jetbrains.kotlin.descriptors.*; 035 import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl; 036 import org.jetbrains.kotlin.incremental.components.NoLookupLocation; 037 import org.jetbrains.kotlin.load.java.JvmAbi; 038 import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader; 039 import org.jetbrains.kotlin.psi.KtElement; 040 import org.jetbrains.kotlin.resolve.BindingContext; 041 import org.jetbrains.kotlin.resolve.DescriptorUtils; 042 import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; 043 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; 044 import org.jetbrains.kotlin.resolve.scopes.MemberScope; 045 import org.jetbrains.kotlin.serialization.DescriptorSerializer; 046 import org.jetbrains.kotlin.serialization.ProtoBuf; 047 import org.jetbrains.kotlin.types.KotlinType; 048 import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils; 049 import org.jetbrains.kotlin.util.OperatorNameConventions; 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.binding.CodegenBinding.CLOSURE; 064 import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.asmTypeForAnonymousClass; 065 import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION; 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.getVisibilityAccessFlagForClass(classDescriptor); 132 } 133 134 @Override 135 protected void generateDeclaration() { 136 JvmSignatureWriter 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.mapAsmMethod(erasedInterfaceFunction), 183 typeMapper.mapAsmMethod(funDescriptor) 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 DescriptorUtilsKt.setSingleOverridden(descriptorForBridges, 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); 216 } 217 218 genClosureFields(closure, v, typeMapper); 219 } 220 221 @Override 222 protected void generateKotlinMetadataAnnotation() { 223 FunctionDescriptor freeLambdaDescriptor = createFreeLambdaDescriptor(funDescriptor); 224 Method method = v.getSerializationBindings().get(METHOD_FOR_FUNCTION, funDescriptor); 225 assert method != null : "No method for " + funDescriptor; 226 v.getSerializationBindings().put(METHOD_FOR_FUNCTION, freeLambdaDescriptor, method); 227 228 final DescriptorSerializer serializer = 229 DescriptorSerializer.createForLambda(new JvmSerializerExtension(v.getSerializationBindings(), state)); 230 231 final ProtoBuf.Function functionProto = serializer.functionProto(freeLambdaDescriptor).build(); 232 233 WriteAnnotationUtilKt.writeKotlinMetadata(v, KotlinClassHeader.Kind.SYNTHETIC_CLASS, new Function1<AnnotationVisitor, Unit>() { 234 @Override 235 public Unit invoke(AnnotationVisitor av) { 236 writeAnnotationData(av, serializer, functionProto); 237 return Unit.INSTANCE; 238 } 239 }); 240 } 241 242 /** 243 * Given a function descriptor, creates another function descriptor with type parameters copied from outer context(s). 244 * This is needed because once we're serializing this to a proto, there's no place to store information about external type parameters. 245 */ 246 @NotNull 247 private static FunctionDescriptor createFreeLambdaDescriptor(@NotNull FunctionDescriptor descriptor) { 248 FunctionDescriptor.CopyBuilder<? extends FunctionDescriptor> builder = descriptor.newCopyBuilder(); 249 List<TypeParameterDescriptor> typeParameters = new ArrayList<TypeParameterDescriptor>(0); 250 builder.setTypeParameters(typeParameters); 251 252 DeclarationDescriptor container = descriptor.getContainingDeclaration(); 253 while (container != null) { 254 if (container instanceof ClassDescriptor) { 255 typeParameters.addAll(((ClassDescriptor) container).getDeclaredTypeParameters()); 256 } 257 else if (container instanceof CallableDescriptor && !(container instanceof ConstructorDescriptor)) { 258 typeParameters.addAll(((CallableDescriptor) container).getTypeParameters()); 259 } 260 container = container.getContainingDeclaration(); 261 } 262 263 return typeParameters.isEmpty() ? descriptor : builder.build(); 264 } 265 266 @Override 267 protected void done() { 268 writeOuterClassAndEnclosingMethod(); 269 super.done(); 270 } 271 272 @NotNull 273 public StackValue putInstanceOnStack(@NotNull final ExpressionCodegen codegen) { 274 return StackValue.operation( 275 functionReferenceTarget != null ? K_FUNCTION : asmType, 276 new Function1<InstructionAdapter, Unit>() { 277 @Override 278 public Unit invoke(InstructionAdapter v) { 279 if (isConst(closure)) { 280 v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor()); 281 } 282 else { 283 v.anew(asmType); 284 v.dup(); 285 286 codegen.pushClosureOnStack(classDescriptor, true, codegen.defaultCallGenerator); 287 v.invokespecial(asmType.getInternalName(), "<init>", constructor.getDescriptor(), false); 288 } 289 290 return Unit.INSTANCE; 291 } 292 } 293 ); 294 } 295 296 private void generateBridge(@NotNull Method bridge, @NotNull Method delegate) { 297 if (bridge.equals(delegate)) return; 298 299 MethodVisitor mv = 300 v.newMethod(JvmDeclarationOriginKt.OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC, 301 bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY); 302 303 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 304 305 mv.visitCode(); 306 307 InstructionAdapter iv = new InstructionAdapter(mv); 308 MemberCodegen.markLineNumberForDescriptor(DescriptorUtils.getParentOfType(funDescriptor, ClassDescriptor.class), iv); 309 310 iv.load(0, asmType); 311 312 Type[] myParameterTypes = bridge.getArgumentTypes(); 313 314 List<ParameterDescriptor> calleeParameters = CollectionsKt.plus( 315 org.jetbrains.kotlin.utils.CollectionsKt.<ParameterDescriptor>singletonOrEmptyList(funDescriptor.getExtensionReceiverParameter()), 316 funDescriptor.getValueParameters() 317 ); 318 319 int slot = 1; 320 for (int i = 0; i < calleeParameters.size(); i++) { 321 Type type = myParameterTypes[i]; 322 StackValue.local(slot, type).put(typeMapper.mapType(calleeParameters.get(i)), iv); 323 slot += type.getSize(); 324 } 325 326 iv.invokevirtual(asmType.getInternalName(), delegate.getName(), delegate.getDescriptor(), false); 327 StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv); 328 329 iv.areturn(bridge.getReturnType()); 330 331 FunctionCodegen.endVisit(mv, "bridge", element); 332 } 333 334 // TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction? 335 private void generateFunctionReferenceMethods(@NotNull FunctionDescriptor descriptor) { 336 int flags = ACC_PUBLIC | ACC_FINAL; 337 boolean generateBody = state.getClassBuilderMode() == ClassBuilderMode.FULL; 338 339 { 340 MethodVisitor mv = 341 v.newMethod(NO_ORIGIN, flags, "getOwner", Type.getMethodDescriptor(K_DECLARATION_CONTAINER_TYPE), null, null); 342 if (generateBody) { 343 mv.visitCode(); 344 InstructionAdapter iv = new InstructionAdapter(mv); 345 generateCallableReferenceDeclarationContainer(iv, descriptor, state); 346 iv.areturn(K_DECLARATION_CONTAINER_TYPE); 347 FunctionCodegen.endVisit(iv, "function reference getOwner", element); 348 } 349 } 350 351 { 352 MethodVisitor mv = 353 v.newMethod(NO_ORIGIN, flags, "getName", Type.getMethodDescriptor(JAVA_STRING_TYPE), null, null); 354 if (generateBody) { 355 mv.visitCode(); 356 InstructionAdapter iv = new InstructionAdapter(mv); 357 iv.aconst(descriptor.getName().asString()); 358 iv.areturn(JAVA_STRING_TYPE); 359 FunctionCodegen.endVisit(iv, "function reference getName", element); 360 } 361 } 362 363 { 364 MethodVisitor mv = v.newMethod(NO_ORIGIN, flags, "getSignature", Type.getMethodDescriptor(JAVA_STRING_TYPE), null, null); 365 if (generateBody) { 366 mv.visitCode(); 367 InstructionAdapter iv = new InstructionAdapter(mv); 368 Method method = typeMapper.mapAsmMethod(descriptor.getOriginal()); 369 iv.aconst(method.getName() + method.getDescriptor()); 370 iv.areturn(JAVA_STRING_TYPE); 371 FunctionCodegen.endVisit(iv, "function reference getSignature", element); 372 } 373 } 374 } 375 376 public static void generateCallableReferenceDeclarationContainer( 377 @NotNull InstructionAdapter iv, 378 @NotNull CallableDescriptor descriptor, 379 @NotNull GenerationState state 380 ) { 381 DeclarationDescriptor container = descriptor.getContainingDeclaration(); 382 if (container instanceof ClassDescriptor) { 383 // TODO: getDefaultType() here is wrong and won't work for arrays 384 StackValue value = generateClassLiteralReference(state.getTypeMapper(), ((ClassDescriptor) container).getDefaultType()); 385 value.put(K_CLASS_TYPE, iv); 386 } 387 else if (container instanceof PackageFragmentDescriptor) { 388 iv.aconst(state.getTypeMapper().mapOwner(descriptor)); 389 iv.aconst(state.getModuleName()); 390 iv.invokestatic(REFLECTION, "getOrCreateKotlinPackage", 391 Type.getMethodDescriptor(K_DECLARATION_CONTAINER_TYPE, getType(Class.class), getType(String.class)), false); 392 } 393 else { 394 iv.aconst(null); 395 } 396 } 397 398 @NotNull 399 private Method generateConstructor() { 400 List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType); 401 402 Type[] argTypes = fieldListToTypeArray(args); 403 404 Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes); 405 MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(element, funDescriptor), visibilityFlag, "<init>", constructor.getDescriptor(), null, 406 ArrayUtil.EMPTY_STRING_ARRAY); 407 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 408 mv.visitCode(); 409 InstructionAdapter iv = new InstructionAdapter(mv); 410 411 int k = 1; 412 for (FieldInfo fieldInfo : args) { 413 k = genAssignInstanceFieldFromParam(fieldInfo, k, iv); 414 } 415 416 iv.load(0, superClassAsmType); 417 418 if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE)) { 419 int arity = funDescriptor.getValueParameters().size(); 420 if (funDescriptor.getExtensionReceiverParameter() != null) arity++; 421 if (funDescriptor.getDispatchReceiverParameter() != null) arity++; 422 iv.iconst(arity); 423 iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "(I)V", false); 424 } 425 else { 426 iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false); 427 } 428 429 iv.visitInsn(RETURN); 430 431 FunctionCodegen.endVisit(iv, "constructor", element); 432 } 433 return constructor; 434 } 435 436 @NotNull 437 public static List<FieldInfo> calculateConstructorParameters( 438 @NotNull KotlinTypeMapper typeMapper, 439 @NotNull CalculatedClosure closure, 440 @NotNull Type ownerType 441 ) { 442 BindingContext bindingContext = typeMapper.getBindingContext(); 443 List<FieldInfo> args = Lists.newArrayList(); 444 ClassDescriptor captureThis = closure.getCaptureThis(); 445 if (captureThis != null) { 446 Type type = typeMapper.mapType(captureThis); 447 args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD)); 448 } 449 KotlinType captureReceiverType = closure.getCaptureReceiverType(); 450 if (captureReceiverType != null) { 451 args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), CAPTURED_RECEIVER_FIELD)); 452 } 453 454 for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) { 455 if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { 456 Type sharedVarType = typeMapper.getSharedVarType(descriptor); 457 458 Type type = sharedVarType != null 459 ? sharedVarType 460 : typeMapper.mapType((VariableDescriptor) descriptor); 461 args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString())); 462 } 463 else if (ExpressionTypingUtils.isLocalFunction(descriptor)) { 464 Type classType = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor); 465 args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString())); 466 } 467 else if (descriptor instanceof FunctionDescriptor) { 468 assert captureReceiverType != null; 469 } 470 } 471 return args; 472 } 473 474 private static Type[] fieldListToTypeArray(List<FieldInfo> args) { 475 Type[] argTypes = new Type[args.size()]; 476 for (int i = 0; i != argTypes.length; ++i) { 477 argTypes[i] = args.get(i).getFieldType(); 478 } 479 return argTypes; 480 } 481 482 @NotNull 483 public static FunctionDescriptor getErasedInvokeFunction(@NotNull FunctionDescriptor function) { 484 ClassDescriptor functionClass = DescriptorUtilsKt.getBuiltIns(function).getFunction( 485 function.getValueParameters().size() + (function.getExtensionReceiverParameter() != null ? 1 : 0) 486 ); 487 MemberScope scope = functionClass.getDefaultType().getMemberScope(); 488 return scope.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND).iterator().next(); 489 } 490 }