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