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