001 /* 002 * Copyright 2010-2016 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.intellij.openapi.progress.ProcessCanceledException; 020 import com.intellij.psi.PsiElement; 021 import com.intellij.util.ArrayUtil; 022 import com.intellij.util.Function; 023 import com.intellij.util.containers.ContainerUtil; 024 import kotlin.jvm.functions.Function1; 025 import kotlin.text.StringsKt; 026 import org.jetbrains.annotations.NotNull; 027 import org.jetbrains.annotations.Nullable; 028 import org.jetbrains.kotlin.backend.common.bridges.Bridge; 029 import org.jetbrains.kotlin.backend.common.bridges.ImplKt; 030 import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithOnlyTargetedAnnotations; 031 import org.jetbrains.kotlin.codegen.context.*; 032 import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor; 033 import org.jetbrains.kotlin.codegen.state.GenerationState; 034 import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper; 035 import org.jetbrains.kotlin.descriptors.*; 036 import org.jetbrains.kotlin.descriptors.annotations.Annotated; 037 import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; 038 import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget; 039 import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo; 040 import org.jetbrains.kotlin.load.java.BuiltinMethodsWithSpecialGenericSignature; 041 import org.jetbrains.kotlin.load.java.JvmAbi; 042 import org.jetbrains.kotlin.load.java.SpecialBuiltinMembers; 043 import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeKt; 044 import org.jetbrains.kotlin.name.FqName; 045 import org.jetbrains.kotlin.psi.KtElement; 046 import org.jetbrains.kotlin.psi.KtFunction; 047 import org.jetbrains.kotlin.psi.KtNamedFunction; 048 import org.jetbrains.kotlin.resolve.BindingContext; 049 import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; 050 import org.jetbrains.kotlin.resolve.DescriptorUtils; 051 import org.jetbrains.kotlin.resolve.annotations.AnnotationUtilKt; 052 import org.jetbrains.kotlin.resolve.constants.ArrayValue; 053 import org.jetbrains.kotlin.resolve.constants.ConstantValue; 054 import org.jetbrains.kotlin.resolve.constants.KClassValue; 055 import org.jetbrains.kotlin.resolve.inline.InlineUtil; 056 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; 057 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind; 058 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt; 059 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature; 060 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; 061 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; 062 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; 063 import org.jetbrains.kotlin.types.KotlinType; 064 import org.jetbrains.kotlin.types.TypeUtils; 065 import org.jetbrains.org.objectweb.asm.AnnotationVisitor; 066 import org.jetbrains.org.objectweb.asm.Label; 067 import org.jetbrains.org.objectweb.asm.MethodVisitor; 068 import org.jetbrains.org.objectweb.asm.Type; 069 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 070 import org.jetbrains.org.objectweb.asm.commons.Method; 071 import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor; 072 073 import java.io.PrintWriter; 074 import java.io.StringWriter; 075 import java.util.Collection; 076 import java.util.Iterator; 077 import java.util.List; 078 import java.util.Set; 079 080 import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableAny; 081 import static org.jetbrains.kotlin.codegen.AsmUtil.*; 082 import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.METHOD_FOR_FUNCTION; 083 import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION; 084 import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*; 085 import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor; 086 import static org.jetbrains.kotlin.resolve.DescriptorUtils.getSuperClassDescriptor; 087 import static org.jetbrains.kotlin.resolve.DescriptorUtils.isInterface; 088 import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; 089 import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.*; 090 import static org.jetbrains.org.objectweb.asm.Opcodes.*; 091 092 public class FunctionCodegen { 093 public final GenerationState state; 094 private final KotlinTypeMapper typeMapper; 095 private final BindingContext bindingContext; 096 private final CodegenContext owner; 097 private final ClassBuilder v; 098 private final MemberCodegen<?> memberCodegen; 099 100 public FunctionCodegen( 101 @NotNull CodegenContext owner, 102 @NotNull ClassBuilder v, 103 @NotNull GenerationState state, 104 @NotNull MemberCodegen<?> memberCodegen 105 ) { 106 this.owner = owner; 107 this.v = v; 108 this.state = state; 109 this.typeMapper = state.getTypeMapper(); 110 this.bindingContext = state.getBindingContext(); 111 this.memberCodegen = memberCodegen; 112 } 113 114 public void gen(@NotNull KtNamedFunction function) { 115 SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, function); 116 if (functionDescriptor == null) { 117 throw ExceptionLogger.logDescriptorNotFound("No descriptor for function " + function.getName(), function); 118 } 119 120 if (owner.getContextKind() != OwnerKind.DEFAULT_IMPLS || function.hasBody()) { 121 generateMethod(JvmDeclarationOriginKt.OtherOrigin(function, functionDescriptor), functionDescriptor, 122 new FunctionGenerationStrategy.FunctionDefault(state, functionDescriptor, function)); 123 } 124 125 generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), functionDescriptor, owner.getContextKind(), 126 DefaultParameterValueLoader.DEFAULT, function); 127 128 generateOverloadsWithDefaultValues(function, functionDescriptor, functionDescriptor); 129 } 130 131 public void generateOverloadsWithDefaultValues( 132 @Nullable KtNamedFunction function, 133 @NotNull FunctionDescriptor functionDescriptor, 134 @NotNull FunctionDescriptor delegateFunctionDescriptor 135 ) { 136 new DefaultParameterValueSubstitutor(state).generateOverloadsIfNeeded( 137 function, functionDescriptor, delegateFunctionDescriptor, owner.getContextKind(), v 138 ); 139 } 140 141 public void generateMethod( 142 @NotNull JvmDeclarationOrigin origin, 143 @NotNull FunctionDescriptor descriptor, 144 @NotNull FunctionGenerationStrategy strategy 145 ) { 146 generateMethod(origin, descriptor, owner.intoFunction(descriptor), strategy); 147 } 148 149 public void generateMethod( 150 @NotNull JvmDeclarationOrigin origin, 151 @NotNull FunctionDescriptor functionDescriptor, 152 @NotNull MethodContext methodContext, 153 @NotNull FunctionGenerationStrategy strategy 154 ) { 155 OwnerKind contextKind = methodContext.getContextKind(); 156 if (isInterface(functionDescriptor.getContainingDeclaration()) && 157 functionDescriptor.getVisibility() == Visibilities.PRIVATE && 158 contextKind != OwnerKind.DEFAULT_IMPLS) { 159 return; 160 } 161 162 JvmMethodGenericSignature jvmSignature = typeMapper.mapSignatureWithGeneric(functionDescriptor, contextKind); 163 Method asmMethod = jvmSignature.getAsmMethod(); 164 165 int flags = getMethodAsmFlags(functionDescriptor, contextKind); 166 167 if (origin.getOriginKind() == JvmDeclarationOriginKind.SAM_DELEGATION) { 168 flags |= ACC_SYNTHETIC; 169 } 170 171 boolean isNative = NativeKt.hasNativeAnnotation(functionDescriptor); 172 173 if (isNative && owner instanceof MultifileClassFacadeContext) { 174 // Native methods are only defined in facades and do not need package part implementations 175 return; 176 } 177 MethodVisitor mv = v.newMethod(origin, 178 flags, 179 asmMethod.getName(), 180 asmMethod.getDescriptor(), 181 jvmSignature.getGenericsSignature(), 182 getThrownExceptions(functionDescriptor, typeMapper)); 183 184 if (CodegenContextUtil.isImplClassOwner(owner)) { 185 v.getSerializationBindings().put(METHOD_FOR_FUNCTION, functionDescriptor, asmMethod); 186 } 187 188 generateMethodAnnotations(functionDescriptor, asmMethod, mv); 189 190 generateParameterAnnotations(functionDescriptor, mv, typeMapper.mapSignatureSkipGeneric(functionDescriptor)); 191 192 generateBridges(functionDescriptor); 193 194 boolean staticInCompanionObject = AnnotationUtilKt.isPlatformStaticInCompanionObject(functionDescriptor); 195 if (staticInCompanionObject) { 196 ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen(); 197 parentBodyCodegen.addAdditionalTask(new JvmStaticGenerator(functionDescriptor, origin, state, parentBodyCodegen)); 198 } 199 200 if (state.getClassBuilderMode() != ClassBuilderMode.FULL || isAbstractMethod(functionDescriptor, contextKind)) { 201 generateLocalVariableTable( 202 mv, 203 jvmSignature, 204 functionDescriptor, 205 getThisTypeForFunction(functionDescriptor, methodContext, typeMapper), 206 new Label(), 207 new Label(), 208 contextKind 209 ); 210 211 mv.visitEnd(); 212 return; 213 } 214 215 if (!isNative) { 216 generateMethodBody(mv, functionDescriptor, methodContext, jvmSignature, strategy, memberCodegen); 217 } 218 else if (staticInCompanionObject) { 219 // native @JvmStatic foo() in companion object should delegate to the static native function moved to the outer class 220 mv.visitCode(); 221 FunctionDescriptor staticFunctionDescriptor = JvmStaticGenerator.createStaticFunctionDescriptor(functionDescriptor); 222 Method accessorMethod = 223 typeMapper.mapAsmMethod(memberCodegen.getContext().accessibleDescriptor(staticFunctionDescriptor, null)); 224 Type owningType = typeMapper.mapClass((ClassifierDescriptor) staticFunctionDescriptor.getContainingDeclaration()); 225 generateDelegateToMethodBody(false, mv, accessorMethod, owningType.getInternalName()); 226 } 227 228 endVisit(mv, null, origin.getElement()); 229 } 230 231 private void generateMethodAnnotations( 232 @NotNull FunctionDescriptor functionDescriptor, 233 Method asmMethod, 234 MethodVisitor mv 235 ) { 236 AnnotationCodegen annotationCodegen = AnnotationCodegen.forMethod(mv, typeMapper); 237 238 if (functionDescriptor instanceof PropertyAccessorDescriptor) { 239 AnnotationUseSiteTarget target = functionDescriptor instanceof PropertySetterDescriptor ? PROPERTY_SETTER : PROPERTY_GETTER; 240 annotationCodegen.genAnnotations(functionDescriptor, asmMethod.getReturnType(), target); 241 } 242 else { 243 annotationCodegen.genAnnotations(functionDescriptor, asmMethod.getReturnType()); 244 } 245 } 246 247 private void generateParameterAnnotations( 248 @NotNull FunctionDescriptor functionDescriptor, 249 @NotNull MethodVisitor mv, 250 @NotNull JvmMethodSignature jvmSignature 251 ) { 252 Iterator<ValueParameterDescriptor> iterator = functionDescriptor.getValueParameters().iterator(); 253 List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getValueParameters(); 254 255 for (int i = 0; i < kotlinParameterTypes.size(); i++) { 256 JvmMethodParameterSignature parameterSignature = kotlinParameterTypes.get(i); 257 JvmMethodParameterKind kind = parameterSignature.getKind(); 258 if (kind.isSkippedInGenericSignature()) { 259 markEnumOrInnerConstructorParameterAsSynthetic(mv, i); 260 continue; 261 } 262 263 if (kind == JvmMethodParameterKind.VALUE) { 264 ValueParameterDescriptor parameter = iterator.next(); 265 AnnotationCodegen annotationCodegen = AnnotationCodegen.forParameter(i, mv, typeMapper); 266 267 if (functionDescriptor instanceof PropertySetterDescriptor) { 268 PropertyDescriptor propertyDescriptor = ((PropertySetterDescriptor) functionDescriptor).getCorrespondingProperty(); 269 Annotated targetedAnnotations = new AnnotatedWithOnlyTargetedAnnotations(propertyDescriptor); 270 annotationCodegen.genAnnotations(targetedAnnotations, parameterSignature.getAsmType(), SETTER_PARAMETER); 271 } 272 273 if (functionDescriptor instanceof ConstructorDescriptor) { 274 annotationCodegen.genAnnotations(parameter, parameterSignature.getAsmType(), CONSTRUCTOR_PARAMETER); 275 } 276 else { 277 annotationCodegen.genAnnotations(parameter, parameterSignature.getAsmType()); 278 } 279 } 280 else if (kind == JvmMethodParameterKind.RECEIVER) { 281 ReceiverParameterDescriptor receiver = JvmCodegenUtil.getDirectMember(functionDescriptor).getExtensionReceiverParameter(); 282 283 if (receiver != null) { 284 AnnotationCodegen annotationCodegen = AnnotationCodegen.forParameter(i, mv, typeMapper); 285 Annotated targetedAnnotations = new AnnotatedWithOnlyTargetedAnnotations(receiver.getType()); 286 annotationCodegen.genAnnotations(targetedAnnotations, parameterSignature.getAsmType(), RECEIVER); 287 288 annotationCodegen.genAnnotations(receiver, parameterSignature.getAsmType()); 289 } 290 } 291 } 292 } 293 294 private void markEnumOrInnerConstructorParameterAsSynthetic(MethodVisitor mv, int i) { 295 // IDEA's ClsPsi builder fails to annotate synthetic parameters 296 if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return; 297 298 // This is needed to avoid RuntimeInvisibleParameterAnnotations error in javac: 299 // see MethodWriter.visitParameterAnnotation() 300 301 AnnotationVisitor av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", true); 302 if (av != null) { 303 av.visitEnd(); 304 } 305 } 306 307 @Nullable 308 private static Type getThisTypeForFunction( 309 @NotNull FunctionDescriptor functionDescriptor, 310 @NotNull MethodContext context, 311 @NotNull KotlinTypeMapper typeMapper 312 ) { 313 ReceiverParameterDescriptor dispatchReceiver = functionDescriptor.getDispatchReceiverParameter(); 314 if (functionDescriptor instanceof ConstructorDescriptor) { 315 return typeMapper.mapType(functionDescriptor); 316 } 317 else if (dispatchReceiver != null) { 318 return typeMapper.mapType(dispatchReceiver.getType()); 319 } 320 else if (isFunctionLiteral(functionDescriptor) || 321 isLocalFunction(functionDescriptor) || 322 isFunctionExpression(functionDescriptor)) { 323 return typeMapper.mapType(context.getThisDescriptor()); 324 } 325 else { 326 return null; 327 } 328 } 329 330 public static void generateMethodBody( 331 @NotNull MethodVisitor mv, 332 @NotNull FunctionDescriptor functionDescriptor, 333 @NotNull MethodContext context, 334 @NotNull JvmMethodSignature signature, 335 @NotNull FunctionGenerationStrategy strategy, 336 @NotNull MemberCodegen<?> parentCodegen 337 ) { 338 mv.visitCode(); 339 340 Label methodBegin = new Label(); 341 mv.visitLabel(methodBegin); 342 343 KotlinTypeMapper typeMapper = parentCodegen.typeMapper; 344 if (BuiltinSpecialBridgesUtil.shouldHaveTypeSafeBarrier(functionDescriptor, getSignatureMapper(typeMapper))) { 345 generateTypeCheckBarrierIfNeeded( 346 new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), /* delegateParameterType = */null); 347 } 348 349 Label methodEnd; 350 351 int functionFakeIndex = -1; 352 int lambdaFakeIndex = -1; 353 354 if (context.getParentContext() instanceof MultifileClassFacadeContext) { 355 generateFacadeDelegateMethodBody(mv, signature.getAsmMethod(), (MultifileClassFacadeContext) context.getParentContext()); 356 methodEnd = new Label(); 357 } 358 else { 359 FrameMap frameMap = createFrameMap(parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(), 360 functionDescriptor)); 361 if (context.isInlineMethodContext()) { 362 functionFakeIndex = frameMap.enterTemp(Type.INT_TYPE); 363 } 364 365 if (context instanceof InlineLambdaContext) { 366 lambdaFakeIndex = frameMap.enterTemp(Type.INT_TYPE); 367 } 368 369 Label methodEntry = new Label(); 370 mv.visitLabel(methodEntry); 371 context.setMethodStartLabel(methodEntry); 372 373 if (!KotlinTypeMapper.isAccessor(functionDescriptor)) { 374 genNotNullAssertionsForParameters(new InstructionAdapter(mv), parentCodegen.state, functionDescriptor, frameMap); 375 } 376 377 parentCodegen.beforeMethodBody(mv); 378 379 methodEnd = new Label(); 380 context.setMethodEndLabel(methodEnd); 381 strategy.generateBody(mv, frameMap, signature, context, parentCodegen); 382 } 383 384 mv.visitLabel(methodEnd); 385 386 Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper); 387 generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind()); 388 389 if (context.isInlineMethodContext() && functionFakeIndex != -1) { 390 mv.visitLocalVariable( 391 JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION + functionDescriptor.getName().asString(), 392 Type.INT_TYPE.getDescriptor(), null, 393 methodBegin, methodEnd, 394 functionFakeIndex); 395 } 396 397 if (context instanceof InlineLambdaContext && thisType != null && lambdaFakeIndex != -1) { 398 String name = thisType.getClassName(); 399 int indexOfLambdaOrdinal = name.lastIndexOf("$"); 400 if (indexOfLambdaOrdinal > 0) { 401 int lambdaOrdinal = Integer.parseInt(name.substring(indexOfLambdaOrdinal + 1)); 402 403 KtElement functionArgument = parentCodegen.element; 404 String functionName = "unknown"; 405 if (functionArgument instanceof KtFunction) { 406 ValueParameterDescriptor inlineArgumentDescriptor = 407 InlineUtil.getInlineArgumentDescriptor((KtFunction) functionArgument, parentCodegen.bindingContext); 408 if (inlineArgumentDescriptor != null) { 409 functionName = inlineArgumentDescriptor.getContainingDeclaration().getName().asString(); 410 } 411 } 412 mv.visitLocalVariable( 413 JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT + lambdaOrdinal + "$" + functionName, 414 Type.INT_TYPE.getDescriptor(), null, 415 methodBegin, methodEnd, 416 lambdaFakeIndex); 417 } 418 } 419 } 420 421 private static void generateLocalVariableTable( 422 @NotNull MethodVisitor mv, 423 @NotNull JvmMethodSignature jvmMethodSignature, 424 @NotNull FunctionDescriptor functionDescriptor, 425 @Nullable Type thisType, 426 @NotNull Label methodBegin, 427 @NotNull Label methodEnd, 428 @NotNull OwnerKind ownerKind 429 ) { 430 generateLocalVariablesForParameters(mv, jvmMethodSignature, thisType, methodBegin, methodEnd, 431 functionDescriptor.getValueParameters(), 432 AsmUtil.isStaticMethod(ownerKind, functionDescriptor)); 433 } 434 435 public static void generateLocalVariablesForParameters( 436 @NotNull MethodVisitor mv, 437 @NotNull JvmMethodSignature jvmMethodSignature, 438 @Nullable Type thisType, 439 @NotNull Label methodBegin, 440 @NotNull Label methodEnd, 441 Collection<ValueParameterDescriptor> valueParameters, 442 boolean isStatic 443 ) { 444 Iterator<ValueParameterDescriptor> valueParameterIterator = valueParameters.iterator(); 445 List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters(); 446 int shift = 0; 447 448 if (!isStatic) { 449 //add this 450 if (thisType != null) { 451 mv.visitLocalVariable("this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift); 452 } 453 else { 454 //TODO: provide thisType for callable reference 455 } 456 shift++; 457 } 458 459 for (int i = 0; i < params.size(); i++) { 460 JvmMethodParameterSignature param = params.get(i); 461 JvmMethodParameterKind kind = param.getKind(); 462 String parameterName; 463 464 if (kind == JvmMethodParameterKind.VALUE) { 465 ValueParameterDescriptor parameter = valueParameterIterator.next(); 466 parameterName = parameter.getName().asString(); 467 } 468 else { 469 String lowercaseKind = kind.name().toLowerCase(); 470 parameterName = needIndexForVar(kind) 471 ? "$" + lowercaseKind + "$" + i 472 : "$" + lowercaseKind; 473 } 474 475 Type type = param.getAsmType(); 476 mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift); 477 shift += type.getSize(); 478 } 479 } 480 481 private static void generateFacadeDelegateMethodBody( 482 @NotNull MethodVisitor mv, 483 @NotNull Method asmMethod, 484 @NotNull MultifileClassFacadeContext context 485 ) { 486 generateDelegateToMethodBody(true, mv, asmMethod, context.getFilePartType().getInternalName()); 487 } 488 489 private static void generateDelegateToMethodBody( 490 boolean isStatic, 491 @NotNull MethodVisitor mv, 492 @NotNull Method asmMethod, 493 @NotNull String classToDelegateTo 494 ) { 495 InstructionAdapter iv = new InstructionAdapter(mv); 496 Type[] argTypes = asmMethod.getArgumentTypes(); 497 498 // The first line of some package file is written to the line number attribute of a static delegate to allow to 'step into' it 499 // This is similar to what javac does with bridge methods 500 Label label = new Label(); 501 iv.visitLabel(label); 502 iv.visitLineNumber(1, label); 503 504 int k = isStatic ? 0 : 1; 505 for (Type argType : argTypes) { 506 iv.load(k, argType); 507 k += argType.getSize(); 508 } 509 iv.invokestatic(classToDelegateTo, asmMethod.getName(), asmMethod.getDescriptor(), false); 510 iv.areturn(asmMethod.getReturnType()); 511 } 512 513 private static boolean needIndexForVar(JvmMethodParameterKind kind) { 514 return kind == JvmMethodParameterKind.CAPTURED_LOCAL_VARIABLE || 515 kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL || 516 kind == JvmMethodParameterKind.SUPER_CALL_PARAM; 517 } 518 519 public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) { 520 try { 521 mv.visitMaxs(-1, -1); 522 mv.visitEnd(); 523 } 524 catch (ProcessCanceledException e) { 525 throw e; 526 } 527 catch (Throwable t) { 528 String bytecode = renderByteCodeIfAvailable(mv); 529 throw new CompilationException( 530 "wrong code generated\n" + 531 (description != null ? " for " + description : "") + 532 t.getClass().getName() + 533 " " + 534 t.getMessage() + 535 (bytecode != null ? "\nbytecode:\n" + bytecode : ""), 536 t, method); 537 } 538 } 539 540 private static String renderByteCodeIfAvailable(MethodVisitor mv) { 541 String bytecode = null; 542 543 if (mv instanceof OptimizationMethodVisitor) { 544 mv = ((OptimizationMethodVisitor) mv).getTraceMethodVisitorIfPossible(); 545 } 546 547 if (mv instanceof TraceMethodVisitor) { 548 TraceMethodVisitor traceMethodVisitor = (TraceMethodVisitor) mv; 549 StringWriter sw = new StringWriter(); 550 PrintWriter pw = new PrintWriter(sw); 551 traceMethodVisitor.p.print(pw); 552 pw.close(); 553 bytecode = sw.toString(); 554 } 555 return bytecode; 556 } 557 558 public void generateBridges(@NotNull FunctionDescriptor descriptor) { 559 if (descriptor instanceof ConstructorDescriptor) return; 560 if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return; 561 if (isInterface(descriptor.getContainingDeclaration())) return; 562 563 // equals(Any?), hashCode(), toString() never need bridges 564 if (isMethodOfAny(descriptor)) return; 565 566 boolean isSpecial = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor) != null; 567 568 Set<Bridge<Method>> bridgesToGenerate; 569 if (!isSpecial) { 570 bridgesToGenerate = ImplKt.generateBridgesForFunctionDescriptor( 571 descriptor, 572 getSignatureMapper(typeMapper) 573 ); 574 if (!bridgesToGenerate.isEmpty()) { 575 PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null; 576 boolean isSpecialBridge = 577 BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(descriptor) != null; 578 579 for (Bridge<Method> bridge : bridgesToGenerate) { 580 generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo(), isSpecialBridge, false); 581 } 582 } 583 } 584 else { 585 Set<BridgeForBuiltinSpecial<Method>> specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial( 586 descriptor, 587 getSignatureMapper(typeMapper) 588 ); 589 590 if (!specials.isEmpty()) { 591 PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null; 592 for (BridgeForBuiltinSpecial<Method> bridge : specials) { 593 generateBridge( 594 origin, descriptor, bridge.getFrom(), bridge.getTo(), 595 bridge.isSpecial(), bridge.isDelegateToSuper()); 596 } 597 } 598 599 if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION)) { 600 CallableDescriptor overridden = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor); 601 assert overridden != null; 602 603 Method method = typeMapper.mapAsmMethod(descriptor); 604 int flags = ACC_ABSTRACT | getVisibilityAccessFlag(descriptor); 605 v.newMethod(JvmDeclarationOriginKt.OtherOrigin(overridden), flags, method.getName(), method.getDescriptor(), null, null); 606 } 607 } 608 } 609 610 @NotNull 611 private static Function1<FunctionDescriptor, Method> getSignatureMapper(final @NotNull KotlinTypeMapper typeMapper) { 612 return new Function1<FunctionDescriptor, Method>() { 613 @Override 614 public Method invoke(FunctionDescriptor descriptor) { 615 return typeMapper.mapAsmMethod(descriptor); 616 } 617 }; 618 } 619 620 private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) { 621 String name = descriptor.getName().asString(); 622 List<ValueParameterDescriptor> parameters = descriptor.getValueParameters(); 623 if (parameters.isEmpty()) { 624 return name.equals("hashCode") || name.equals("toString"); 625 } 626 else if (parameters.size() == 1 && name.equals("equals")) { 627 return isNullableAny(parameters.get(0).getType()); 628 } 629 return false; 630 } 631 632 @NotNull 633 public static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final KotlinTypeMapper mapper) { 634 AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws")); 635 if (annotation == null) { 636 annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.jvm.Throws")); 637 } 638 639 if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY; 640 641 Collection<ConstantValue<?>> values = annotation.getAllValueArguments().values(); 642 if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY; 643 644 Object value = values.iterator().next(); 645 if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY; 646 ArrayValue arrayValue = (ArrayValue) value; 647 648 List<String> strings = ContainerUtil.mapNotNull( 649 arrayValue.getValue(), 650 new Function<ConstantValue<?>, String>() { 651 @Override 652 public String fun(ConstantValue<?> constant) { 653 if (constant instanceof KClassValue) { 654 KClassValue classValue = (KClassValue) constant; 655 ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue()); 656 return mapper.mapClass(classDescriptor).getInternalName(); 657 } 658 return null; 659 } 660 } 661 ); 662 return ArrayUtil.toStringArray(strings); 663 } 664 665 void generateDefaultIfNeeded( 666 @NotNull MethodContext owner, 667 @NotNull FunctionDescriptor functionDescriptor, 668 @NotNull OwnerKind kind, 669 @NotNull DefaultParameterValueLoader loadStrategy, 670 @Nullable KtNamedFunction function 671 ) { 672 DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration(); 673 674 if (kind != OwnerKind.DEFAULT_IMPLS && isInterface(contextClass)) { 675 return; 676 } 677 678 if (!isDefaultNeeded(functionDescriptor)) { 679 return; 680 } 681 682 int flags = getVisibilityAccessFlag(functionDescriptor) | 683 getDeprecatedAccessFlag(functionDescriptor) | 684 ACC_SYNTHETIC; 685 if (!(functionDescriptor instanceof ConstructorDescriptor)) { 686 flags |= ACC_STATIC | ACC_BRIDGE; 687 } 688 // $default methods are never private to be accessible from other class files (e.g. inner) without the need of synthetic accessors 689 flags &= ~ACC_PRIVATE; 690 691 Method defaultMethod = typeMapper.mapDefaultMethod(functionDescriptor, kind); 692 693 MethodVisitor mv = v.newMethod( 694 JvmDeclarationOriginKt.Synthetic(function, functionDescriptor), 695 flags, 696 defaultMethod.getName(), 697 defaultMethod.getDescriptor(), null, 698 getThrownExceptions(functionDescriptor, typeMapper) 699 ); 700 701 // Only method annotations are copied to the $default method. Parameter annotations are not copied until there are valid use cases; 702 // enum constructors have two additional synthetic parameters which somewhat complicate this task 703 AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor, defaultMethod.getReturnType()); 704 705 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 706 if (this.owner instanceof MultifileClassFacadeContext) { 707 mv.visitCode(); 708 generateFacadeDelegateMethodBody(mv, defaultMethod, (MultifileClassFacadeContext) this.owner); 709 endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor)); 710 } 711 else { 712 mv.visitCode(); 713 generateDefaultImplBody(owner, functionDescriptor, mv, loadStrategy, function, memberCodegen, defaultMethod); 714 endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor)); 715 } 716 } 717 } 718 719 public static void generateDefaultImplBody( 720 @NotNull MethodContext methodContext, 721 @NotNull FunctionDescriptor functionDescriptor, 722 @NotNull MethodVisitor mv, 723 @NotNull DefaultParameterValueLoader loadStrategy, 724 @Nullable KtNamedFunction function, 725 @NotNull MemberCodegen<?> parentCodegen, 726 @NotNull Method defaultMethod 727 ) { 728 GenerationState state = parentCodegen.state; 729 JvmMethodSignature signature = state.getTypeMapper().mapSignatureWithGeneric(functionDescriptor, methodContext.getContextKind()); 730 731 boolean isStatic = isStaticMethod(methodContext.getContextKind(), functionDescriptor); 732 FrameMap frameMap = createFrameMap(state, functionDescriptor, signature, isStatic); 733 734 ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen); 735 736 CallGenerator generator = codegen.getOrCreateCallGeneratorForDefaultImplBody(functionDescriptor, function); 737 738 InstructionAdapter iv = new InstructionAdapter(mv); 739 genDefaultSuperCallCheckIfNeeded(iv, defaultMethod); 740 741 loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator); 742 743 List<JvmMethodParameterSignature> mappedParameters = signature.getValueParameters(); 744 int capturedArgumentsCount = 0; 745 while (capturedArgumentsCount < mappedParameters.size() && 746 mappedParameters.get(capturedArgumentsCount).getKind() != JvmMethodParameterKind.VALUE) { 747 capturedArgumentsCount++; 748 } 749 750 int maskIndex = 0; 751 List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters(); 752 for (int index = 0; index < valueParameters.size(); index++) { 753 if (index % Integer.SIZE == 0) { 754 maskIndex = frameMap.enterTemp(Type.INT_TYPE); 755 } 756 ValueParameterDescriptor parameterDescriptor = valueParameters.get(index); 757 Type type = mappedParameters.get(capturedArgumentsCount + index).getAsmType(); 758 759 int parameterIndex = frameMap.getIndex(parameterDescriptor); 760 if (parameterDescriptor.declaresDefaultValue()) { 761 iv.load(maskIndex, Type.INT_TYPE); 762 iv.iconst(1 << (index % Integer.SIZE)); 763 iv.and(Type.INT_TYPE); 764 Label loadArg = new Label(); 765 iv.ifeq(loadArg); 766 767 StackValue.local(parameterIndex, type).store(loadStrategy.genValue(parameterDescriptor, codegen), iv); 768 769 iv.mark(loadArg); 770 } 771 772 generator.putValueIfNeeded(type, StackValue.local(parameterIndex, type)); 773 } 774 775 CallableMethod method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false); 776 777 generator.genCall(method, null, false, codegen); 778 779 iv.areturn(signature.getReturnType()); 780 } 781 782 private static void genDefaultSuperCallCheckIfNeeded(@NotNull InstructionAdapter iv, @NotNull Method defaultMethod) { 783 String defaultMethodName = defaultMethod.getName(); 784 if ("<init>".equals(defaultMethodName)) { 785 return; 786 } 787 Label end = new Label(); 788 int handleIndex = (Type.getArgumentsAndReturnSizes(defaultMethod.getDescriptor()) >> 2) - 2; /*-1 for this, and -1 for handle*/ 789 iv.load(handleIndex, OBJECT_TYPE); 790 iv.ifnull(end); 791 AsmUtil.genThrow(iv, 792 "java/lang/UnsupportedOperationException", 793 "Super calls with default arguments not supported in this target, function: " + 794 StringsKt.substringBeforeLast(defaultMethodName, JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, defaultMethodName)); 795 iv.visitLabel(end); 796 } 797 798 @NotNull 799 private static FrameMap createFrameMap( 800 @NotNull GenerationState state, 801 @NotNull FunctionDescriptor function, 802 @NotNull JvmMethodSignature signature, 803 boolean isStatic 804 ) { 805 FrameMap frameMap = new FrameMap(); 806 if (!isStatic) { 807 frameMap.enterTemp(OBJECT_TYPE); 808 } 809 810 for (JvmMethodParameterSignature parameter : signature.getValueParameters()) { 811 if (parameter.getKind() == JvmMethodParameterKind.RECEIVER) { 812 ReceiverParameterDescriptor receiverParameter = function.getExtensionReceiverParameter(); 813 if (receiverParameter != null) { 814 frameMap.enter(receiverParameter, state.getTypeMapper().mapType(receiverParameter)); 815 } 816 else { 817 frameMap.enterTemp(parameter.getAsmType()); 818 } 819 } 820 else if (parameter.getKind() != JvmMethodParameterKind.VALUE) { 821 frameMap.enterTemp(parameter.getAsmType()); 822 } 823 } 824 825 for (ValueParameterDescriptor parameter : function.getValueParameters()) { 826 frameMap.enter(parameter, state.getTypeMapper().mapType(parameter)); 827 } 828 829 return frameMap; 830 } 831 832 private static void loadExplicitArgumentsOnStack( 833 @NotNull Type ownerType, 834 boolean isStatic, 835 @NotNull JvmMethodSignature signature, 836 @NotNull CallGenerator callGenerator 837 ) { 838 int var = 0; 839 if (!isStatic) { 840 callGenerator.putValueIfNeeded(ownerType, StackValue.local(var, ownerType)); 841 var += ownerType.getSize(); 842 } 843 844 for (JvmMethodParameterSignature parameterSignature : signature.getValueParameters()) { 845 if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) { 846 Type type = parameterSignature.getAsmType(); 847 callGenerator.putValueIfNeeded(type, StackValue.local(var, type)); 848 var += type.getSize(); 849 } 850 } 851 } 852 853 private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) { 854 boolean needed = false; 855 if (functionDescriptor != null) { 856 for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) { 857 if (parameterDescriptor.declaresDefaultValue()) { 858 needed = true; 859 break; 860 } 861 } 862 } 863 return needed; 864 } 865 866 private void generateBridge( 867 @Nullable PsiElement origin, 868 @NotNull FunctionDescriptor descriptor, 869 @NotNull Method bridge, 870 @NotNull Method delegateTo, 871 boolean isSpecialBridge, 872 boolean isStubDeclarationWithDelegationToSuper 873 ) { 874 boolean isSpecialOrDelegationToSuper = isSpecialBridge || isStubDeclarationWithDelegationToSuper; 875 int flags = ACC_PUBLIC | ACC_BRIDGE | (!isSpecialOrDelegationToSuper ? ACC_SYNTHETIC : 0) | (isSpecialBridge ? ACC_FINAL : 0); // TODO. 876 877 MethodVisitor mv = 878 v.newMethod(JvmDeclarationOriginKt.Bridge(descriptor, origin), flags, bridge.getName(), bridge.getDescriptor(), null, null); 879 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 880 881 mv.visitCode(); 882 883 Type[] argTypes = bridge.getArgumentTypes(); 884 Type[] originalArgTypes = delegateTo.getArgumentTypes(); 885 886 InstructionAdapter iv = new InstructionAdapter(mv); 887 MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv); 888 889 if (delegateTo.getArgumentTypes().length == 1 && isSpecialBridge) { 890 generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes()[0]); 891 } 892 893 iv.load(0, OBJECT_TYPE); 894 for (int i = 0, reg = 1; i < argTypes.length; i++) { 895 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv); 896 //noinspection AssignmentToForLoopParameter 897 reg += argTypes[i].getSize(); 898 } 899 900 if (isStubDeclarationWithDelegationToSuper) { 901 ClassDescriptor parentClass = getSuperClassDescriptor((ClassDescriptor) descriptor.getContainingDeclaration()); 902 assert parentClass != null; 903 String parentInternalName = typeMapper.mapClass(parentClass).getInternalName(); 904 iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor()); 905 } 906 else { 907 iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor()); 908 } 909 910 StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv); 911 iv.areturn(bridge.getReturnType()); 912 913 endVisit(mv, "bridge method", origin); 914 } 915 916 private static void generateTypeCheckBarrierIfNeeded( 917 @NotNull InstructionAdapter iv, 918 @NotNull FunctionDescriptor descriptor, 919 @NotNull Type returnType, 920 @Nullable final Type delegateParameterType 921 ) { 922 BuiltinMethodsWithSpecialGenericSignature.DefaultValue defaultValue = 923 BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor); 924 if (defaultValue == null) return; 925 926 assert descriptor.getValueParameters().size() == 1 : "Should be descriptor with one value parameter, but found: " + descriptor; 927 928 boolean isCheckForAny = delegateParameterType == null || OBJECT_TYPE.equals(delegateParameterType); 929 930 final KotlinType kotlinType = descriptor.getValueParameters().get(0).getType(); 931 932 if (isCheckForAny && TypeUtils.isNullableType(kotlinType)) return; 933 934 iv.load(1, OBJECT_TYPE); 935 936 Label afterBarrier = new Label(); 937 938 if (isCheckForAny) { 939 assert !TypeUtils.isNullableType(kotlinType) : "Only bridges for not-nullable types are necessary"; 940 iv.ifnonnull(afterBarrier); 941 } 942 else { 943 CodegenUtilKt.generateIsCheck(iv, kotlinType, boxType(delegateParameterType)); 944 iv.ifne(afterBarrier); 945 } 946 947 StackValue.constant(defaultValue.getValue(), returnType).put(returnType, iv); 948 iv.areturn(returnType); 949 950 iv.visitLabel(afterBarrier); 951 } 952 953 public void genSamDelegate(@NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) { 954 FunctionDescriptor delegatedTo = overriddenDescriptor.getOriginal(); 955 JvmDeclarationOrigin declarationOrigin = 956 JvmDeclarationOriginKt.SamDelegation(functionDescriptor); 957 genDelegate( 958 functionDescriptor, delegatedTo, 959 declarationOrigin, 960 (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), 961 field); 962 } 963 964 public void genDelegate(@NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) { 965 genDelegate(functionDescriptor, overriddenDescriptor.getOriginal(), 966 (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field); 967 } 968 969 public void genDelegate( 970 @NotNull FunctionDescriptor delegateFunction, 971 FunctionDescriptor delegatedTo, 972 ClassDescriptor toClass, 973 StackValue field 974 ) { 975 JvmDeclarationOrigin declarationOrigin = 976 JvmDeclarationOriginKt.Delegation(DescriptorToSourceUtils.descriptorToDeclaration(delegatedTo), delegateFunction); 977 genDelegate(delegateFunction, delegatedTo, declarationOrigin, toClass, field); 978 } 979 980 private void genDelegate( 981 @NotNull final FunctionDescriptor delegateFunction, 982 final FunctionDescriptor delegatedTo, 983 @NotNull JvmDeclarationOrigin declarationOrigin, 984 final ClassDescriptor toClass, 985 final StackValue field 986 ) { 987 generateMethod( 988 declarationOrigin, delegateFunction, 989 new FunctionGenerationStrategy() { 990 @Override 991 public void generateBody( 992 @NotNull MethodVisitor mv, 993 @NotNull FrameMap frameMap, 994 @NotNull JvmMethodSignature signature, 995 @NotNull MethodContext context, 996 @NotNull MemberCodegen<?> parentCodegen 997 ) { 998 Method delegateToMethod = typeMapper.mapToCallableMethod(delegatedTo, /* superCall = */ false).getAsmMethod(); 999 Method delegateMethod = typeMapper.mapAsmMethod(delegateFunction); 1000 1001 Type[] argTypes = delegateMethod.getArgumentTypes(); 1002 Type[] originalArgTypes = delegateToMethod.getArgumentTypes(); 1003 1004 InstructionAdapter iv = new InstructionAdapter(mv); 1005 iv.load(0, OBJECT_TYPE); 1006 field.put(field.type, iv); 1007 for (int i = 0, reg = 1; i < argTypes.length; i++) { 1008 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv); 1009 //noinspection AssignmentToForLoopParameter 1010 reg += argTypes[i].getSize(); 1011 } 1012 1013 String internalName = typeMapper.mapType(toClass).getInternalName(); 1014 if (toClass.getKind() == ClassKind.INTERFACE) { 1015 iv.invokeinterface(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor()); 1016 } 1017 else { 1018 iv.invokevirtual(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor()); 1019 } 1020 1021 StackValue stackValue = AsmUtil.genNotNullAssertions( 1022 state, 1023 StackValue.onStack(delegateToMethod.getReturnType()), 1024 RuntimeAssertionInfo.create( 1025 delegateFunction.getReturnType(), 1026 delegatedTo.getReturnType(), 1027 new RuntimeAssertionInfo.DataFlowExtras.OnlyMessage(delegatedTo.getName() + "(...)") 1028 ) 1029 ); 1030 1031 stackValue.put(delegateMethod.getReturnType(), iv); 1032 1033 iv.areturn(delegateMethod.getReturnType()); 1034 } 1035 } 1036 ); 1037 } 1038 }