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 Label methodEnd; 324 if (context.getParentContext() instanceof PackageFacadeContext) { 325 generatePackageDelegateMethodBody(mv, signature.getAsmMethod(), (PackageFacadeContext) context.getParentContext()); 326 methodEnd = new Label(); 327 } 328 else { 329 FrameMap frameMap = createFrameMap(parentCodegen.state, functionDescriptor, signature, isStaticMethod(context.getContextKind(), 330 functionDescriptor)); 331 332 Label methodEntry = new Label(); 333 mv.visitLabel(methodEntry); 334 context.setMethodStartLabel(methodEntry); 335 336 if (!JetTypeMapper.isAccessor(functionDescriptor)) { 337 genNotNullAssertionsForParameters(new InstructionAdapter(mv), parentCodegen.state, functionDescriptor, frameMap); 338 } 339 methodEnd = new Label(); 340 context.setMethodEndLabel(methodEnd); 341 strategy.generateBody(mv, frameMap, signature, context, parentCodegen); 342 } 343 344 mv.visitLabel(methodEnd); 345 346 Type thisType = getThisTypeForFunction(functionDescriptor, context, typeMapper); 347 generateLocalVariableTable(mv, signature, functionDescriptor, thisType, methodBegin, methodEnd, context.getContextKind()); 348 } 349 350 private static void generateLocalVariableTable( 351 @NotNull MethodVisitor mv, 352 @NotNull JvmMethodSignature jvmMethodSignature, 353 @NotNull FunctionDescriptor functionDescriptor, 354 @Nullable Type thisType, 355 @NotNull Label methodBegin, 356 @NotNull Label methodEnd, 357 @NotNull OwnerKind ownerKind 358 ) { 359 Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator(); 360 List<JvmMethodParameterSignature> params = jvmMethodSignature.getValueParameters(); 361 int shift = 0; 362 363 boolean isStatic = AsmUtil.isStaticMethod(ownerKind, functionDescriptor); 364 if (!isStatic) { 365 //add this 366 if (thisType != null) { 367 mv.visitLocalVariable("this", thisType.getDescriptor(), null, methodBegin, methodEnd, shift); 368 } else { 369 //TODO: provide thisType for callable reference 370 } 371 shift++; 372 } 373 374 for (int i = 0; i < params.size(); i++) { 375 JvmMethodParameterSignature param = params.get(i); 376 JvmMethodParameterKind kind = param.getKind(); 377 String parameterName; 378 379 if (kind == JvmMethodParameterKind.VALUE) { 380 ValueParameterDescriptor parameter = valueParameters.next(); 381 parameterName = parameter.getName().asString(); 382 } 383 else { 384 String lowercaseKind = kind.name().toLowerCase(); 385 parameterName = needIndexForVar(kind) 386 ? "$" + lowercaseKind + "$" + i 387 : "$" + lowercaseKind; 388 } 389 390 Type type = param.getAsmType(); 391 mv.visitLocalVariable(parameterName, type.getDescriptor(), null, methodBegin, methodEnd, shift); 392 shift += type.getSize(); 393 } 394 } 395 396 private static void generatePackageDelegateMethodBody( 397 @NotNull MethodVisitor mv, 398 @NotNull Method asmMethod, 399 @NotNull PackageFacadeContext context 400 ) { 401 generateDelegateToMethodBody(true, mv, asmMethod, context.getDelegateToClassType().getInternalName()); 402 } 403 404 private static void generateDelegateToMethodBody( 405 boolean isStatic, 406 @NotNull MethodVisitor mv, 407 @NotNull Method asmMethod, 408 @NotNull String classToDelegateTo 409 ) { 410 InstructionAdapter iv = new InstructionAdapter(mv); 411 Type[] argTypes = asmMethod.getArgumentTypes(); 412 413 // The first line of some package file is written to the line number attribute of a static delegate to allow to 'step into' it 414 // This is similar to what javac does with bridge methods 415 Label label = new Label(); 416 iv.visitLabel(label); 417 iv.visitLineNumber(1, label); 418 419 int k = isStatic ? 0 : 1; 420 for (Type argType : argTypes) { 421 iv.load(k, argType); 422 k += argType.getSize(); 423 } 424 iv.invokestatic(classToDelegateTo, asmMethod.getName(), asmMethod.getDescriptor(), false); 425 iv.areturn(asmMethod.getReturnType()); 426 } 427 428 private static boolean needIndexForVar(JvmMethodParameterKind kind) { 429 return kind == JvmMethodParameterKind.CAPTURED_LOCAL_VARIABLE || 430 kind == JvmMethodParameterKind.ENUM_NAME_OR_ORDINAL || 431 kind == JvmMethodParameterKind.SUPER_CALL_PARAM; 432 } 433 434 public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) { 435 try { 436 mv.visitMaxs(-1, -1); 437 mv.visitEnd(); 438 } 439 catch (ProcessCanceledException e) { 440 throw e; 441 } 442 catch (Throwable t) { 443 String bytecode = renderByteCodeIfAvailable(mv); 444 throw new CompilationException( 445 "wrong code generated" + 446 (description != null ? " for " + description : "") + 447 t.getClass().getName() + 448 " " + 449 t.getMessage() + 450 (bytecode != null ? "\nbytecode:\n" + bytecode : ""), 451 t, method); 452 } 453 } 454 455 private static String renderByteCodeIfAvailable(MethodVisitor mv) { 456 String bytecode = null; 457 458 if (mv instanceof OptimizationMethodVisitor) { 459 mv = ((OptimizationMethodVisitor) mv).getTraceMethodVisitorIfPossible(); 460 } 461 462 if (mv instanceof TraceMethodVisitor) { 463 TraceMethodVisitor traceMethodVisitor = (TraceMethodVisitor) mv; 464 StringWriter sw = new StringWriter(); 465 PrintWriter pw = new PrintWriter(sw); 466 traceMethodVisitor.p.print(pw); 467 pw.close(); 468 bytecode = sw.toString(); 469 } 470 return bytecode; 471 } 472 473 public void generateBridges(@NotNull FunctionDescriptor descriptor) { 474 if (descriptor instanceof ConstructorDescriptor) return; 475 if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) return; 476 if (isTrait(descriptor.getContainingDeclaration())) return; 477 478 // equals(Any?), hashCode(), toString() never need bridges 479 if (isMethodOfAny(descriptor)) return; 480 481 // If the function doesn't have a physical declaration among super-functions, it's a SAM adapter or alike and doesn't need bridges 482 if (CallResolverUtil.isOrOverridesSynthesized(descriptor)) return; 483 484 Set<Bridge<Method>> bridgesToGenerate = BridgesPackage.generateBridgesForFunctionDescriptor( 485 descriptor, 486 new Function1<FunctionDescriptor, Method>() { 487 @Override 488 public Method invoke(FunctionDescriptor descriptor) { 489 return typeMapper.mapSignature(descriptor).getAsmMethod(); 490 } 491 } 492 ); 493 494 if (!bridgesToGenerate.isEmpty()) { 495 PsiElement origin = descriptor.getKind() == DECLARATION ? callableDescriptorToDeclaration(descriptor) : null; 496 for (Bridge<Method> bridge : bridgesToGenerate) { 497 generateBridge(origin, descriptor, bridge.getFrom(), bridge.getTo()); 498 } 499 } 500 } 501 502 private static boolean isMethodOfAny(@NotNull FunctionDescriptor descriptor) { 503 String name = descriptor.getName().asString(); 504 List<ValueParameterDescriptor> parameters = descriptor.getValueParameters(); 505 if (parameters.isEmpty()) { 506 return name.equals("hashCode") || name.equals("toString"); 507 } 508 else if (parameters.size() == 1 && name.equals("equals")) { 509 ValueParameterDescriptor parameter = parameters.get(0); 510 return parameter.getType().equals(KotlinBuiltIns.getInstance().getNullableAnyType()); 511 } 512 return false; 513 } 514 515 @NotNull 516 public static String[] getThrownExceptions(@NotNull FunctionDescriptor function, @NotNull final JetTypeMapper mapper) { 517 AnnotationDescriptor annotation = function.getAnnotations().findAnnotation(new FqName("kotlin.throws")); 518 if (annotation == null) return ArrayUtil.EMPTY_STRING_ARRAY; 519 520 Collection<CompileTimeConstant<?>> values = annotation.getAllValueArguments().values(); 521 if (values.isEmpty()) return ArrayUtil.EMPTY_STRING_ARRAY; 522 523 Object value = values.iterator().next(); 524 if (!(value instanceof ArrayValue)) return ArrayUtil.EMPTY_STRING_ARRAY; 525 ArrayValue arrayValue = (ArrayValue) value; 526 527 List<String> strings = ContainerUtil.mapNotNull( 528 arrayValue.getValue(), 529 new Function<CompileTimeConstant<?>, String>() { 530 @Override 531 public String fun(CompileTimeConstant<?> constant) { 532 if (constant instanceof JavaClassValue) { 533 JavaClassValue classValue = (JavaClassValue) constant; 534 ClassDescriptor classDescriptor = DescriptorUtils.getClassDescriptorForType(classValue.getValue()); 535 return mapper.mapClass(classDescriptor).getInternalName(); 536 } 537 return null; 538 } 539 } 540 ); 541 return ArrayUtil.toStringArray(strings); 542 } 543 544 static void generateConstructorWithoutParametersIfNeeded( 545 @NotNull GenerationState state, 546 @NotNull CallableMethod method, 547 @NotNull ConstructorDescriptor constructorDescriptor, 548 @NotNull ClassBuilder classBuilder, 549 @NotNull JetClassOrObject classOrObject 550 ) { 551 if (!isEmptyConstructorNeeded(state.getBindingContext(), constructorDescriptor, classOrObject)) { 552 return; 553 } 554 int flags = getVisibilityAccessFlag(constructorDescriptor); 555 MethodVisitor mv = classBuilder.newMethod(OtherOrigin(constructorDescriptor), flags, "<init>", "()V", null, 556 getThrownExceptions(constructorDescriptor, state.getTypeMapper())); 557 558 if (state.getClassBuilderMode() == ClassBuilderMode.LIGHT_CLASSES) return; 559 560 InstructionAdapter v = new InstructionAdapter(mv); 561 mv.visitCode(); 562 563 Type methodOwner = method.getOwner(); 564 v.load(0, methodOwner); // Load this on stack 565 566 int mask = 0; 567 List<Integer> masks = new ArrayList<Integer>(1); 568 for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) { 569 Type paramType = state.getTypeMapper().mapType(parameterDescriptor.getType()); 570 pushDefaultValueOnStack(paramType, v); 571 int i = parameterDescriptor.getIndex(); 572 if (i != 0 && i % Integer.SIZE == 0) { 573 masks.add(mask); 574 mask = 0; 575 } 576 mask |= (1 << (i % Integer.SIZE)); 577 } 578 masks.add(mask); 579 for (int m : masks) { 580 v.iconst(m); 581 } 582 String desc = JetTypeMapper.getDefaultDescriptor(method.getAsmMethod(), false); 583 v.invokespecial(methodOwner.getInternalName(), "<init>", desc, false); 584 v.areturn(Type.VOID_TYPE); 585 endVisit(mv, "default constructor for " + methodOwner.getInternalName(), classOrObject); 586 } 587 588 void generateDefaultIfNeeded( 589 @NotNull MethodContext owner, 590 @NotNull JvmMethodSignature signature, 591 @NotNull FunctionDescriptor functionDescriptor, 592 @NotNull OwnerKind kind, 593 @NotNull DefaultParameterValueLoader loadStrategy, 594 @Nullable JetNamedFunction function 595 ) { 596 DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration(); 597 598 if (kind != OwnerKind.TRAIT_IMPL && 599 contextClass instanceof ClassDescriptor && 600 ((ClassDescriptor) contextClass).getKind() == ClassKind.TRAIT) { 601 return; 602 } 603 604 if (!isDefaultNeeded(functionDescriptor)) { 605 return; 606 } 607 608 Method jvmSignature = signature.getAsmMethod(); 609 610 int flags = getVisibilityAccessFlag(functionDescriptor) | getDeprecatedAccessFlag(functionDescriptor); 611 612 boolean isConstructor = "<init>".equals(jvmSignature.getName()); 613 614 Method defaultMethod = typeMapper.mapDefaultMethod(functionDescriptor, kind, owner); 615 616 MethodVisitor mv = v.newMethod(Synthetic(function, functionDescriptor), flags | (isConstructor ? 0 : ACC_STATIC), 617 defaultMethod.getName(), 618 defaultMethod.getDescriptor(), null, 619 getThrownExceptions(functionDescriptor, typeMapper)); 620 621 if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 622 if (this.owner instanceof PackageFacadeContext) { 623 mv.visitCode(); 624 generatePackageDelegateMethodBody(mv, defaultMethod, (PackageFacadeContext) this.owner); 625 endVisit(mv, "default method delegation", callableDescriptorToDeclaration(functionDescriptor)); 626 } 627 else { 628 generateDefaultImpl(owner, signature, functionDescriptor, isStaticMethod(kind, functionDescriptor), mv, loadStrategy, function); 629 } 630 } 631 } 632 633 private void generateDefaultImpl( 634 @NotNull MethodContext methodContext, 635 @NotNull JvmMethodSignature signature, 636 @NotNull FunctionDescriptor functionDescriptor, 637 boolean isStatic, 638 @NotNull MethodVisitor mv, 639 @NotNull DefaultParameterValueLoader loadStrategy, 640 @Nullable JetNamedFunction function 641 ) { 642 mv.visitCode(); 643 generateDefaultImplBody(methodContext, signature, functionDescriptor, isStatic, mv, loadStrategy, function, getParentCodegen(), state); 644 endVisit(mv, "default method", callableDescriptorToDeclaration(functionDescriptor)); 645 } 646 647 public static void generateDefaultImplBody( 648 @NotNull MethodContext methodContext, 649 @NotNull JvmMethodSignature signature, 650 @NotNull FunctionDescriptor functionDescriptor, 651 boolean isStatic, 652 @NotNull MethodVisitor mv, 653 @NotNull DefaultParameterValueLoader loadStrategy, 654 @Nullable JetNamedFunction function, 655 @NotNull MemberCodegen<?> parentCodegen, 656 @NotNull GenerationState state 657 ) { 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.VALUE) { 727 frameMap.enterTemp(parameter.getAsmType()); 728 } 729 } 730 731 for (ValueParameterDescriptor parameter : function.getValueParameters()) { 732 frameMap.enter(parameter, state.getTypeMapper().mapType(parameter)); 733 } 734 735 return frameMap; 736 } 737 738 private static void loadExplicitArgumentsOnStack( 739 @NotNull Type ownerType, 740 boolean isStatic, 741 @NotNull JvmMethodSignature signature, 742 @NotNull CallGenerator callGenerator 743 ) { 744 int var = 0; 745 if (!isStatic) { 746 callGenerator.putValueIfNeeded(null, ownerType, StackValue.local(var, ownerType)); 747 var += ownerType.getSize(); 748 } 749 750 for (JvmMethodParameterSignature parameterSignature : signature.getValueParameters()) { 751 if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) { 752 Type type = parameterSignature.getAsmType(); 753 callGenerator.putValueIfNeeded(null, type, StackValue.local(var, type)); 754 var += type.getSize(); 755 } 756 } 757 } 758 759 private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) { 760 boolean needed = false; 761 if (functionDescriptor != null) { 762 for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) { 763 if (parameterDescriptor.declaresDefaultValue()) { 764 needed = true; 765 break; 766 } 767 } 768 } 769 return needed; 770 } 771 772 private static boolean isEmptyConstructorNeeded( 773 @NotNull BindingContext context, 774 @NotNull ConstructorDescriptor constructorDescriptor, 775 @NotNull JetClassOrObject classOrObject 776 ) { 777 ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration(); 778 779 if (classOrObject.isLocal()) return false; 780 781 if (CodegenBinding.canHaveOuter(context, classDescriptor)) return false; 782 783 if (Visibilities.isPrivate(classDescriptor.getVisibility()) || 784 Visibilities.isPrivate(constructorDescriptor.getVisibility())) return false; 785 786 if (constructorDescriptor.getValueParameters().isEmpty()) return false; 787 788 for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) { 789 if (!parameterDescriptor.declaresDefaultValue()) { 790 return false; 791 } 792 } 793 return true; 794 } 795 796 private void generateBridge( 797 @Nullable PsiElement origin, 798 @NotNull FunctionDescriptor descriptor, 799 @NotNull Method bridge, 800 @NotNull Method delegateTo 801 ) { 802 int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO. 803 804 MethodVisitor mv = v.newMethod(OtherOrigin(descriptor), flags, delegateTo.getName(), bridge.getDescriptor(), null, null); 805 if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return; 806 807 mv.visitCode(); 808 809 Type[] argTypes = bridge.getArgumentTypes(); 810 Type[] originalArgTypes = delegateTo.getArgumentTypes(); 811 812 InstructionAdapter iv = new InstructionAdapter(mv); 813 ImplementationBodyCodegen.markLineNumberForSyntheticFunction(owner.getThisDescriptor(), iv); 814 815 iv.load(0, OBJECT_TYPE); 816 for (int i = 0, reg = 1; i < argTypes.length; i++) { 817 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv); 818 //noinspection AssignmentToForLoopParameter 819 reg += argTypes[i].getSize(); 820 } 821 822 iv.invokevirtual(v.getThisName(), delegateTo.getName(), delegateTo.getDescriptor()); 823 824 StackValue.coerce(delegateTo.getReturnType(), bridge.getReturnType(), iv); 825 iv.areturn(bridge.getReturnType()); 826 827 endVisit(mv, "bridge method", origin); 828 } 829 830 public void genDelegate(FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) { 831 genDelegate(functionDescriptor, overriddenDescriptor.getOriginal(), (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field); 832 } 833 834 public void genDelegate( 835 final FunctionDescriptor delegateFunction, 836 final FunctionDescriptor delegatedTo, 837 final ClassDescriptor toClass, 838 final StackValue field 839 ) { 840 final JvmMethodSignature jvmDelegateMethodSignature = typeMapper.mapSignature(delegateFunction); 841 final JvmMethodSignature jvmDelegateToMethodSignature = typeMapper.mapSignature(delegatedTo); 842 generateMethod( 843 OtherOrigin(delegateFunction), jvmDelegateMethodSignature, delegateFunction, 844 new FunctionGenerationStrategy() { 845 @Override 846 public void generateBody( 847 @NotNull MethodVisitor mv, 848 @NotNull FrameMap frameMap, 849 @NotNull JvmMethodSignature signature, 850 @NotNull MethodContext context, 851 @NotNull MemberCodegen<?> parentCodegen 852 ) { 853 Method delegateToMethod = jvmDelegateToMethodSignature.getAsmMethod(); 854 Method delegateMethod = jvmDelegateMethodSignature.getAsmMethod(); 855 856 Type[] argTypes = delegateMethod.getArgumentTypes(); 857 Type[] originalArgTypes = delegateToMethod.getArgumentTypes(); 858 859 InstructionAdapter iv = new InstructionAdapter(mv); 860 iv.load(0, OBJECT_TYPE); 861 field.put(field.type, iv); 862 for (int i = 0, reg = 1; i < argTypes.length; i++) { 863 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv); 864 //noinspection AssignmentToForLoopParameter 865 reg += argTypes[i].getSize(); 866 } 867 868 String internalName = typeMapper.mapType(toClass).getInternalName(); 869 if (toClass.getKind() == ClassKind.TRAIT) { 870 iv.invokeinterface(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor()); 871 } 872 else { 873 iv.invokevirtual(internalName, delegateToMethod.getName(), delegateToMethod.getDescriptor()); 874 } 875 876 StackValue stackValue = AsmUtil.genNotNullAssertions( 877 state, 878 StackValue.onStack(delegateToMethod.getReturnType()), 879 TypesPackage.getApproximationTo( 880 delegatedTo.getReturnType(), 881 delegateFunction.getReturnType(), 882 new Approximation.DataFlowExtras.OnlyMessage(delegatedTo.getName() + "(...)")) 883 ); 884 885 stackValue.put(delegateMethod.getReturnType(), iv); 886 887 iv.areturn(delegateMethod.getReturnType()); 888 } 889 } 890 ); 891 } 892 }