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