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