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