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