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