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