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