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