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