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