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 017 package org.jetbrains.jet.codegen; 018 019 import com.intellij.openapi.progress.ProcessCanceledException; 020 import com.intellij.psi.PsiElement; 021 import org.jetbrains.annotations.NotNull; 022 import org.jetbrains.annotations.Nullable; 023 import org.jetbrains.asm4.AnnotationVisitor; 024 import org.jetbrains.asm4.Label; 025 import org.jetbrains.asm4.MethodVisitor; 026 import org.jetbrains.asm4.Type; 027 import org.jetbrains.asm4.commons.InstructionAdapter; 028 import org.jetbrains.asm4.commons.Method; 029 import org.jetbrains.jet.codegen.binding.CodegenBinding; 030 import org.jetbrains.jet.codegen.context.CodegenContext; 031 import org.jetbrains.jet.codegen.context.MethodContext; 032 import org.jetbrains.jet.codegen.signature.JvmMethodParameterKind; 033 import org.jetbrains.jet.codegen.signature.JvmMethodParameterSignature; 034 import org.jetbrains.jet.codegen.signature.JvmMethodSignature; 035 import org.jetbrains.jet.codegen.signature.JvmPropertyAccessorSignature; 036 import org.jetbrains.jet.codegen.signature.kotlin.JetMethodAnnotationWriter; 037 import org.jetbrains.jet.codegen.signature.kotlin.JetValueParameterAnnotationWriter; 038 import org.jetbrains.jet.codegen.state.GenerationState; 039 import org.jetbrains.jet.codegen.state.GenerationStateAware; 040 import org.jetbrains.jet.codegen.state.JetTypeMapper; 041 import org.jetbrains.jet.codegen.state.JetTypeMapperMode; 042 import org.jetbrains.jet.lang.descriptors.*; 043 import org.jetbrains.jet.lang.psi.JetNamedFunction; 044 import org.jetbrains.jet.lang.resolve.BindingContext; 045 import org.jetbrains.jet.lang.resolve.java.JvmAbi; 046 import org.jetbrains.jet.lang.resolve.java.JvmClassName; 047 import org.jetbrains.jet.lang.resolve.java.JvmStdlibNames; 048 import org.jetbrains.jet.lang.resolve.java.kt.DescriptorKindUtils; 049 import org.jetbrains.jet.lang.resolve.name.Name; 050 051 import java.util.*; 052 053 import static org.jetbrains.asm4.Opcodes.*; 054 import static org.jetbrains.jet.codegen.AsmUtil.*; 055 import static org.jetbrains.jet.codegen.CodegenUtil.*; 056 import static org.jetbrains.jet.codegen.binding.CodegenBinding.isLocalNamedFun; 057 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.callableDescriptorToDeclaration; 058 import static org.jetbrains.jet.lang.resolve.BindingContextUtils.descriptorToDeclaration; 059 import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isFunctionLiteral; 060 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.OBJECT_TYPE; 061 062 public 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 generateMethodParametersAnnotations(mv, functionDescriptor, jvmSignature); 373 } 374 375 void generateMethodParametersAnnotations( 376 MethodVisitor mv, 377 FunctionDescriptor functionDescriptor, 378 JvmMethodSignature jvmSignature 379 ) { 380 Iterator<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters().iterator(); 381 List<JvmMethodParameterSignature> kotlinParameterTypes = jvmSignature.getKotlinParameterTypes(); 382 383 assert kotlinParameterTypes != null; 384 385 for (int i = 0; i < kotlinParameterTypes.size(); i++) { 386 JvmMethodParameterSignature param = kotlinParameterTypes.get(i); 387 JvmMethodParameterKind kind = param.getKind(); 388 String parameterName = "$" + param.getKind().name().toLowerCase(); 389 390 ValueParameterDescriptor parameterDescriptor = null; 391 if (kind == JvmMethodParameterKind.VALUE) { 392 parameterDescriptor = valueParameters.next(); 393 parameterName = parameterDescriptor.getName().asString(); 394 } else if (kind == JvmMethodParameterKind.ENUM_NAME || kind == JvmMethodParameterKind.ENUM_ORDINAL) { 395 //we shouldn't generate annotations for invisible in runtime parameters otherwise we get bad RuntimeInvisibleParameterAnnotations error in javac 396 continue; 397 } else if (needIndexForVar(kind)) { 398 parameterName = parameterName + "$" + i; 399 } 400 401 AnnotationCodegen.forParameter(i, mv, typeMapper).genAnnotations(parameterDescriptor); 402 JetValueParameterAnnotationWriter av = JetValueParameterAnnotationWriter.visitParameterAnnotation(mv, i); 403 av.writeName(parameterName); 404 if (kind == JvmMethodParameterKind.RECEIVER) { 405 av.writeReceiver(); 406 } 407 if (parameterDescriptor != null) { 408 av.writeHasDefaultValue(parameterDescriptor.declaresDefaultValue()); 409 av.writeVararg(parameterDescriptor.getVarargElementType() != null); 410 } 411 av.writeType(param.getKotlinSignature()); 412 av.visitEnd(); 413 } 414 } 415 416 private boolean needIndexForVar(JvmMethodParameterKind kind) { 417 return kind == JvmMethodParameterKind.SHARED_VAR || kind == JvmMethodParameterKind.SUPER_CALL_PARAM; 418 } 419 420 public static void endVisit(MethodVisitor mv, @Nullable String description, @Nullable PsiElement method) { 421 try { 422 mv.visitMaxs(-1, -1); 423 } 424 catch (ProcessCanceledException e) { 425 throw e; 426 } 427 catch (Throwable t) { 428 throw new CompilationException( 429 "wrong code generated" + 430 (description != null ? " for " + description : "") + 431 t.getClass().getName() + 432 " " + 433 t.getMessage(), 434 t, method); 435 } 436 mv.visitEnd(); 437 } 438 439 static void generateBridgeIfNeeded( 440 CodegenContext owner, 441 GenerationState state, 442 ClassBuilder v, 443 Method jvmSignature, 444 FunctionDescriptor functionDescriptor 445 ) { 446 if (owner.getContextKind() == OwnerKind.TRAIT_IMPL) { 447 return; 448 } 449 450 Method method = 451 state.getTypeMapper().mapSignature(functionDescriptor).getAsmMethod(); 452 453 Queue<FunctionDescriptor> bfsQueue = new LinkedList<FunctionDescriptor>(); 454 Set<FunctionDescriptor> visited = new HashSet<FunctionDescriptor>(); 455 456 bfsQueue.offer(functionDescriptor.getOriginal()); 457 visited.add(functionDescriptor.getOriginal()); 458 for (FunctionDescriptor overriddenDescriptor : functionDescriptor.getOverriddenDescriptors()) { 459 FunctionDescriptor orig = overriddenDescriptor.getOriginal(); 460 if (!visited.contains(orig)) { 461 bfsQueue.offer(overriddenDescriptor); 462 visited.add(overriddenDescriptor); 463 } 464 } 465 466 Set<Method> bridgesToGenerate = new HashSet<Method>(); 467 while (!bfsQueue.isEmpty()) { 468 FunctionDescriptor descriptor = bfsQueue.poll(); 469 if (descriptor.getKind() == CallableMemberDescriptor.Kind.DECLARATION) { 470 Method overridden = 471 state.getTypeMapper().mapSignature(descriptor.getOriginal()).getAsmMethod(); 472 if (differentMethods(method, overridden)) { 473 bridgesToGenerate.add(overridden); 474 } 475 continue; 476 } 477 478 for (FunctionDescriptor overriddenDescriptor : descriptor.getOverriddenDescriptors()) { 479 FunctionDescriptor orig = overriddenDescriptor.getOriginal(); 480 if (!visited.contains(orig)) { 481 bfsQueue.offer(orig); 482 visited.add(orig); 483 } 484 } 485 } 486 487 for (Method overridden : bridgesToGenerate) { 488 generateBridge(owner, state, v, jvmSignature, functionDescriptor, overridden); 489 } 490 } 491 492 static void generateConstructorWithoutParametersIfNeeded( 493 @NotNull GenerationState state, 494 @NotNull CallableMethod method, 495 @NotNull ConstructorDescriptor constructorDescriptor, 496 @NotNull ClassBuilder classBuilder 497 ) { 498 if (!isDefaultConstructorNeeded(state.getBindingContext(), constructorDescriptor)) { 499 return; 500 } 501 int flags = getVisibilityAccessFlag(constructorDescriptor); 502 MethodVisitor mv = classBuilder.newMethod(null, flags, "<init>", "()V", null, null); 503 504 if (state.getClassBuilderMode() == ClassBuilderMode.SIGNATURES) { 505 return; 506 } 507 else if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { 508 genStubCode(mv); 509 } 510 else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 511 InstructionAdapter v = new InstructionAdapter(mv); 512 mv.visitCode(); 513 514 JvmClassName ownerInternalName = method.getOwner(); 515 Method jvmSignature = method.getSignature().getAsmMethod(); 516 v.load(0, ownerInternalName.getAsmType()); // Load this on stack 517 518 int mask = 0; 519 for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) { 520 Type paramType = state.getTypeMapper().mapType(parameterDescriptor.getType()); 521 pushDefaultValueOnStack(paramType, v); 522 mask |= (1 << parameterDescriptor.getIndex()); 523 } 524 v.iconst(mask); 525 String desc = jvmSignature.getDescriptor().replace(")", "I)"); 526 v.invokespecial(ownerInternalName.getInternalName(), "<init>", desc); 527 v.areturn(Type.VOID_TYPE); 528 endVisit(mv, "default constructor for " + ownerInternalName.getInternalName(), null); 529 } 530 } 531 532 static void generateDefaultIfNeeded( 533 @NotNull MethodContext owner, 534 @NotNull GenerationState state, 535 @NotNull ClassBuilder v, 536 @NotNull JvmMethodSignature signature, 537 @NotNull FunctionDescriptor functionDescriptor, 538 @NotNull OwnerKind kind, 539 @NotNull DefaultParameterValueLoader loadStrategy 540 ) { 541 DeclarationDescriptor contextClass = owner.getContextDescriptor().getContainingDeclaration(); 542 543 if (kind != OwnerKind.TRAIT_IMPL && 544 contextClass instanceof ClassDescriptor && 545 ((ClassDescriptor) contextClass).getKind() == ClassKind.TRAIT) { 546 return; 547 } 548 549 if (!isDefaultNeeded(functionDescriptor)) { 550 return; 551 } 552 553 boolean isStatic = isStatic(kind); 554 555 Method jvmSignature = signature.getAsmMethod(); 556 557 int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO. 558 559 JvmClassName ownerInternalName; 560 if (contextClass instanceof NamespaceDescriptor) { 561 ownerInternalName = state.getTypeMapper().getOwner(functionDescriptor, kind, true); 562 } 563 else { 564 ownerInternalName = JvmClassName.byType(state.getTypeMapper() 565 .mapType(((ClassDescriptor) contextClass).getDefaultType(), 566 JetTypeMapperMode.IMPL)); 567 } 568 569 String descriptor = jvmSignature.getDescriptor().replace(")", "I)"); 570 boolean isConstructor = "<init>".equals(jvmSignature.getName()); 571 if (!isStatic && !isConstructor) { 572 descriptor = descriptor.replace("(", "(" + ownerInternalName.getDescriptor()); 573 } 574 MethodVisitor mv = v.newMethod(null, flags | (isConstructor ? 0 : ACC_STATIC), 575 isConstructor ? "<init>" : jvmSignature.getName() + JvmAbi.DEFAULT_PARAMS_IMPL_SUFFIX, 576 descriptor, null, null); 577 578 if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { 579 genStubCode(mv); 580 } 581 else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 582 generateDefaultImpl(owner, state, signature, functionDescriptor, kind, isStatic, mv, loadStrategy); 583 } 584 } 585 586 private static void generateDefaultImpl( 587 @NotNull MethodContext methodContext, 588 @NotNull GenerationState state, 589 @NotNull JvmMethodSignature signature, 590 @NotNull FunctionDescriptor functionDescriptor, 591 @NotNull OwnerKind kind, 592 boolean aStatic, 593 @NotNull MethodVisitor mv, 594 @NotNull DefaultParameterValueLoader loadStrategy 595 ) { 596 mv.visitCode(); 597 598 FrameMap frameMap = new FrameMap(); 599 600 if (!aStatic) { 601 frameMap.enterTemp(OBJECT_TYPE); 602 } 603 604 Method jvmSignature = signature.getAsmMethod(); 605 ExpressionCodegen codegen = new ExpressionCodegen(mv, frameMap, jvmSignature.getReturnType(), methodContext, state); 606 607 Type[] argTypes = jvmSignature.getArgumentTypes(); 608 List<ValueParameterDescriptor> paramDescrs = functionDescriptor.getValueParameters(); 609 Iterator<ValueParameterDescriptor> iterator = paramDescrs.iterator(); 610 611 int countOfExtraVarsInMethodArgs = 0; 612 List<JvmMethodParameterSignature> params = signature.getKotlinParameterTypes(); 613 614 for (int i = 0; i < params.size(); i++) { 615 JvmMethodParameterSignature parameterSignature = params.get(i); 616 if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) { 617 countOfExtraVarsInMethodArgs++; 618 frameMap.enterTemp(parameterSignature.getAsmType()); 619 } else { 620 frameMap.enter(iterator.next(), parameterSignature.getAsmType()); 621 } 622 } 623 624 int maskIndex = frameMap.enterTemp(Type.INT_TYPE); 625 626 InstructionAdapter iv = new InstructionAdapter(mv); 627 loadExplicitArgumentsOnStack(iv, OBJECT_TYPE, aStatic, signature); 628 629 for (int index = 0; index < paramDescrs.size(); index++) { 630 ValueParameterDescriptor parameterDescriptor = paramDescrs.get(index); 631 632 Type t = argTypes[countOfExtraVarsInMethodArgs + index]; 633 634 if (parameterDescriptor.declaresDefaultValue()) { 635 iv.load(maskIndex, Type.INT_TYPE); 636 iv.iconst(1 << index); 637 iv.and(Type.INT_TYPE); 638 Label loadArg = new Label(); 639 iv.ifeq(loadArg); 640 641 loadStrategy.putValueOnStack(parameterDescriptor, codegen); 642 643 int ind = frameMap.getIndex(parameterDescriptor); 644 iv.store(ind, t); 645 646 iv.mark(loadArg); 647 } 648 649 iv.load(frameMap.getIndex(parameterDescriptor), t); 650 } 651 652 CallableMethod method = null; 653 if (functionDescriptor instanceof ConstructorDescriptor) { 654 method = state.getTypeMapper().mapToCallableMethod((ConstructorDescriptor) functionDescriptor); 655 } else { 656 method = state.getTypeMapper() 657 .mapToCallableMethod(functionDescriptor, false, isCallInsideSameClassAsDeclared(functionDescriptor, methodContext), 658 isCallInsideSameModuleAsDeclared(functionDescriptor, methodContext), OwnerKind.IMPLEMENTATION); 659 } 660 661 iv.visitMethodInsn(method.getInvokeOpcode(), method.getOwner().getInternalName(), method.getSignature().getAsmMethod().getName(), 662 method.getSignature().getAsmMethod().getDescriptor()); 663 664 iv.areturn(jvmSignature.getReturnType()); 665 666 endVisit(mv, "default method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor)); 667 mv.visitEnd(); 668 } 669 670 671 private static void loadExplicitArgumentsOnStack( 672 @NotNull InstructionAdapter iv, 673 @NotNull Type ownerType, 674 boolean isStatic, 675 @NotNull JvmMethodSignature signature 676 ) { 677 int var = 0; 678 if (!isStatic) { 679 iv.load(var, ownerType); 680 var += ownerType.getSize(); 681 } 682 683 List<JvmMethodParameterSignature> params = signature.getKotlinParameterTypes(); 684 for (int i = 0; i < params.size(); i++) { 685 JvmMethodParameterSignature parameterSignature = params.get(i); 686 if (parameterSignature.getKind() != JvmMethodParameterKind.VALUE) { 687 Type type = parameterSignature.getAsmType(); 688 iv.load(var, type); 689 var += type.getSize(); 690 } 691 } 692 } 693 694 private static boolean isDefaultNeeded(FunctionDescriptor functionDescriptor) { 695 boolean needed = false; 696 if (functionDescriptor != null) { 697 for (ValueParameterDescriptor parameterDescriptor : functionDescriptor.getValueParameters()) { 698 if (parameterDescriptor.declaresDefaultValue()) { 699 needed = true; 700 break; 701 } 702 } 703 } 704 return needed; 705 } 706 707 private static boolean isDefaultConstructorNeeded(@NotNull BindingContext context, @NotNull ConstructorDescriptor constructorDescriptor) { 708 ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration(); 709 710 if (CodegenBinding.canHaveOuter(context, classDescriptor)) return false; 711 712 if (classDescriptor.getVisibility() == Visibilities.PRIVATE || 713 constructorDescriptor.getVisibility() == Visibilities.PRIVATE) return false; 714 715 if (constructorDescriptor.getValueParameters().isEmpty()) return false; 716 717 for (ValueParameterDescriptor parameterDescriptor : constructorDescriptor.getValueParameters()) { 718 if (!parameterDescriptor.declaresDefaultValue()) { 719 return false; 720 } 721 } 722 return true; 723 } 724 725 private static boolean differentMethods(Method method, Method overridden) { 726 if (!method.getReturnType().equals(overridden.getReturnType())) { 727 return true; 728 } 729 Type[] methodArgumentTypes = method.getArgumentTypes(); 730 Type[] overriddenArgumentTypes = overridden.getArgumentTypes(); 731 if (methodArgumentTypes.length != overriddenArgumentTypes.length) { 732 return true; 733 } 734 for (int i = 0; i != methodArgumentTypes.length; ++i) { 735 if (!methodArgumentTypes[i].equals(overriddenArgumentTypes[i])) { 736 return true; 737 } 738 } 739 return false; 740 } 741 742 private static void generateBridge( 743 CodegenContext owner, 744 GenerationState state, 745 ClassBuilder v, 746 Method jvmSignature, 747 FunctionDescriptor functionDescriptor, 748 Method overridden 749 ) { 750 int flags = ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC; // TODO. 751 752 MethodVisitor mv = v.newMethod(null, flags, jvmSignature.getName(), overridden.getDescriptor(), null, null); 753 if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { 754 genStubCode(mv); 755 } 756 else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 757 mv.visitCode(); 758 759 Type[] argTypes = overridden.getArgumentTypes(); 760 Type[] originalArgTypes = jvmSignature.getArgumentTypes(); 761 762 InstructionAdapter iv = new InstructionAdapter(mv); 763 iv.load(0, OBJECT_TYPE); 764 for (int i = 0, reg = 1; i < argTypes.length; i++) { 765 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv); 766 //noinspection AssignmentToForLoopParameter 767 reg += argTypes[i].getSize(); 768 } 769 770 iv.invokevirtual(v.getThisName(), jvmSignature.getName(), jvmSignature.getDescriptor()); 771 772 StackValue.onStack(jvmSignature.getReturnType()).put(overridden.getReturnType(), iv); 773 774 iv.areturn(overridden.getReturnType()); 775 endVisit(mv, "bridge method", callableDescriptorToDeclaration(state.getBindingContext(), functionDescriptor)); 776 } 777 } 778 779 public void genDelegate(FunctionDescriptor functionDescriptor, FunctionDescriptor overriddenDescriptor, StackValue field) { 780 genDelegate(functionDescriptor, (ClassDescriptor) overriddenDescriptor.getContainingDeclaration(), field, 781 typeMapper.mapSignature(functionDescriptor), 782 typeMapper.mapSignature(overriddenDescriptor.getOriginal()) 783 ); 784 } 785 786 public void genDelegate( 787 FunctionDescriptor functionDescriptor, 788 ClassDescriptor toClass, 789 StackValue field, 790 JvmMethodSignature jvmDelegateMethodSignature, 791 JvmMethodSignature jvmOverriddenMethodSignature 792 ) { 793 Method overriddenMethod = jvmOverriddenMethodSignature.getAsmMethod(); 794 Method delegateMethod = jvmDelegateMethodSignature.getAsmMethod(); 795 796 int flags = ACC_PUBLIC | ACC_SYNTHETIC; // TODO. 797 798 MethodVisitor mv = v.newMethod(null, flags, delegateMethod.getName(), delegateMethod.getDescriptor(), null, null); 799 if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { 800 genStubCode(mv); 801 } 802 else if (state.getClassBuilderMode() == ClassBuilderMode.FULL) { 803 mv.visitCode(); 804 805 Type[] argTypes = delegateMethod.getArgumentTypes(); 806 Type[] originalArgTypes = overriddenMethod.getArgumentTypes(); 807 808 InstructionAdapter iv = new InstructionAdapter(mv); 809 iv.load(0, OBJECT_TYPE); 810 field.put(field.type, iv); 811 for (int i = 0, reg = 1; i < argTypes.length; i++) { 812 StackValue.local(reg, argTypes[i]).put(originalArgTypes[i], iv); 813 //noinspection AssignmentToForLoopParameter 814 reg += argTypes[i].getSize(); 815 } 816 817 String internalName = typeMapper.mapType(toClass).getInternalName(); 818 if (toClass.getKind() == ClassKind.TRAIT) { 819 iv.invokeinterface(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor()); 820 } 821 else { 822 iv.invokevirtual(internalName, overriddenMethod.getName(), overriddenMethod.getDescriptor()); 823 } 824 825 StackValue.onStack(overriddenMethod.getReturnType()).put(delegateMethod.getReturnType(), iv); 826 827 iv.areturn(delegateMethod.getReturnType()); 828 endVisit(mv, "Delegate method " + functionDescriptor + " to " + jvmOverriddenMethodSignature, 829 descriptorToDeclaration(bindingContext, functionDescriptor.getContainingDeclaration())); 830 831 generateBridgeIfNeeded(owner, state, v, jvmDelegateMethodSignature.getAsmMethod(), functionDescriptor); 832 } 833 } 834 }