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.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.kotlin.utils.FunctionsKt; 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.JvmCodegenUtil.writeModuleName; 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.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.getVisibilityAccessFlagForAnonymous(classDescriptor); 132 } 133 134 @Override 135 protected void generateDeclaration() { 136 BothSignatureWriter 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.mapSignature(erasedInterfaceFunction).getAsmMethod(), 183 typeMapper.mapSignature(funDescriptor).getAsmMethod() 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 descriptorForBridges.addOverriddenDescriptor(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, FunctionsKt.<InstructionAdapter>doNothing()); 216 } 217 218 genClosureFields(closure, v, typeMapper); 219 } 220 221 @Override 222 protected void generateKotlinAnnotation() { 223 writeKotlinSyntheticClassAnnotation(v, state); 224 225 DescriptorSerializer serializer = 226 DescriptorSerializer.createForLambda( 227 new JvmSerializerExtension(v.getSerializationBindings(), typeMapper, state.getUseTypeTableInSerializer()) 228 ); 229 230 ProtoBuf.Function functionProto = serializer.functionProto(funDescriptor).build(); 231 232 AnnotationVisitor av = v.getVisitor().visitAnnotation(asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_FUNCTION), true); 233 writeAnnotationData(av, serializer, functionProto); 234 writeModuleName(av, state); 235 av.visitEnd(); 236 } 237 238 @Override 239 protected void done() { 240 writeOuterClassAndEnclosingMethod(); 241 super.done(); 242 } 243 244 @NotNull 245 public StackValue putInstanceOnStack(@NotNull final ExpressionCodegen codegen) { 246 return StackValue.operation( 247 functionReferenceTarget != null ? K_FUNCTION : asmType, 248 new Function1<InstructionAdapter, Unit>() { 249 @Override 250 public Unit invoke(InstructionAdapter v) { 251 if (isConst(closure)) { 252 v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor()); 253 } 254 else { 255 v.anew(asmType); 256 v.dup(); 257 258 codegen.pushClosureOnStack(classDescriptor, true, codegen.defaultCallGenerator); 259 v.invokespecial(asmType.getInternalName(), "<init>", constructor.getDescriptor(), false); 260 } 261 262 if (functionReferenceTarget != null) { 263 if (!"true".equalsIgnoreCase(System.getProperty("kotlin.jvm.optimize.callable.references"))) { 264 v.invokestatic(REFLECTION, "function", Type.getMethodDescriptor(K_FUNCTION, FUNCTION_REFERENCE), false); 265 } 266 } 267 268 return Unit.INSTANCE$; 269 } 270 } 271 ); 272 } 273 274 private void generateBridge(@NotNull Method bridge, @NotNull Method delegate) { 275 if (bridge.equals(delegate)) return; 276 277 MethodVisitor mv = 278 v.newMethod(JvmDeclarationOriginKt.OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC, 279 bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY); 280 281 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 282 283 mv.visitCode(); 284 285 InstructionAdapter iv = new InstructionAdapter(mv); 286 MemberCodegen.markLineNumberForDescriptor(DescriptorUtils.getParentOfType(funDescriptor, ClassDescriptor.class), iv); 287 288 iv.load(0, asmType); 289 290 Type[] myParameterTypes = bridge.getArgumentTypes(); 291 292 List<ParameterDescriptor> calleeParameters = CollectionsKt.<ParameterDescriptor>plus( 293 org.jetbrains.kotlin.utils.CollectionsKt.<ParameterDescriptor>singletonOrEmptyList(funDescriptor.getExtensionReceiverParameter()), 294 funDescriptor.getValueParameters() 295 ); 296 297 int slot = 1; 298 for (int i = 0; i < calleeParameters.size(); i++) { 299 Type type = myParameterTypes[i]; 300 StackValue.local(slot, type).put(typeMapper.mapType(calleeParameters.get(i)), iv); 301 slot += type.getSize(); 302 } 303 304 iv.invokevirtual(asmType.getInternalName(), delegate.getName(), delegate.getDescriptor(), false); 305 StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv); 306 307 iv.areturn(bridge.getReturnType()); 308 309 FunctionCodegen.endVisit(mv, "bridge", element); 310 } 311 312 // TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction? 313 private void generateFunctionReferenceMethods(@NotNull FunctionDescriptor descriptor) { 314 int flags = ACC_PUBLIC | ACC_FINAL; 315 boolean generateBody = state.getClassBuilderMode() == ClassBuilderMode.FULL; 316 317 { 318 MethodVisitor mv = 319 v.newMethod(NO_ORIGIN, flags, "getOwner", Type.getMethodDescriptor(K_DECLARATION_CONTAINER_TYPE), null, null); 320 if (generateBody) { 321 mv.visitCode(); 322 InstructionAdapter iv = new InstructionAdapter(mv); 323 generateCallableReferenceDeclarationContainer(iv, descriptor, state); 324 iv.areturn(K_DECLARATION_CONTAINER_TYPE); 325 FunctionCodegen.endVisit(iv, "function reference getOwner", element); 326 } 327 } 328 329 { 330 MethodVisitor mv = 331 v.newMethod(NO_ORIGIN, flags, "getName", Type.getMethodDescriptor(JAVA_STRING_TYPE), null, null); 332 if (generateBody) { 333 mv.visitCode(); 334 InstructionAdapter iv = new InstructionAdapter(mv); 335 iv.aconst(descriptor.getName().asString()); 336 iv.areturn(JAVA_STRING_TYPE); 337 FunctionCodegen.endVisit(iv, "function reference getName", element); 338 } 339 } 340 341 { 342 MethodVisitor mv = v.newMethod(NO_ORIGIN, flags, "getSignature", Type.getMethodDescriptor(JAVA_STRING_TYPE), null, null); 343 if (generateBody) { 344 mv.visitCode(); 345 InstructionAdapter iv = new InstructionAdapter(mv); 346 Method method = typeMapper.mapSignature(descriptor.getOriginal()).getAsmMethod(); 347 iv.aconst(method.getName() + method.getDescriptor()); 348 iv.areturn(JAVA_STRING_TYPE); 349 FunctionCodegen.endVisit(iv, "function reference getSignature", element); 350 } 351 } 352 } 353 354 public static void generateCallableReferenceDeclarationContainer( 355 @NotNull InstructionAdapter iv, 356 @NotNull CallableDescriptor descriptor, 357 @NotNull GenerationState state 358 ) { 359 DeclarationDescriptor container = descriptor.getContainingDeclaration(); 360 if (container instanceof ClassDescriptor) { 361 // TODO: getDefaultType() here is wrong and won't work for arrays 362 StackValue value = generateClassLiteralReference(state.getTypeMapper(), ((ClassDescriptor) container).getDefaultType()); 363 value.put(K_CLASS_TYPE, iv); 364 } 365 else if (container instanceof PackageFragmentDescriptor) { 366 iv.aconst(state.getTypeMapper().mapOwner(descriptor)); 367 iv.aconst(state.getModuleName()); 368 iv.invokestatic(REFLECTION, "getOrCreateKotlinPackage", 369 Type.getMethodDescriptor(K_DECLARATION_CONTAINER_TYPE, getType(Class.class), getType(String.class)), false); 370 } 371 else { 372 iv.aconst(null); 373 } 374 } 375 376 @NotNull 377 private Method generateConstructor() { 378 List<FieldInfo> args = calculateConstructorParameters(typeMapper, closure, asmType); 379 380 Type[] argTypes = fieldListToTypeArray(args); 381 382 Method constructor = new Method("<init>", Type.VOID_TYPE, argTypes); 383 MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(element, funDescriptor), visibilityFlag, "<init>", constructor.getDescriptor(), null, 384 ArrayUtil.EMPTY_STRING_ARRAY); 385 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 386 mv.visitCode(); 387 InstructionAdapter iv = new InstructionAdapter(mv); 388 389 int k = 1; 390 for (FieldInfo fieldInfo : args) { 391 k = genAssignInstanceFieldFromParam(fieldInfo, k, iv); 392 } 393 394 iv.load(0, superClassAsmType); 395 396 if (superClassAsmType.equals(LAMBDA) || superClassAsmType.equals(FUNCTION_REFERENCE)) { 397 int arity = funDescriptor.getValueParameters().size(); 398 if (funDescriptor.getExtensionReceiverParameter() != null) arity++; 399 if (funDescriptor.getDispatchReceiverParameter() != null) arity++; 400 iv.iconst(arity); 401 iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "(I)V", false); 402 } 403 else { 404 iv.invokespecial(superClassAsmType.getInternalName(), "<init>", "()V", false); 405 } 406 407 iv.visitInsn(RETURN); 408 409 FunctionCodegen.endVisit(iv, "constructor", element); 410 } 411 return constructor; 412 } 413 414 @NotNull 415 public static List<FieldInfo> calculateConstructorParameters( 416 @NotNull JetTypeMapper typeMapper, 417 @NotNull CalculatedClosure closure, 418 @NotNull Type ownerType 419 ) { 420 BindingContext bindingContext = typeMapper.getBindingContext(); 421 List<FieldInfo> args = Lists.newArrayList(); 422 ClassDescriptor captureThis = closure.getCaptureThis(); 423 if (captureThis != null) { 424 Type type = typeMapper.mapType(captureThis); 425 args.add(FieldInfo.createForHiddenField(ownerType, type, CAPTURED_THIS_FIELD)); 426 } 427 KotlinType captureReceiverType = closure.getCaptureReceiverType(); 428 if (captureReceiverType != null) { 429 args.add(FieldInfo.createForHiddenField(ownerType, typeMapper.mapType(captureReceiverType), CAPTURED_RECEIVER_FIELD)); 430 } 431 432 for (DeclarationDescriptor descriptor : closure.getCaptureVariables().keySet()) { 433 if (descriptor instanceof VariableDescriptor && !(descriptor instanceof PropertyDescriptor)) { 434 Type sharedVarType = typeMapper.getSharedVarType(descriptor); 435 436 Type type = sharedVarType != null 437 ? sharedVarType 438 : typeMapper.mapType((VariableDescriptor) descriptor); 439 args.add(FieldInfo.createForHiddenField(ownerType, type, "$" + descriptor.getName().asString())); 440 } 441 else if (ExpressionTypingUtils.isLocalFunction(descriptor)) { 442 Type classType = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor); 443 args.add(FieldInfo.createForHiddenField(ownerType, classType, "$" + descriptor.getName().asString())); 444 } 445 else if (descriptor instanceof FunctionDescriptor) { 446 assert captureReceiverType != null; 447 } 448 } 449 return args; 450 } 451 452 private static Type[] fieldListToTypeArray(List<FieldInfo> args) { 453 Type[] argTypes = new Type[args.size()]; 454 for (int i = 0; i != argTypes.length; ++i) { 455 argTypes[i] = args.get(i).getFieldType(); 456 } 457 return argTypes; 458 } 459 460 @NotNull 461 public static FunctionDescriptor getErasedInvokeFunction(@NotNull FunctionDescriptor elementDescriptor) { 462 int arity = elementDescriptor.getValueParameters().size(); 463 ClassDescriptor elementClass = elementDescriptor.getExtensionReceiverParameter() == null 464 ? DescriptorUtilsKt.getBuiltIns(elementDescriptor).getFunction(arity) 465 : DescriptorUtilsKt.getBuiltIns(elementDescriptor).getExtensionFunction(arity); 466 MemberScope scope = elementClass.getDefaultType().getMemberScope(); 467 return scope.getContributedFunctions(OperatorNameConventions.INVOKE, NoLookupLocation.FROM_BACKEND).iterator().next(); 468 } 469 }