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