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