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