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 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 if (BuiltinSpecialBridgesUtil.shouldHaveTypeSafeBarrier(functionDescriptor, getSignatureMapper(typeMapper))) { 358 generateTypeCheckBarrierIfNeeded( 359 new InstructionAdapter(mv), functionDescriptor, signature.getReturnType(), /* delegateParameterType = */null); 360 } 361 362 Label methodEnd; 363 364 int functionFakeIndex = -1; 365 int lambdaFakeIndex = -1; 366 367 if (context.getParentContext() instanceof DelegatingFacadeContext) { 368 generateFacadeDelegateMethodBody(mv, signature.getAsmMethod(), (DelegatingFacadeContext) context.getParentContext()); 369 methodEnd = new Label(); 370 } 371 else { 372 FrameMap frameMap = createFrameMap(parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(), 373 functionDescriptor)); 374 if (context.isInlineMethodContext()) { 375 functionFakeIndex = frameMap.enterTemp(Type.INT_TYPE); 376 } 377 378 if (context instanceof InlineLambdaContext) { 379 lambdaFakeIndex = frameMap.enterTemp(Type.INT_TYPE); 380 } 381 382 Label methodEntry = new Label(); 383 mv.visitLabel(methodEntry); 384 context.setMethodStartLabel(methodEntry); 385 386 if (!JetTypeMapper.isAccessor(functionDescriptor)) { 387 genNotNullAssertionsForParameters(new InstructionAdapter(mv), parentCodegen.state, functionDescriptor, frameMap); 388 } 389 methodEnd = new Label(); 390 context.setMethodEndLabel(methodEnd); 391 strategy.generateBody(mv, frameMap, signature, context, parentCodegen); 392 } 393 394 mv.visitLabel(methodEnd); 395 396 Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper); 397 generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind()); 398 399 if (context.isInlineMethodContext() && functionFakeIndex != -1) { 400 mv.visitLocalVariable( 401 JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_FUNCTION + functionDescriptor.getName().asString(), 402 Type.INT_TYPE.getDescriptor(), null, 403 methodBegin, methodEnd, 404 functionFakeIndex); 405 } 406 407 if (context instanceof InlineLambdaContext && thisType != null && lambdaFakeIndex != -1) { 408 String name = thisType.getClassName(); 409 int indexOfLambdaOrdinal = name.lastIndexOf("$"); 410 if (indexOfLambdaOrdinal > 0) { 411 int lambdaOrdinal = Integer.parseInt(name.substring(indexOfLambdaOrdinal + 1)); 412 mv.visitLocalVariable( 413 JvmAbi.LOCAL_VARIABLE_NAME_PREFIX_INLINE_ARGUMENT + lambdaOrdinal, 414 Type.INT_TYPE.getDescriptor(), null, 415 methodBegin, methodEnd, 416 lambdaFakeIndex); 417 } 418 } 419 } 420 421 private static void generateLocalVariableTable( 422 @NotNull MethodVisitor mv, 423 @NotNull JvmMethodSignature jvmMethodSignature, 424 @NotNull FunctionDescriptor functionDescriptor, 425 @Nullable Type thisType, 426 @NotNull Label methodBegin, 427 @NotNull Label methodEnd, 428 @NotNull OwnerKind ownerKind 429 ) { 430 Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator(); 431 List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters(); 432 int shift = 0; 433 434 boolean isStatic = AsmUtil.isStaticMethod(ownerKind, functionDescriptor); 435 if (!isStatic) { 436 //add this 437 if (thisType != null) { 438 mv.visitLocalVariable("this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift); 439 } 440 else { 441 //TODO: provide thisType for callable reference 442 } 443 shift++; 444 } 445 446 for (int i = 0; i < params.size(); i++) { 447 JvmMethodParameterSignature param = params.get(i); 448 JvmMethodParameterKind kind = param.getKind(); 449 String parameterName; 450 451 if (kind == JvmMethodParameterKind.VALUE) { 452 ValueParameterDescriptor parameter = valueParameters.next(); 453 parameterName = parameter.getName().asString(); 454 } 455 else { 456 String lowercaseKind = kind.name().toLowerCase(); 457 parameterName = needIndexForVar(kind) 458 ? "$" + lowercaseKind + "$" + i 459 : "$" + lowercaseKind; 460 } 461 462 Type type = param.getAsmType(); 463 mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift); 464 shift += type.getSize(); 465 } 466 } 467 468 private static void generateFacadeDelegateMethodBody( 469 @NotNull MethodVisitor mv, 470 @NotNull Method asmMethod, 471 @NotNull DelegatingFacadeContext context 472 ) { 473 generateDelegateToMethodBody(true, mv, asmMethod, context.getDelegateToClassType().getInternalName()); 474 } 475 476 private static void generateDelegateToMethodBody( 477 boolean isStatic, 478 @NotNull MethodVisitor mv, 479 @NotNull Method asmMethod, 480 @NotNull String classToDelegateTo 481 ) { 482 InstructionAdapter iv = new InstructionAdapter(mv); 483 Type[] argTypes = asmMethod.getArgumentTypes(); 484 485 // The first line of some package file is written to the line number attribute of a static delegate to allow to 'step into' it 486 // This is similar to what javac does with bridge methods 487 Label label = new Label(); 488 iv.visitLabel(label); 489 iv.visitLineNumber(1, label); 490 491 int k = isStatic ? 0 : 1; 492 for (Type argType : argTypes) { 493 iv.load(k, argType); 494 k += argType.getSize(); 495 } 496 iv.invokestatic(classToDelegateTo, asmMethod.getName(), asmMethod.getDescriptor(), false); 497 iv.areturn(asmMethod.getReturnType()); 498 } 499 500 private static boolean needIndexForVar(JvmMethodParameterKind kind) { 501 return kind == JvmMethodParameterKind.CAPTURED_LOCAL_VARIABLE || 502 kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL || 503 kind == JvmMethodParameterKind.SUPER_CALL_PARAM; 504 } 505 506 public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) { 507 try { 508 mv.visitMaxs(-1, -1); 509 mv.visitEnd(); 510 } 511 catch (ProcessCanceledException e) { 512 throw e; 513 } 514 catch (Throwable t) { 515 String bytecode = renderByteCodeIfAvailable(mv); 516 throw new CompilationException( 517 "wrong code generated" + 518 (description != null ? " for " + description : "") + 519 t.getClass().getName() + 520 " " + 521 t.getMessage() + 522 (bytecode != null ? "\nbytecode:\n" + bytecode : ""), 523 t, method); 524 } 525 } 526 527 private static String renderByteCodeIfAvailable(MethodVisitor mv) { 528 String bytecode = null; 529 530 if (mv instanceof OptimizationMethodVisitor) { 531 mv = ((OptimizationMethodVisitor) mv).getTraceMethodVisitorIfPossible(); 532 } 533 534 if (mv instanceof TraceMethodVisitor) { 535 TraceMethodVisitor traceMethodVisitor = (TraceMethodVisitor) mv; 536 StringWriter sw = new StringWriter(); 537 PrintWriter pw = new PrintWriter(sw); 538 traceMethodVisitor.p.print(pw); 539 pw.close(); 540 bytecode = sw.toString(); 541 } 542 return bytecode; 543 } 544 545 public void generateBridges(@NotNull FunctionDescriptor descriptor) { 546 if (descriptor instanceof ConstructorDescriptor) return; 547 if (owner.getContextKind() == OwnerKind.DEFAULT_IMPLS) return; 548 if (isInterface(descriptor.getContainingDeclaration())) return; 549 550 // equals(Any?), hashCode(), toString() never need bridges 551 if (isMethodOfAny(descriptor)) return; 552 553 // If the function doesn't have a physical declaration among super-functions, it's a SAM adapter or alike and doesn't need bridges 554 if (CallResolverUtilKt.isOrOverridesSynthesized(descriptor)) return; 555 556 boolean isSpecial = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor) != null; 557 558 Set<Bridge<Method>> bridgesToGenerate; 559 if (!isSpecial) { 560 bridgesToGenerate = ImplKt.generateBridgesForFunctionDescriptor( 561 descriptor, 562 getSignatureMapper(typeMapper) 563 ); 564 if (!bridgesToGenerate.isEmpty()) { 565 PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null; 566 boolean isSpecialBridge = 567 BuiltinMethodsWithSpecialGenericSignature.getOverriddenBuiltinFunctionWithErasedValueParametersInJava(descriptor) != null; 568 569 for (Bridge<Method> bridge : bridgesToGenerate) { 570 generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo(), isSpecialBridge, false); 571 } 572 } 573 } 574 else { 575 Set<BridgeForBuiltinSpecial<Method>> specials = BuiltinSpecialBridgesUtil.generateBridgesForBuiltinSpecial( 576 descriptor, 577 getSignatureMapper(typeMapper) 578 ); 579 580 if (!specials.isEmpty()) { 581 PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null; 582 for (BridgeForBuiltinSpecial<Method> bridge : specials) { 583 generateBridge( 584 origin, descriptor, bridge.getFrom(), bridge.getTo(), 585 bridge.isSpecial(), bridge.isDelegateToSuper()); 586 } 587 } 588 589 if (!descriptor.getKind().isReal() && isAbstractMethod(descriptor, OwnerKind.IMPLEMENTATION)) { 590 CallableDescriptor overridden = SpecialBuiltinMembers.getOverriddenBuiltinReflectingJvmDescriptor(descriptor); 591 assert overridden != null; 592 593 Method method = typeMapper.mapSignature(descriptor).getAsmMethod(); 594 int flags = ACC_ABSTRACT | getVisibilityAccessFlag(descriptor); 595 v.newMethod(JvmDeclarationOriginKt.OtherOrigin(overridden), flags, method.getName(), method.getDescriptor(), null, null); 596 } 597 } 598 } 599 600 @NotNull 601 private static Function1<FunctionDescriptor, Method> getSignatureMapper(final @NotNull JetTypeMapper typeMapper) { 602 return new Function1<FunctionDescriptor, Method>() { 603 @Override 604 public Method invoke(FunctionDescriptor descriptor) { 605 return typeMapper.mapSignature(descriptor).getAsmMethod(); 606 } 607 }; 608 } 609 610 private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) { 611 String name = descriptor.getName().asString(); 612 List<ValueParameterDescriptor> parameters = descriptor.getValueParameters(); 613 if (parameters.isEmpty()) { 614 return name.equals("hashCode") || name.equals("toString"); 615 } 616 else if (parameters.size() == 1 && name.equals("equals")) { 617 return isNullableAny(parameters.get(0).getType()); 618 } 619 return false; 620 } 621 622 @NotNull 623 public static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final JetTypeMapper mapper) { 624 AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws")); 625 if (annotation == null) { 626 annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.jvm.Throws")); 627 } 628 629 if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY; 630 631 Collection<ConstantValue<?>> values = annotation.getAllValueArguments().values(); 632 if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY; 633 634 Object value = values.iterator().next(); 635 if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY; 636 ArrayValue arrayValue = (ArrayValue) value; 637 638 List<String> strings = ContainerUtil.mapNotNull( 639 arrayValue.getValue(), 640 new Function<ConstantValue<?>, String>() { 641 @Override 642 public String fun(ConstantValue<?> constant) { 643 if (constant instanceof KClassValue) { 644 KClassValue classValue = (KClassValue) constant; 645 ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue()); 646 return mapper.mapClass(classDescriptor).getInternalName(); 647 } 648 return null; 649 } 650 } 651 ); 652 return ArrayUtil.toStringArray(strings); 653 } 654 655 void generateDefaultIfNeeded( 656 @NotNull MethodContext owner, 657 @NotNull FunctionDescriptor functionDescriptor, 658 @NotNull OwnerKind kind, 659 @NotNull DefaultParameterValueLoader loadStrategy, 660 @Nullable KtNamedFunction function 661 ) { 662 DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration(); 663 664 if (kind != OwnerKind.DEFAULT_IMPLS && isInterface(contextClass)) { 665 return; 666 } 667 668 if (!isDefaultNeeded(functionDescriptor)) { 669 return; 670 } 671 672 int flags = getVisibilityAccessFlag(functionDescriptor) | 673 getDeprecatedAccessFlag(functionDescriptor) | 674 ACC_SYNTHETIC; 675 if (!(functionDescriptor instanceof ConstructorDescriptor)) { 676 flags |= ACC_STATIC | ACC_BRIDGE; 677 } 678 // $default methods are never private to be accessible from other class files (e.g. inner) without the need of synthetic accessors 679 flags &= ~ACC_PRIVATE; 680 681 Method defaultMethod = typeMapper.mapDefaultMethod(functionDescriptor, kind); 682 683 MethodVisitor mv = v.newMethod( 684 JvmDeclarationOriginKt.Synthetic(function, functionDescriptor), 685 flags, 686 defaultMethod.getName(), 687 defaultMethod.getDescriptor(), null, 688 getThrownExceptions(functionDescriptor, typeMapper) 689 ); 690 691 // Only method annotations are copied to the $default method. Parameter annotations are not copied until there are valid use cases; 692 // enum constructors have two additional synthetic parameters which somewhat complicate this task 693 AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor, defaultMethod.getReturnType()); 694 695 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 696 if (this.owner instanceof DelegatingFacadeContext) { 697 mv.visitCode(); 698 generateFacadeDelegateMethodBody(mv, defaultMethod, (DelegatingFacadeContext) this.owner); 699 endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor)); 700 } 701 else { 702 mv.visitCode(); 703 generateDefaultImplBody(owner, functionDescriptor, mv, loadStrategy, function, memberCodegen); 704 endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor)); 705 } 706 } 707 } 708 709 public static void generateDefaultImplBody( 710 @NotNull MethodContext methodContext, 711 @NotNull FunctionDescriptor functionDescriptor, 712 @NotNull MethodVisitor mv, 713 @NotNull DefaultParameterValueLoader loadStrategy, 714 @Nullable KtNamedFunction function, 715 @NotNull MemberCodegen<?> parentCodegen 716 ) { 717 GenerationState state = parentCodegen.state; 718 JvmMethodSignature signature = state.getTypeMapper().mapSignature(functionDescriptor, methodContext.getContextKind()); 719 720 boolean isStatic = isStaticMethod(methodContext.getContextKind(), functionDescriptor); 721 FrameMap frameMap = createFrameMap(state, functionDescriptor, signature, isStatic); 722 723 ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen); 724 725 CallGenerator generator = codegen.getOrCreateCallGenerator(functionDescriptor, function); 726 727 loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator); 728 729 List<JvmMethodParameterSignature> mappedParameters = signature.getValueParameters(); 730 int capturedArgumentsCount = 0; 731 while (capturedArgumentsCount < mappedParameters.size() && 732 mappedParameters.get(capturedArgumentsCount).getKind() != JvmMethodParameterKind.VALUE) { 733 capturedArgumentsCount++; 734 } 735 736 InstructionAdapter iv = new InstructionAdapter(mv); 737 738 int maskIndex = 0; 739 List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters(); 740 for (int index = 0; index < valueParameters.size(); index++) { 741 if (index % Integer.SIZE == 0) { 742 maskIndex = frameMap.enterTemp(Type.INT_TYPE); 743 } 744 ValueParameterDescriptor parameterDescriptor = valueParameters.get(index); 745 Type type = mappedParameters.get(capturedArgumentsCount + index).getAsmType(); 746 747 int parameterIndex = frameMap.getIndex(parameterDescriptor); 748 if (parameterDescriptor.declaresDefaultValue()) { 749 iv.load(maskIndex, Type.INT_TYPE); 750 iv.iconst(1 << (index % Integer.SIZE)); 751 iv.and(Type.INT_TYPE); 752 Label loadArg = new Label(); 753 iv.ifeq(loadArg); 754 755 StackValue.local(parameterIndex, type).store(loadStrategy.genValue(parameterDescriptor, codegen), iv); 756 757 iv.mark(loadArg); 758 } 759 760 generator.putValueIfNeeded(parameterDescriptor, type, StackValue.local(parameterIndex, type)); 761 } 762 763 CallableMethod method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false); 764 765 generator.genCallWithoutAssertions(method, codegen); 766 767 iv.areturn(signature.getReturnType()); 768 } 769 770 @NotNull 771 private static FrameMap createFrameMap( 772 @NotNull GenerationState state, 773 @NotNull FunctionDescriptor function, 774 @NotNull JvmMethodSignature signature, 775 boolean isStatic 776 ) { 777 FrameMap frameMap = new FrameMap(); 778 if (!isStatic) { 779 frameMap.enterTemp(OBJECT_TYPE); 780 } 781 782 for (JvmMethodParameterSignature parameter : signature.getValueParameters()) { 783 if (parameter.getKind() == JvmMethodParameterKind.RECEIVER) { 784 ReceiverParameterDescriptor receiverParameter = function.getExtensionReceiverParameter(); 785 if (receiverParameter != null) { 786 frameMap.enter(receiverParameter, state.getTypeMapper().mapType(receiverParameter)); 787 } 788 } 789 else if (parameter.getKind() != JvmMethodParameterKind.VALUE) { 790 frameMap.enterTemp(parameter.getAsmType()); 791 } 792 } 793 794 for (ValueParameterDescriptor parameter : function.getValueParameters()) { 795 frameMap.enter(parameter, state.getTypeMapper().mapType(parameter)); 796 } 797 798 return frameMap; 799 } 800 801 private static void loadExplicitArgumentsOnStack( 802 @NotNull Type ownerType, 803 boolean isStatic, 804 @NotNull JvmMethodSignature signature, 805 @NotNull CallGenerator callGenerator 806 ) { 807 int var = 0; 808 if (!isStatic) { 809 callGenerator.putValueIfNeeded(null, ownerType, StackValue.local(var, ownerType)); 810 var += ownerType.getSize(); 811 } 812 813 for (JvmMethodParameterSignature parameterSignature : signature.getValueParameters()) { 814 if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) { 815 Type type = parameterSignature.getAsmType(); 816 callGenerator.putValueIfNeeded(null, type, StackValue.local(var, type)); 817 var += type.getSize(); 818 } 819 } 820 } 821 822 private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) { 823 boolean needed = false; 824 if (functionDescriptor != null) { 825 for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) { 826 if (parameterDescriptor.declaresDefaultValue()) { 827 needed = true; 828 break; 829 } 830 } 831 } 832 return needed; 833 } 834 835 private void generateBridge( 836 @Nullable PsiElement origin, 837 @NotNull FunctionDescriptor descriptor, 838 @NotNull Method bridge, 839 @NotNull Method delegateTo, 840 boolean isSpecialBridge, 841 boolean isStubDeclarationWithDelegationToSuper 842 ) { 843 boolean isSpecialOrDelegationToSuper = isSpecialBridge || isStubDeclarationWithDelegationToSuper; 844 int flags = ACC_PUBLIC | ACC_BRIDGE | (!isSpecialOrDelegationToSuper ? ACC_SYNTHETIC : 0) | (isSpecialBridge ? ACC_FINAL : 0); // TODO. 845 846 MethodVisitor mv = 847 v.newMethod(JvmDeclarationOriginKt.Bridge(descriptor, origin), flags, bridge.getName(), bridge.getDescriptor(), null, null); 848 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 849 850 mv.visitCode(); 851 852 Type[] argTypes = bridge.getArgumentTypes(); 853 Type[] originalArgTypes = delegateTo.getArgumentTypes(); 854 855 InstructionAdapter iv = new InstructionAdapter(mv); 856 MemberCodegen.markLineNumberForDescriptor(owner.getThisDescriptor(), iv); 857 858 if (delegateTo.getArgumentTypes().length == 1 && isSpecialBridge) { 859 generateTypeCheckBarrierIfNeeded(iv, descriptor, bridge.getReturnType(), delegateTo.getArgumentTypes()[0]); 860 } 861 862 iv.load(0, OBJECT_TYPE); 863 for (int i = 0, reg = 1; i < argTypes.length; i++) { 864 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv); 865 //noinspection AssignmentToForLoopParameter 866 reg += argTypes[i].getSize(); 867 } 868 869 if (isStubDeclarationWithDelegationToSuper) { 870 ClassDescriptor parentClass = getSuperClassDescriptor((ClassDescriptor) descriptor.getContainingDeclaration()); 871 assert parentClass != null; 872 String parentInternalName = typeMapper.mapClass(parentClass).getInternalName(); 873 iv.invokespecial(parentInternalName, delegateTo.getName(), delegateTo.getDescriptor()); 874 } 875 else { 876 iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor()); 877 } 878 879 StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv); 880 iv.areturn(bridge.getReturnType()); 881 882 endVisit(mv, "bridge method", origin); 883 } 884 885 private static void generateTypeCheckBarrierIfNeeded( 886 @NotNull InstructionAdapter iv, 887 @NotNull FunctionDescriptor descriptor, 888 @NotNull Type returnType, 889 @Nullable final Type delegateParameterType 890 ) { 891 BuiltinMethodsWithSpecialGenericSignature.DefaultValue defaultValue = 892 BuiltinMethodsWithSpecialGenericSignature.getDefaultValueForOverriddenBuiltinFunction(descriptor); 893 if (defaultValue == null) return; 894 895 assert descriptor.getValueParameters().size() == 1 : "Should be descriptor with one value parameter, but found: " + descriptor; 896 897 boolean isCheckForAny = delegateParameterType == null || OBJECT_TYPE.equals(delegateParameterType); 898 899 final KotlinType kotlinType = descriptor.getValueParameters().get(0).getType(); 900 901 if (isCheckForAny && TypeUtils.isNullableType(kotlinType)) return; 902 903 iv.load(1, OBJECT_TYPE); 904 905 Label afterBarrier = new Label(); 906 907 if (isCheckForAny) { 908 assert !TypeUtils.isNullableType(kotlinType) : "Only bridges for not-nullable types are necessary"; 909 iv.ifnonnull(afterBarrier); 910 } 911 else { 912 CodegenUtilKt.generateIsCheck(iv, kotlinType.isMarkedNullable(), new Function1<InstructionAdapter, Unit>() { 913 @Override 914 public Unit invoke(InstructionAdapter adapter) { 915 TypeIntrinsics.instanceOf(adapter, kotlinType, boxType(delegateParameterType)); 916 return Unit.INSTANCE; 917 } 918 }); 919 iv.ifne(afterBarrier); 920 } 921 922 StackValue.constant(defaultValue.getValue(), returnType).put(returnType, iv); 923 iv.areturn(returnType); 924 925 iv.visitLabel(afterBarrier); 926 } 927 928 public void genDelegate(@NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) { 929 genDelegate(functionDescriptor, overriddenDescriptor.getOriginal(), 930 (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field); 931 } 932 933 public void genDelegate( 934 @NotNull final FunctionDescriptor delegateFunction, 935 final FunctionDescriptor delegatedTo, 936 final ClassDescriptor toClass, 937 final StackValue field 938 ) { 939 generateMethod( 940 JvmDeclarationOriginKt.Delegation(DescriptorToSourceUtils.descriptorToDeclaration(delegatedTo), delegateFunction), delegateFunction, 941 new FunctionGenerationStrategy() { 942 @Override 943 public void generateBody( 944 @NotNull MethodVisitor mv, 945 @NotNull FrameMap frameMap, 946 @NotNull JvmMethodSignature signature, 947 @NotNull MethodContext context, 948 @NotNull MemberCodegen<?> parentCodegen 949 ) { 950 Method delegateToMethod = typeMapper.mapSignature(delegatedTo).getAsmMethod(); 951 Method delegateMethod = typeMapper.mapSignature(delegateFunction).getAsmMethod(); 952 953 Type[] argTypes = delegateMethod.getArgumentTypes(); 954 Type[] originalArgTypes = delegateToMethod.getArgumentTypes(); 955 956 InstructionAdapter iv = new InstructionAdapter(mv); 957 iv.load(0, OBJECT_TYPE); 958 field.put(field.type, iv); 959 for (int i = 0, reg = 1; i < argTypes.length; i++) { 960 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv); 961 //noinspection AssignmentToForLoopParameter 962 reg += argTypes[i].getSize(); 963 } 964 965 String internalName = typeMapper.mapType(toClass).getInternalName(); 966 if (toClass.getKind() == ClassKind.INTERFACE) { 967 iv.invokeinterface(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor()); 968 } 969 else { 970 iv.invokevirtual(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor()); 971 } 972 973 StackValue stackValue = AsmUtil.genNotNullAssertions( 974 state, 975 StackValue.onStack(delegateToMethod.getReturnType()), 976 RuntimeAssertionInfo.create( 977 delegateFunction.getReturnType(), 978 delegatedTo.getReturnType(), 979 new RuntimeAssertionInfo.DataFlowExtras.OnlyMessage(delegatedTo.getName() + "(...)") 980 ) 981 ); 982 983 stackValue.put(delegateMethod.getReturnType(), iv); 984 985 iv.areturn(delegateMethod.getReturnType()); 986 } 987 } 988 ); 989 } 990 }