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