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