001 /* 002 * Copyright 2010-2015 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.kotlin.codegen; 018 019 import com.intellij.openapi.progress.ProcessCanceledException; 020 import com.intellij.psi.PsiElement; 021 import com.intellij.util.ArrayUtil; 022 import com.intellij.util.Function; 023 import com.intellij.util.containers.ContainerUtil; 024 import kotlin.jvm.functions.Function1; 025 import org.jetbrains.annotations.NotNull; 026 import org.jetbrains.annotations.Nullable; 027 import org.jetbrains.kotlin.backend.common.bridges.Bridge; 028 import org.jetbrains.kotlin.backend.common.bridges.BridgesPackage; 029 import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithOnlyTargetedAnnotations; 030 import org.jetbrains.kotlin.codegen.context.*; 031 import org.jetbrains.kotlin.codegen.optimization.OptimizationMethodVisitor; 032 import org.jetbrains.kotlin.codegen.state.GenerationState; 033 import org.jetbrains.kotlin.codegen.state.JetTypeMapper; 034 import org.jetbrains.kotlin.descriptors.*; 035 import org.jetbrains.kotlin.descriptors.annotations.Annotated; 036 import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; 037 import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget; 038 import org.jetbrains.kotlin.jvm.RuntimeAssertionInfo; 039 import org.jetbrains.kotlin.load.java.JvmAnnotationNames; 040 import org.jetbrains.kotlin.load.kotlin.nativeDeclarations.NativeDeclarationsPackage; 041 import org.jetbrains.kotlin.name.FqName; 042 import org.jetbrains.kotlin.psi.JetNamedFunction; 043 import org.jetbrains.kotlin.resolve.BindingContext; 044 import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; 045 import org.jetbrains.kotlin.resolve.DescriptorUtils; 046 import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage; 047 import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilPackage; 048 import org.jetbrains.kotlin.resolve.constants.ArrayValue; 049 import org.jetbrains.kotlin.resolve.constants.ConstantValue; 050 import org.jetbrains.kotlin.resolve.constants.KClassValue; 051 import org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage; 052 import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin; 053 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind; 054 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature; 055 import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; 056 import org.jetbrains.org.objectweb.asm.AnnotationVisitor; 057 import org.jetbrains.org.objectweb.asm.Label; 058 import org.jetbrains.org.objectweb.asm.MethodVisitor; 059 import org.jetbrains.org.objectweb.asm.Type; 060 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 061 import org.jetbrains.org.objectweb.asm.commons.Method; 062 import org.jetbrains.org.objectweb.asm.util.TraceMethodVisitor; 063 064 import java.io.PrintWriter; 065 import java.io.StringWriter; 066 import java.util.Collection; 067 import java.util.Iterator; 068 import java.util.List; 069 import java.util.Set; 070 071 import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isNullableAny; 072 import static org.jetbrains.kotlin.codegen.AsmUtil.*; 073 import static org.jetbrains.kotlin.codegen.JvmSerializationBindings.*; 074 import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.DECLARATION; 075 import static org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*; 076 import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.getSourceFromDescriptor; 077 import static org.jetbrains.kotlin.resolve.DescriptorUtils.*; 078 import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.OBJECT_TYPE; 079 import static org.jetbrains.kotlin.resolve.jvm.diagnostics.DiagnosticsPackage.*; 080 import static org.jetbrains.org.objectweb.asm.Opcodes.*; 081 082 public class FunctionCodegen { 083 public final GenerationState state; 084 private final JetTypeMapper typeMapper; 085 private final BindingContext bindingContext; 086 private final CodegenContext owner; 087 private final ClassBuilder v; 088 private final MemberCodegen<?> memberCodegen; 089 090 public FunctionCodegen( 091 @NotNull CodegenContext owner, 092 @NotNull ClassBuilder v, 093 @NotNull GenerationState state, 094 @NotNull MemberCodegen<?> memberCodegen 095 ) { 096 this.owner = owner; 097 this.v = v; 098 this.state = state; 099 this.typeMapper = state.getTypeMapper(); 100 this.bindingContext = state.getBindingContext(); 101 this.memberCodegen = memberCodegen; 102 } 103 104 public void gen(@NotNull JetNamedFunction function) { 105 SimpleFunctionDescriptor functionDescriptor = bindingContext.get(BindingContext.FUNCTION, function); 106 assert functionDescriptor != null : "No descriptor for function " + function.getText() + "\n" + 107 "in " + function.getContainingFile().getVirtualFile(); 108 109 if (owner.getContextKind() != OwnerKind.TRAIT_IMPL || function.hasBody()) { 110 generateMethod(OtherOrigin(function, functionDescriptor), functionDescriptor, 111 new FunctionGenerationStrategy.FunctionDefault(state, functionDescriptor, function)); 112 } 113 114 generateDefaultIfNeeded(owner.intoFunction(functionDescriptor), functionDescriptor, owner.getContextKind(), 115 DefaultParameterValueLoader.DEFAULT, function); 116 117 generateOverloadsWithDefaultValues(function, functionDescriptor, functionDescriptor); 118 } 119 120 public void generateOverloadsWithDefaultValues( 121 @Nullable JetNamedFunction function, 122 @NotNull FunctionDescriptor functionDescriptor, 123 @NotNull FunctionDescriptor delegateFunctionDescriptor 124 ) { 125 new DefaultParameterValueSubstitutor(state).generateOverloadsIfNeeded( 126 function, functionDescriptor, delegateFunctionDescriptor, owner.getContextKind(), v 127 ); 128 } 129 130 public void generateMethod( 131 @NotNull JvmDeclarationOrigin origin, 132 @NotNull FunctionDescriptor descriptor, 133 @NotNull FunctionGenerationStrategy strategy 134 ) { 135 generateMethod(origin, descriptor, owner.intoFunction(descriptor), strategy); 136 } 137 138 public void generateMethod( 139 @NotNull JvmDeclarationOrigin origin, 140 @NotNull FunctionDescriptor functionDescriptor, 141 @NotNull MethodContext methodContext, 142 @NotNull FunctionGenerationStrategy strategy 143 ) { 144 OwnerKind contextKind = methodContext.getContextKind(); 145 if (isTrait(functionDescriptor.getContainingDeclaration()) && 146 functionDescriptor.getVisibility() == Visibilities.PRIVATE && 147 contextKind != OwnerKind.TRAIT_IMPL) { 148 return; 149 } 150 151 JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, contextKind); 152 Method asmMethod = jvmSignature.getAsmMethod(); 153 154 int flags = getMethodAsmFlags(functionDescriptor, contextKind); 155 boolean isNative = NativeDeclarationsPackage.hasNativeAnnotation(functionDescriptor); 156 157 if (isNative && owner instanceof DelegatingFacadeContext) { 158 // Native methods are only defined in facades and do not need package part implementations 159 return; 160 } 161 MethodVisitor mv = v.newMethod(origin, 162 flags, 163 asmMethod.getName(), 164 asmMethod.getDescriptor(), 165 jvmSignature.getGenericsSignature(), 166 getThrownExceptions(functionDescriptor, typeMapper)); 167 168 String implClassName = CodegenContextUtil.getImplementationClassShortName(owner); 169 if (implClassName != null) { 170 v.getSerializationBindings().put(IMPL_CLASS_NAME_FOR_CALLABLE, functionDescriptor, implClassName); 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 = AnnotationsPackage.isPlatformStaticInCompanionObject(functionDescriptor); 183 if (staticInCompanionObject) { 184 ImplementationBodyCodegen parentBodyCodegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen(); 185 parentBodyCodegen.addAdditionalTask(new PlatformStaticGenerator(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 platformStatic foo() in companion object should delegate to the static native function moved to the outer class 208 mv.visitCode(); 209 FunctionDescriptor staticFunctionDescriptor = PlatformStaticGenerator.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 methodContext.recordSyntheticAccessorIfNeeded(functionDescriptor, bindingContext); 219 } 220 221 private void generateMethodAnnotations( 222 @NotNull FunctionDescriptor functionDescriptor, 223 Method asmMethod, 224 MethodVisitor mv 225 ) { 226 AnnotationCodegen annotationCodegen = AnnotationCodegen.forMethod(mv, typeMapper); 227 228 if (functionDescriptor instanceof PropertyAccessorDescriptor) { 229 AnnotationUseSiteTarget target = functionDescriptor instanceof PropertySetterDescriptor ? PROPERTY_SETTER : PROPERTY_GETTER; 230 annotationCodegen.genAnnotations(functionDescriptor, asmMethod.getReturnType(), target); 231 } 232 else { 233 annotationCodegen.genAnnotations(functionDescriptor, asmMethod.getReturnType()); 234 } 235 236 writePackageFacadeMethodAnnotationsIfNeeded(mv); 237 } 238 239 private void writePackageFacadeMethodAnnotationsIfNeeded(MethodVisitor mv) { 240 if (owner instanceof PackageFacadeContext) { 241 PackageFacadeContext packageFacadeContext = (PackageFacadeContext) owner; 242 Type delegateToClassType = packageFacadeContext.getDelegateToClassType(); 243 if (delegateToClassType != null) { 244 String className = delegateToClassType.getClassName(); 245 AnnotationVisitor 246 av = mv.visitAnnotation(AsmUtil.asmDescByFqNameWithoutInnerClasses(JvmAnnotationNames.KOTLIN_DELEGATED_METHOD), true); 247 av.visit(JvmAnnotationNames.IMPLEMENTATION_CLASS_NAME_FIELD_NAME, className); 248 av.visitEnd(); 249 } 250 } 251 } 252 253 private void generateParameterAnnotations( 254 @NotNull FunctionDescriptor functionDescriptor, 255 @NotNull MethodVisitor mv, 256 @NotNull JvmMethodSignature jvmSignature 257 ) { 258 Iterator<ValueParameterDescriptor> iterator = functionDescriptor.getValueParameters().iterator(); 259 List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getValueParameters(); 260 261 for (int i = 0; i < kotlinParameterTypes.size(); i++) { 262 JvmMethodParameterSignature parameterSignature = kotlinParameterTypes.get(i); 263 JvmMethodParameterKind kind = parameterSignature.getKind(); 264 if (kind.isSkippedInGenericSignature()) { 265 markEnumOrInnerConstructorParameterAsSynthetic(mv, i); 266 continue; 267 } 268 269 if (kind == JvmMethodParameterKind.VALUE) { 270 ValueParameterDescriptor parameter = iterator.next(); 271 v.getSerializationBindings().put(INDEX_FOR_VALUE_PARAMETER, parameter, i); 272 AnnotationCodegen annotationCodegen = AnnotationCodegen.forParameter(i, mv, typeMapper); 273 274 if (functionDescriptor instanceof PropertySetterDescriptor) { 275 PropertyDescriptor propertyDescriptor = ((PropertySetterDescriptor) functionDescriptor).getCorrespondingProperty(); 276 Annotated targetedAnnotations = new AnnotatedWithOnlyTargetedAnnotations(propertyDescriptor); 277 annotationCodegen.genAnnotations(targetedAnnotations, parameterSignature.getAsmType(), SETTER_PARAMETER); 278 } 279 280 if (functionDescriptor instanceof ConstructorDescriptor) { 281 annotationCodegen.genAnnotations(parameter, parameterSignature.getAsmType(), CONSTRUCTOR_PARAMETER); 282 } 283 else { 284 annotationCodegen.genAnnotations(parameter, parameterSignature.getAsmType()); 285 } 286 } 287 else if (kind == JvmMethodParameterKind.RECEIVER) { 288 ReceiverParameterDescriptor receiver = ((functionDescriptor instanceof PropertyAccessorDescriptor) 289 ? ((PropertyAccessorDescriptor) functionDescriptor).getCorrespondingProperty() 290 : functionDescriptor).getExtensionReceiverParameter(); 291 if (receiver != null) { 292 AnnotationCodegen annotationCodegen = AnnotationCodegen.forParameter(i, mv, typeMapper); 293 Annotated targetedAnnotations = new AnnotatedWithOnlyTargetedAnnotations(receiver.getType()); 294 annotationCodegen.genAnnotations(targetedAnnotations, parameterSignature.getAsmType(), RECEIVER); 295 } 296 } 297 } 298 } 299 300 private void markEnumOrInnerConstructorParameterAsSynthetic(MethodVisitor mv, int i) { 301 // IDEA's ClsPsi builder fails to annotate synthetic parameters 302 if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return; 303 304 // This is needed to avoid RuntimeInvisibleParameterAnnotations error in javac: 305 // see MethodWriter.visitParameterAnnotation() 306 307 AnnotationVisitor av = mv.visitParameterAnnotation(i, "Ljava/lang/Synthetic;", true); 308 if (av != null) { 309 av.visitEnd(); 310 } 311 } 312 313 @Nullable 314 private static Type getThisTypeForFunction( 315 @NotNull FunctionDescriptor functionDescriptor, 316 @NotNull MethodContext context, 317 @NotNull JetTypeMapper typeMapper 318 ) { 319 ReceiverParameterDescriptor dispatchReceiver = functionDescriptor.getDispatchReceiverParameter(); 320 if (functionDescriptor instanceof ConstructorDescriptor) { 321 return typeMapper.mapType(functionDescriptor); 322 } 323 else if (dispatchReceiver != null) { 324 return typeMapper.mapType(dispatchReceiver.getType()); 325 } 326 else if (isFunctionLiteral(functionDescriptor) || 327 isLocalFunction(functionDescriptor) || 328 isFunctionExpression(functionDescriptor) 329 ) { 330 return typeMapper.mapType(context.getThisDescriptor()); 331 } 332 else { 333 return null; 334 } 335 } 336 337 public static void generateMethodBody( 338 @NotNull MethodVisitor mv, 339 @NotNull FunctionDescriptor functionDescriptor, 340 @NotNull MethodContext context, 341 @NotNull JvmMethodSignature signature, 342 @NotNull FunctionGenerationStrategy strategy, 343 @NotNull MemberCodegen<?> parentCodegen 344 ) { 345 mv.visitCode(); 346 347 Label methodBegin = new Label(); 348 mv.visitLabel(methodBegin); 349 350 JetTypeMapper typeMapper = parentCodegen.typeMapper; 351 352 Label methodEnd; 353 if (context.getParentContext() instanceof DelegatingFacadeContext) { 354 generateFacadeDelegateMethodBody(mv, signature.getAsmMethod(), (DelegatingFacadeContext) context.getParentContext()); 355 methodEnd = new Label(); 356 } 357 else { 358 FrameMap frameMap = createFrameMap(parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(), 359 functionDescriptor)); 360 361 Label methodEntry = new Label(); 362 mv.visitLabel(methodEntry); 363 context.setMethodStartLabel(methodEntry); 364 365 if (!JetTypeMapper.isAccessor(functionDescriptor)) { 366 genNotNullAssertionsForParameters(new InstructionAdapter(mv), parentCodegen.state, functionDescriptor, frameMap); 367 } 368 methodEnd = new Label(); 369 context.setMethodEndLabel(methodEnd); 370 strategy.generateBody(mv, frameMap, signature, context, parentCodegen); 371 } 372 373 mv.visitLabel(methodEnd); 374 375 Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper); 376 generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind()); 377 } 378 379 private static void generateLocalVariableTable( 380 @NotNull MethodVisitor mv, 381 @NotNull JvmMethodSignature jvmMethodSignature, 382 @NotNull FunctionDescriptor functionDescriptor, 383 @Nullable Type thisType, 384 @NotNull Label methodBegin, 385 @NotNull Label methodEnd, 386 @NotNull OwnerKind ownerKind 387 ) { 388 Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator(); 389 List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters(); 390 int shift = 0; 391 392 boolean isStatic = AsmUtil.isStaticMethod(ownerKind, functionDescriptor); 393 if (!isStatic) { 394 //add this 395 if (thisType != null) { 396 mv.visitLocalVariable("this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift); 397 } 398 else { 399 //TODO: provide thisType for callable reference 400 } 401 shift++; 402 } 403 404 for (int i = 0; i < params.size(); i++) { 405 JvmMethodParameterSignature param = params.get(i); 406 JvmMethodParameterKind kind = param.getKind(); 407 String parameterName; 408 409 if (kind == JvmMethodParameterKind.VALUE) { 410 ValueParameterDescriptor parameter = valueParameters.next(); 411 parameterName = parameter.getName().asString(); 412 } 413 else { 414 String lowercaseKind = kind.name().toLowerCase(); 415 parameterName = needIndexForVar(kind) 416 ? "$" + lowercaseKind + "$" + i 417 : "$" + lowercaseKind; 418 } 419 420 Type type = param.getAsmType(); 421 mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift); 422 shift += type.getSize(); 423 } 424 } 425 426 private static void generateFacadeDelegateMethodBody( 427 @NotNull MethodVisitor mv, 428 @NotNull Method asmMethod, 429 @NotNull DelegatingFacadeContext context 430 ) { 431 generateDelegateToMethodBody(true, mv, asmMethod, context.getDelegateToClassType().getInternalName()); 432 } 433 434 private static void generateDelegateToMethodBody( 435 boolean isStatic, 436 @NotNull MethodVisitor mv, 437 @NotNull Method asmMethod, 438 @NotNull String classToDelegateTo 439 ) { 440 InstructionAdapter iv = new InstructionAdapter(mv); 441 Type[] argTypes = asmMethod.getArgumentTypes(); 442 443 // The first line of some package file is written to the line number attribute of a static delegate to allow to 'step into' it 444 // This is similar to what javac does with bridge methods 445 Label label = new Label(); 446 iv.visitLabel(label); 447 iv.visitLineNumber(1, label); 448 449 int k = isStatic ? 0 : 1; 450 for (Type argType : argTypes) { 451 iv.load(k, argType); 452 k += argType.getSize(); 453 } 454 iv.invokestatic(classToDelegateTo, asmMethod.getName(), asmMethod.getDescriptor(), false); 455 iv.areturn(asmMethod.getReturnType()); 456 } 457 458 private static boolean needIndexForVar(JvmMethodParameterKind kind) { 459 return kind == JvmMethodParameterKind.CAPTURED_LOCAL_VARIABLE || 460 kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL || 461 kind == JvmMethodParameterKind.SUPER_CALL_PARAM; 462 } 463 464 public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) { 465 try { 466 mv.visitMaxs(-1, -1); 467 mv.visitEnd(); 468 } 469 catch (ProcessCanceledException e) { 470 throw e; 471 } 472 catch (Throwable t) { 473 String bytecode = renderByteCodeIfAvailable(mv); 474 throw new CompilationException( 475 "wrong code generated" + 476 (description != null ? " for " + description : "") + 477 t.getClass().getName() + 478 " " + 479 t.getMessage() + 480 (bytecode != null ? "\nbytecode:\n" + bytecode : ""), 481 t, method); 482 } 483 } 484 485 private static String renderByteCodeIfAvailable(MethodVisitor mv) { 486 String bytecode = null; 487 488 if (mv instanceof OptimizationMethodVisitor) { 489 mv = ((OptimizationMethodVisitor) mv).getTraceMethodVisitorIfPossible(); 490 } 491 492 if (mv instanceof TraceMethodVisitor) { 493 TraceMethodVisitor traceMethodVisitor = (TraceMethodVisitor) mv; 494 StringWriter sw = new StringWriter(); 495 PrintWriter pw = new PrintWriter(sw); 496 traceMethodVisitor.p.print(pw); 497 pw.close(); 498 bytecode = sw.toString(); 499 } 500 return bytecode; 501 } 502 503 public void generateBridges(@NotNull FunctionDescriptor descriptor) { 504 if (descriptor instanceof ConstructorDescriptor) return; 505 if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) return; 506 if (isTrait(descriptor.getContainingDeclaration())) return; 507 508 // equals(Any?), hashCode(), toString() never need bridges 509 if (isMethodOfAny(descriptor)) return; 510 511 // If the function doesn't have a physical declaration among super-functions, it's a SAM adapter or alike and doesn't need bridges 512 if (CallResolverUtilPackage.isOrOverridesSynthesized(descriptor)) return; 513 514 Set<Bridge<Method>> bridgesToGenerate = BridgesPackage.generateBridgesForFunctionDescriptor( 515 descriptor, 516 new Function1<FunctionDescriptor, Method>() { 517 @Override 518 public Method invoke(FunctionDescriptor descriptor) { 519 return typeMapper.mapSignature(descriptor).getAsmMethod(); 520 } 521 } 522 ); 523 524 if (!bridgesToGenerate.isEmpty()) { 525 PsiElement origin = descriptor.getKind() == DECLARATION ? getSourceFromDescriptor(descriptor) : null; 526 for (Bridge<Method> bridge : bridgesToGenerate) { 527 generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo()); 528 } 529 } 530 } 531 532 private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) { 533 String name = descriptor.getName().asString(); 534 List<ValueParameterDescriptor> parameters = descriptor.getValueParameters(); 535 if (parameters.isEmpty()) { 536 return name.equals("hashCode") || name.equals("toString"); 537 } 538 else if (parameters.size() == 1 && name.equals("equals")) { 539 return isNullableAny(parameters.get(0).getType()); 540 } 541 return false; 542 } 543 544 @NotNull 545 public static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final JetTypeMapper mapper) { 546 AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws")); 547 if (annotation == null) { 548 annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.jvm.Throws")); 549 } 550 551 if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY; 552 553 Collection<ConstantValue<?>> values = annotation.getAllValueArguments().values(); 554 if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY; 555 556 Object value = values.iterator().next(); 557 if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY; 558 ArrayValue arrayValue = (ArrayValue) value; 559 560 List<String> strings = ContainerUtil.mapNotNull( 561 arrayValue.getValue(), 562 new Function<ConstantValue<?>, String>() { 563 @Override 564 public String fun(ConstantValue<?> constant) { 565 if (constant instanceof KClassValue) { 566 KClassValue classValue = (KClassValue) constant; 567 ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue()); 568 return mapper.mapClass(classDescriptor).getInternalName(); 569 } 570 return null; 571 } 572 } 573 ); 574 return ArrayUtil.toStringArray(strings); 575 } 576 577 void generateDefaultIfNeeded( 578 @NotNull MethodContext owner, 579 @NotNull FunctionDescriptor functionDescriptor, 580 @NotNull OwnerKind kind, 581 @NotNull DefaultParameterValueLoader loadStrategy, 582 @Nullable JetNamedFunction function 583 ) { 584 DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration(); 585 586 if (kind != OwnerKind.TRAIT_IMPL && isTrait(contextClass)) { 587 return; 588 } 589 590 if (!isDefaultNeeded(functionDescriptor)) { 591 return; 592 } 593 594 int flags = getVisibilityAccessFlag(functionDescriptor) | 595 getDeprecatedAccessFlag(functionDescriptor) | 596 ACC_SYNTHETIC; 597 if (!(functionDescriptor instanceof ConstructorDescriptor)) { 598 flags |= ACC_STATIC; 599 } 600 // $default methods are never private to be accessible from other class files (e.g. inner) without the need of synthetic accessors 601 flags &= ~ACC_PRIVATE; 602 603 Method defaultMethod = typeMapper.mapDefaultMethod(functionDescriptor, kind); 604 605 MethodVisitor mv = v.newMethod( 606 Synthetic(function, functionDescriptor), 607 flags, 608 defaultMethod.getName(), 609 defaultMethod.getDescriptor(), null, 610 getThrownExceptions(functionDescriptor, typeMapper) 611 ); 612 613 // Only method annotations are copied to the $default method. Parameter annotations are not copied until there are valid use cases; 614 // enum constructors have two additional synthetic parameters which somewhat complicate this task 615 AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(functionDescriptor, defaultMethod.getReturnType()); 616 617 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 618 if (this.owner instanceof DelegatingFacadeContext) { 619 mv.visitCode(); 620 generateFacadeDelegateMethodBody(mv, defaultMethod, (DelegatingFacadeContext) this.owner); 621 endVisit(mv, "default method delegation", getSourceFromDescriptor(functionDescriptor)); 622 } 623 else { 624 mv.visitCode(); 625 generateDefaultImplBody(owner, functionDescriptor, mv, loadStrategy, function, memberCodegen); 626 endVisit(mv, "default method", getSourceFromDescriptor(functionDescriptor)); 627 } 628 } 629 } 630 631 public static void generateDefaultImplBody( 632 @NotNull MethodContext methodContext, 633 @NotNull FunctionDescriptor functionDescriptor, 634 @NotNull MethodVisitor mv, 635 @NotNull DefaultParameterValueLoader loadStrategy, 636 @Nullable JetNamedFunction function, 637 @NotNull MemberCodegen<?> parentCodegen 638 ) { 639 GenerationState state = parentCodegen.state; 640 JvmMethodSignature signature = state.getTypeMapper().mapSignature(functionDescriptor, methodContext.getContextKind()); 641 642 boolean isStatic = isStaticMethod(methodContext.getContextKind(), functionDescriptor); 643 FrameMap frameMap = createFrameMap(state, functionDescriptor, signature, isStatic); 644 645 ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, signature.getReturnType(), methodContext, state, parentCodegen); 646 647 CallGenerator generator = codegen.getOrCreateCallGenerator(functionDescriptor, function); 648 649 loadExplicitArgumentsOnStack(OBJECT_TYPE, isStatic, signature, generator); 650 651 List<JvmMethodParameterSignature> mappedParameters = signature.getValueParameters(); 652 int capturedArgumentsCount = 0; 653 while (capturedArgumentsCount < mappedParameters.size() && 654 mappedParameters.get(capturedArgumentsCount).getKind() != JvmMethodParameterKind.VALUE) { 655 capturedArgumentsCount++; 656 } 657 658 InstructionAdapter iv = new InstructionAdapter(mv); 659 660 int maskIndex = 0; 661 List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters(); 662 for (int index = 0; index < valueParameters.size(); index++) { 663 if (index % Integer.SIZE == 0) { 664 maskIndex = frameMap.enterTemp(Type.INT_TYPE); 665 } 666 ValueParameterDescriptor parameterDescriptor = valueParameters.get(index); 667 Type type = mappedParameters.get(capturedArgumentsCount + index).getAsmType(); 668 669 int parameterIndex = frameMap.getIndex(parameterDescriptor); 670 if (parameterDescriptor.declaresDefaultValue()) { 671 iv.load(maskIndex, Type.INT_TYPE); 672 iv.iconst(1 << (index % Integer.SIZE)); 673 iv.and(Type.INT_TYPE); 674 Label loadArg = new Label(); 675 iv.ifeq(loadArg); 676 677 StackValue.local(parameterIndex, type).store(loadStrategy.genValue(parameterDescriptor, codegen), iv); 678 679 iv.mark(loadArg); 680 } 681 682 generator.putValueIfNeeded(parameterDescriptor, type, StackValue.local(parameterIndex, type)); 683 } 684 685 CallableMethod method = state.getTypeMapper().mapToCallableMethod(functionDescriptor, false); 686 687 generator.genCallWithoutAssertions(method, codegen); 688 689 iv.areturn(signature.getReturnType()); 690 } 691 692 @NotNull 693 private static FrameMap createFrameMap( 694 @NotNull GenerationState state, 695 @NotNull FunctionDescriptor function, 696 @NotNull JvmMethodSignature signature, 697 boolean isStatic 698 ) { 699 FrameMap frameMap = new FrameMap(); 700 if (!isStatic) { 701 frameMap.enterTemp(OBJECT_TYPE); 702 } 703 704 for (JvmMethodParameterSignature parameter : signature.getValueParameters()) { 705 if (parameter.getKind() == JvmMethodParameterKind.RECEIVER) { 706 ReceiverParameterDescriptor receiverParameter = function.getExtensionReceiverParameter(); 707 if (receiverParameter != null) { 708 frameMap.enter(receiverParameter, state.getTypeMapper().mapType(receiverParameter)); 709 } 710 } 711 else if (parameter.getKind() != JvmMethodParameterKind.VALUE) { 712 frameMap.enterTemp(parameter.getAsmType()); 713 } 714 } 715 716 for (ValueParameterDescriptor parameter : function.getValueParameters()) { 717 frameMap.enter(parameter, state.getTypeMapper().mapType(parameter)); 718 } 719 720 return frameMap; 721 } 722 723 private static void loadExplicitArgumentsOnStack( 724 @NotNull Type ownerType, 725 boolean isStatic, 726 @NotNull JvmMethodSignature signature, 727 @NotNull CallGenerator callGenerator 728 ) { 729 int var = 0; 730 if (!isStatic) { 731 callGenerator.putValueIfNeeded(null, ownerType, StackValue.local(var, ownerType)); 732 var += ownerType.getSize(); 733 } 734 735 for (JvmMethodParameterSignature parameterSignature : signature.getValueParameters()) { 736 if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) { 737 Type type = parameterSignature.getAsmType(); 738 callGenerator.putValueIfNeeded(null, type, StackValue.local(var, type)); 739 var += type.getSize(); 740 } 741 } 742 } 743 744 private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) { 745 boolean needed = false; 746 if (functionDescriptor != null) { 747 for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) { 748 if (parameterDescriptor.declaresDefaultValue()) { 749 needed = true; 750 break; 751 } 752 } 753 } 754 return needed; 755 } 756 757 private void generateBridge( 758 @Nullable PsiElement origin, 759 @NotNull FunctionDescriptor descriptor, 760 @NotNull Method bridge, 761 @NotNull Method delegateTo 762 ) { 763 int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO. 764 765 MethodVisitor mv = 766 v.newMethod(DiagnosticsPackage.Bridge(descriptor, origin), flags, bridge.getName(), bridge.getDescriptor(), null, null); 767 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 768 769 mv.visitCode(); 770 771 Type[] argTypes = bridge.getArgumentTypes(); 772 Type[] originalArgTypes = delegateTo.getArgumentTypes(); 773 774 InstructionAdapter iv = new InstructionAdapter(mv); 775 ImplementationBodyCodegen.markLineNumberForSyntheticFunction(owner.getThisDescriptor(), iv); 776 777 iv.load(0, OBJECT_TYPE); 778 for (int i = 0, reg = 1; i < argTypes.length; i++) { 779 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv); 780 //noinspection AssignmentToForLoopParameter 781 reg += argTypes[i].getSize(); 782 } 783 784 iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor()); 785 786 StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv); 787 iv.areturn(bridge.getReturnType()); 788 789 endVisit(mv, "bridge method", origin); 790 } 791 792 public void genDelegate(@NotNull FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) { 793 genDelegate(functionDescriptor, overriddenDescriptor.getOriginal(), 794 (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field); 795 } 796 797 public void genDelegate( 798 @NotNull final FunctionDescriptor delegateFunction, 799 final FunctionDescriptor delegatedTo, 800 final ClassDescriptor toClass, 801 final StackValue field 802 ) { 803 generateMethod( 804 Delegation(DescriptorToSourceUtils.descriptorToDeclaration(delegatedTo), delegateFunction), delegateFunction, 805 new FunctionGenerationStrategy() { 806 @Override 807 public void generateBody( 808 @NotNull MethodVisitor mv, 809 @NotNull FrameMap frameMap, 810 @NotNull JvmMethodSignature signature, 811 @NotNull MethodContext context, 812 @NotNull MemberCodegen<?> parentCodegen 813 ) { 814 Method delegateToMethod = typeMapper.mapSignature(delegatedTo).getAsmMethod(); 815 Method delegateMethod = typeMapper.mapSignature(delegateFunction).getAsmMethod(); 816 817 Type[] argTypes = delegateMethod.getArgumentTypes(); 818 Type[] originalArgTypes = delegateToMethod.getArgumentTypes(); 819 820 InstructionAdapter iv = new InstructionAdapter(mv); 821 iv.load(0, OBJECT_TYPE); 822 field.put(field.type, iv); 823 for (int i = 0, reg = 1; i < argTypes.length; i++) { 824 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv); 825 //noinspection AssignmentToForLoopParameter 826 reg += argTypes[i].getSize(); 827 } 828 829 String internalName = typeMapper.mapType(toClass).getInternalName(); 830 if (toClass.getKind() == ClassKind.INTERFACE) { 831 iv.invokeinterface(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor()); 832 } 833 else { 834 iv.invokevirtual(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor()); 835 } 836 837 StackValue stackValue = AsmUtil.genNotNullAssertions( 838 state, 839 StackValue.onStack(delegateToMethod.getReturnType()), 840 RuntimeAssertionInfo.create( 841 delegateFunction.getReturnType(), 842 delegatedTo.getReturnType(), 843 new RuntimeAssertionInfo.DataFlowExtras.OnlyMessage(delegatedTo.getName() + "(...)") 844 ) 845 ); 846 847 stackValue.put(delegateMethod.getReturnType(), iv); 848 849 iv.areturn(delegateMethod.getReturnType()); 850 } 851 } 852 ); 853 } 854 }