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