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