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