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