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