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