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