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