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