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