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