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