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