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