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