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