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