001 /* 002 * Copyright 2010-2013 JetBrains s.r.o. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package org.jetbrains.jet.codegen; 018 019 import com.intellij.psi.tree.IElementType; 020 import org.jetbrains.annotations.NotNull; 021 import org.jetbrains.annotations.Nullable; 022 import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod; 023 import org.jetbrains.jet.codegen.state.GenerationState; 024 import org.jetbrains.jet.codegen.state.JetTypeMapper; 025 import org.jetbrains.jet.lang.descriptors.*; 026 import org.jetbrains.jet.lang.psi.JetExpression; 027 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 028 import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; 029 import org.jetbrains.jet.lexer.JetTokens; 030 import org.jetbrains.org.objectweb.asm.Label; 031 import org.jetbrains.org.objectweb.asm.Type; 032 import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; 033 import org.jetbrains.org.objectweb.asm.commons.Method; 034 035 import java.util.List; 036 037 import static org.jetbrains.jet.codegen.AsmUtil.*; 038 import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*; 039 import static org.jetbrains.org.objectweb.asm.Opcodes.*; 040 041 public abstract class StackValue { 042 043 private static final String NULLABLE_BYTE_TYPE_NAME = "java/lang/Byte"; 044 private static final String NULLABLE_SHORT_TYPE_NAME = "java/lang/Short"; 045 private static final String NULLABLE_LONG_TYPE_NAME = "java/lang/Long"; 046 047 @NotNull 048 public final Type type; 049 050 protected StackValue(@NotNull Type type) { 051 this.type = type; 052 } 053 054 /** 055 * Put this value to the top of the stack. 056 */ 057 public abstract void put(Type type, InstructionAdapter v); 058 059 /** 060 * This method is called to put the value on the top of the JVM stack if <code>depth</code> other values have been put on the 061 * JVM stack after this value was generated. 062 * 063 * @param type the type as which the value should be put 064 * @param v the visitor used to genClassOrObject the instructions 065 * @param depth the number of new values put onto the stack 066 */ 067 protected void moveToTopOfStack(Type type, InstructionAdapter v, int depth) { 068 put(type, v); 069 } 070 071 /** 072 * Set this value from the top of the stack. 073 */ 074 public void store(Type topOfStackType, InstructionAdapter v) { 075 throw new UnsupportedOperationException("cannot store to value " + this); 076 } 077 078 public void dupReceiver(InstructionAdapter v) { 079 } 080 081 public int receiverSize() { 082 return 0; 083 } 084 085 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { 086 put(this.type, v); 087 coerceTo(Type.BOOLEAN_TYPE, v); 088 if (jumpIfFalse) { 089 v.ifeq(label); 090 } 091 else { 092 v.ifne(label); 093 } 094 } 095 096 public static Local local(int index, Type type) { 097 return new Local(index, type); 098 } 099 100 public static StackValue shared(int index, Type type) { 101 return new Shared(index, type); 102 } 103 104 public static StackValue onStack(Type type) { 105 return type == Type.VOID_TYPE ? none() : new OnStack(type); 106 } 107 108 public static StackValue constant(@Nullable Object value, Type type) { 109 return new Constant(value, type); 110 } 111 112 public static StackValue cmp(IElementType opToken, Type type) { 113 return type.getSort() == Type.OBJECT ? new ObjectCompare(opToken, type) : new NumberCompare(opToken, type); 114 } 115 116 public static StackValue not(StackValue stackValue) { 117 return new Invert(stackValue); 118 } 119 120 @NotNull 121 public static StackValue arrayElement(Type type) { 122 return new ArrayElement(type); 123 } 124 125 @NotNull 126 public static StackValue collectionElement( 127 Type type, 128 ResolvedCall<FunctionDescriptor> getter, 129 ResolvedCall<FunctionDescriptor> setter, 130 ExpressionCodegen codegen, 131 GenerationState state 132 ) { 133 return new CollectionElement(type, getter, setter, codegen, state); 134 } 135 136 @NotNull 137 public static Field field(@NotNull Type type, @NotNull Type owner, @NotNull String name, boolean isStatic) { 138 return new Field(type, owner, name, isStatic); 139 } 140 141 @NotNull 142 public static Property property( 143 @NotNull PropertyDescriptor descriptor, 144 @NotNull Type methodOwner, 145 @NotNull Type type, 146 boolean isStatic, 147 @Nullable String fieldName, 148 @Nullable CallableMethod getter, 149 @Nullable CallableMethod setter, 150 GenerationState state 151 ) { 152 return new Property(descriptor, methodOwner, getter, setter, isStatic, fieldName, type, state); 153 } 154 155 @NotNull 156 public static StackValue expression(Type type, JetExpression expression, ExpressionCodegen generator) { 157 return new Expression(type, expression, generator); 158 } 159 160 private static void box(Type type, Type toType, InstructionAdapter v) { 161 if (type == Type.BYTE_TYPE || toType.getInternalName().equals(NULLABLE_BYTE_TYPE_NAME) && type == Type.INT_TYPE) { 162 v.cast(type, Type.BYTE_TYPE); 163 v.invokestatic(NULLABLE_BYTE_TYPE_NAME, "valueOf", "(B)L" + NULLABLE_BYTE_TYPE_NAME + ";"); 164 } 165 else if (type == Type.SHORT_TYPE || toType.getInternalName().equals(NULLABLE_SHORT_TYPE_NAME) && type == Type.INT_TYPE) { 166 v.cast(type, Type.SHORT_TYPE); 167 v.invokestatic(NULLABLE_SHORT_TYPE_NAME, "valueOf", "(S)L" + NULLABLE_SHORT_TYPE_NAME + ";"); 168 } 169 else if (type == Type.LONG_TYPE || toType.getInternalName().equals(NULLABLE_LONG_TYPE_NAME) && type == Type.INT_TYPE) { 170 v.cast(type, Type.LONG_TYPE); 171 v.invokestatic(NULLABLE_LONG_TYPE_NAME, "valueOf", "(J)L" + NULLABLE_LONG_TYPE_NAME +";"); 172 } 173 else if (type == Type.INT_TYPE) { 174 v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;"); 175 } 176 else if (type == Type.BOOLEAN_TYPE) { 177 v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;"); 178 } 179 else if (type == Type.CHAR_TYPE) { 180 v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;"); 181 } 182 else if (type == Type.FLOAT_TYPE) { 183 v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;"); 184 } 185 else if (type == Type.DOUBLE_TYPE) { 186 v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;"); 187 } 188 } 189 190 private static void unbox(Type type, InstructionAdapter v) { 191 if (type == Type.INT_TYPE) { 192 v.invokevirtual("java/lang/Number", "intValue", "()I"); 193 } 194 else if (type == Type.BOOLEAN_TYPE) { 195 v.invokevirtual("java/lang/Boolean", "booleanValue", "()Z"); 196 } 197 else if (type == Type.CHAR_TYPE) { 198 v.invokevirtual("java/lang/Character", "charValue", "()C"); 199 } 200 else if (type == Type.SHORT_TYPE) { 201 v.invokevirtual("java/lang/Number", "shortValue", "()S"); 202 } 203 else if (type == Type.LONG_TYPE) { 204 v.invokevirtual("java/lang/Number", "longValue", "()J"); 205 } 206 else if (type == Type.BYTE_TYPE) { 207 v.invokevirtual("java/lang/Number", "byteValue", "()B"); 208 } 209 else if (type == Type.FLOAT_TYPE) { 210 v.invokevirtual("java/lang/Number", "floatValue", "()F"); 211 } 212 else if (type == Type.DOUBLE_TYPE) { 213 v.invokevirtual("java/lang/Number", "doubleValue", "()D"); 214 } 215 } 216 217 protected void coerceTo(Type toType, InstructionAdapter v) { 218 coerce(this.type, toType, v); 219 } 220 221 protected void coerceFrom(Type topOfStackType, InstructionAdapter v) { 222 coerce(topOfStackType, this.type, v); 223 } 224 225 public static void coerce(Type fromType, Type toType, InstructionAdapter v) { 226 if (toType.equals(fromType)) return; 227 228 if (toType.getSort() == Type.VOID) { 229 pop(v, fromType); 230 } 231 else if (fromType.getSort() == Type.VOID) { 232 if (toType.equals(UNIT_TYPE) || toType.equals(OBJECT_TYPE)) { 233 putUnitInstance(v); 234 } 235 else if (toType.getSort() == Type.OBJECT || toType.getSort() == Type.ARRAY) { 236 v.aconst(null); 237 } 238 else { 239 pushDefaultPrimitiveValueOnStack(toType, v); 240 } 241 } 242 else if (toType.equals(UNIT_TYPE)) { 243 if (fromType.equals(getType(Object.class))) { 244 v.checkcast(UNIT_TYPE); 245 } 246 else if (!fromType.equals(getType(Void.class))) { 247 pop(v, fromType); 248 putUnitInstance(v); 249 } 250 } 251 else if (toType.getSort() == Type.ARRAY) { 252 v.checkcast(toType); 253 } 254 else if (toType.getSort() == Type.OBJECT) { 255 if (fromType.getSort() == Type.OBJECT || fromType.getSort() == Type.ARRAY) { 256 if (!toType.equals(OBJECT_TYPE)) { 257 v.checkcast(toType); 258 } 259 } 260 else { 261 box(fromType, toType, v); 262 } 263 } 264 else if (fromType.getSort() == Type.OBJECT) { 265 if (fromType.equals(getType(Boolean.class)) || fromType.equals(getType(Character.class))) { 266 unbox(unboxType(fromType), v); 267 coerce(unboxType(fromType), toType, v); 268 } 269 else { 270 if (toType.getSort() == Type.BOOLEAN || toType.getSort() == Type.CHAR) { 271 coerce(fromType, boxType(toType), v); 272 } 273 else { 274 coerce(fromType, getType(Number.class), v); 275 } 276 unbox(toType, v); 277 } 278 } 279 else { 280 v.cast(fromType, toType); 281 } 282 } 283 284 public static void putUnitInstance(InstructionAdapter v) { 285 v.visitFieldInsn(GETSTATIC, UNIT_TYPE.getInternalName(), "VALUE", UNIT_TYPE.getDescriptor()); 286 } 287 288 protected void putAsBoolean(InstructionAdapter v) { 289 Label ifTrue = new Label(); 290 Label end = new Label(); 291 condJump(ifTrue, false, v); 292 v.iconst(0); 293 v.goTo(end); 294 v.mark(ifTrue); 295 v.iconst(1); 296 v.mark(end); 297 } 298 299 public static StackValue none() { 300 return None.INSTANCE; 301 } 302 303 public static StackValue fieldForSharedVar(Type localType, Type classType, String fieldName) { 304 return new FieldForSharedVar(localType, classType, fieldName); 305 } 306 307 public static StackValue composed(StackValue prefix, StackValue suffix) { 308 return new Composed(prefix, suffix); 309 } 310 311 public static StackValue thisOrOuter(ExpressionCodegen codegen, ClassDescriptor descriptor, boolean isSuper, boolean isExplicit) { 312 // Coerce this/super for traits to support traits with required classes. 313 // Coerce explicit 'this' for the case when it is smartcasted. 314 // Do not coerce for other classes due to the 'protected' access issues (JVMS 7, 4.9.2 Structural Constraints). 315 boolean coerceType = descriptor.getKind() == ClassKind.TRAIT || (isExplicit && !isSuper); 316 return new ThisOuter(codegen, descriptor, isSuper, coerceType); 317 } 318 319 public static StackValue postIncrement(int index, int increment) { 320 return new PostIncrement(index, increment); 321 } 322 323 public static StackValue preIncrement(int index, int increment) { 324 return new PreIncrement(index, increment); 325 } 326 327 public static StackValue receiver( 328 ResolvedCall<?> resolvedCall, 329 StackValue receiver, 330 ExpressionCodegen codegen, 331 @Nullable CallableMethod callableMethod 332 ) { 333 if (resolvedCall.getThisObject().exists() || resolvedCall.getReceiverArgument().exists() || isLocalFunCall(callableMethod)) { 334 return new CallReceiver(resolvedCall, receiver, codegen, callableMethod, true); 335 } 336 return receiver; 337 } 338 339 private static boolean isLocalFunCall(@Nullable CallableMethod callableMethod) { 340 return callableMethod != null && callableMethod.getGenerateCalleeType() != null; 341 } 342 343 public static StackValue receiverWithoutReceiverArgument(StackValue receiverWithParameter) { 344 if (receiverWithParameter instanceof CallReceiver) { 345 CallReceiver callReceiver = (CallReceiver) receiverWithParameter; 346 return new CallReceiver(callReceiver.resolvedCall, callReceiver.receiver, 347 callReceiver.codegen, callReceiver.callableMethod, false); 348 } 349 return receiverWithParameter; 350 } 351 352 public static Field singleton(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) { 353 FieldInfo info = FieldInfo.createForSingleton(classDescriptor, typeMapper); 354 return field(info.getFieldType(), Type.getObjectType(info.getOwnerInternalName()), info.getFieldName(), true); 355 } 356 357 private static class None extends StackValue { 358 public static final None INSTANCE = new None(); 359 360 private None() { 361 super(Type.VOID_TYPE); 362 } 363 364 @Override 365 public void put(Type type, InstructionAdapter v) { 366 coerceTo(type, v); 367 } 368 } 369 370 public static class Local extends StackValue { 371 public final int index; 372 373 private Local(int index, Type type) { 374 super(type); 375 this.index = index; 376 377 if (index < 0) { 378 throw new IllegalStateException("local variable index must be non-negative"); 379 } 380 } 381 382 @Override 383 public void put(Type type, InstructionAdapter v) { 384 v.load(index, this.type); 385 coerceTo(type, v); 386 // TODO unbox 387 } 388 389 @Override 390 public void store(Type topOfStackType, InstructionAdapter v) { 391 coerceFrom(topOfStackType, v); 392 v.store(index, this.type); 393 } 394 } 395 396 public static class OnStack extends StackValue { 397 public OnStack(Type type) { 398 super(type); 399 } 400 401 @Override 402 public void put(Type type, InstructionAdapter v) { 403 coerceTo(type, v); 404 } 405 406 @Override 407 public void moveToTopOfStack(Type type, InstructionAdapter v, int depth) { 408 if (depth == 0) { 409 put(type, v); 410 } 411 else if (depth == 1) { 412 if (type.getSize() != 1) { 413 throw new UnsupportedOperationException("don't know how to move type " + type + " to top of stack"); 414 } 415 v.swap(); 416 } 417 else { 418 throw new UnsupportedOperationException("unsupported move-to-top depth " + depth); 419 } 420 } 421 } 422 423 public static class Constant extends StackValue { 424 @Nullable 425 private final Object value; 426 427 public Constant(@Nullable Object value, Type type) { 428 super(type); 429 this.value = value; 430 } 431 432 @Override 433 public void put(Type type, InstructionAdapter v) { 434 if (value instanceof Integer) { 435 v.iconst((Integer) value); 436 } 437 else if (value instanceof Long) { 438 v.lconst((Long) value); 439 } 440 else if (value instanceof Float) { 441 v.fconst((Float) value); 442 } 443 else if (value instanceof Double) { 444 v.dconst((Double) value); 445 } 446 else { 447 v.aconst(value); 448 } 449 450 coerceTo(type, v); 451 } 452 453 @Override 454 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { 455 if (value instanceof Boolean) { 456 boolean boolValue = (Boolean) value; 457 if (boolValue ^ jumpIfFalse) { 458 v.goTo(label); 459 } 460 } 461 else { 462 throw new UnsupportedOperationException("don't know how to generate this condjump"); 463 } 464 } 465 } 466 467 private static class NumberCompare extends StackValue { 468 protected final IElementType opToken; 469 private final Type operandType; 470 471 public NumberCompare(IElementType opToken, Type operandType) { 472 super(Type.BOOLEAN_TYPE); 473 this.opToken = opToken; 474 this.operandType = operandType; 475 } 476 477 @Override 478 public void put(Type type, InstructionAdapter v) { 479 putAsBoolean(v); 480 coerceTo(type, v); 481 } 482 483 @Override 484 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { 485 int opcode; 486 if (opToken == JetTokens.EQEQ) { 487 opcode = jumpIfFalse ? IFNE : IFEQ; 488 } 489 else if (opToken == JetTokens.EXCLEQ) { 490 opcode = jumpIfFalse ? IFEQ : IFNE; 491 } 492 else if (opToken == JetTokens.GT) { 493 opcode = jumpIfFalse ? IFLE : IFGT; 494 } 495 else if (opToken == JetTokens.GTEQ) { 496 opcode = jumpIfFalse ? IFLT : IFGE; 497 } 498 else if (opToken == JetTokens.LT) { 499 opcode = jumpIfFalse ? IFGE : IFLT; 500 } 501 else if (opToken == JetTokens.LTEQ) { 502 opcode = jumpIfFalse ? IFGT : IFLE; 503 } 504 else { 505 throw new UnsupportedOperationException("don't know how to generate this condjump"); 506 } 507 if (operandType == Type.FLOAT_TYPE || operandType == Type.DOUBLE_TYPE) { 508 if (opToken == JetTokens.GT || opToken == JetTokens.GTEQ) { 509 v.cmpl(operandType); 510 } 511 else { 512 v.cmpg(operandType); 513 } 514 } 515 else if (operandType == Type.LONG_TYPE) { 516 v.lcmp(); 517 } 518 else { 519 opcode += (IF_ICMPEQ - IFEQ); 520 } 521 v.visitJumpInsn(opcode, label); 522 } 523 } 524 525 private static class ObjectCompare extends NumberCompare { 526 public ObjectCompare(IElementType opToken, Type operandType) { 527 super(opToken, operandType); 528 } 529 530 @Override 531 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { 532 int opcode; 533 if (opToken == JetTokens.EQEQEQ) { 534 opcode = jumpIfFalse ? IF_ACMPNE : IF_ACMPEQ; 535 } 536 else if (opToken == JetTokens.EXCLEQEQEQ) { 537 opcode = jumpIfFalse ? IF_ACMPEQ : IF_ACMPNE; 538 } 539 else { 540 throw new UnsupportedOperationException("don't know how to generate this condjump"); 541 } 542 v.visitJumpInsn(opcode, label); 543 } 544 } 545 546 private static class Invert extends StackValue { 547 private final StackValue myOperand; 548 549 private Invert(StackValue operand) { 550 super(Type.BOOLEAN_TYPE); 551 myOperand = operand; 552 if (myOperand.type != Type.BOOLEAN_TYPE) { 553 throw new UnsupportedOperationException("operand of ! must be boolean"); 554 } 555 } 556 557 @Override 558 public void put(Type type, InstructionAdapter v) { 559 putAsBoolean(v); 560 coerceTo(type, v); 561 } 562 563 @Override 564 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { 565 myOperand.condJump(label, !jumpIfFalse, v); 566 } 567 } 568 569 private static class ArrayElement extends StackValue { 570 public ArrayElement(Type type) { 571 super(type); 572 } 573 574 @Override 575 public void put(Type type, InstructionAdapter v) { 576 v.aload(this.type); // assumes array and index are on the stack 577 coerceTo(type, v); 578 } 579 580 @Override 581 public void store(Type topOfStackType, InstructionAdapter v) { 582 coerceFrom(topOfStackType, v); 583 v.astore(this.type); 584 } 585 586 @Override 587 public void dupReceiver(InstructionAdapter v) { 588 v.dup2(); // array and index 589 } 590 591 @Override 592 public int receiverSize() { 593 return 2; 594 } 595 } 596 597 private static class CollectionElement extends StackValue { 598 private final Callable getter; 599 private final Callable setter; 600 private final ExpressionCodegen codegen; 601 private final GenerationState state; 602 private final FrameMap frame; 603 private final ResolvedCall<FunctionDescriptor> resolvedGetCall; 604 private final ResolvedCall<FunctionDescriptor> resolvedSetCall; 605 private final FunctionDescriptor setterDescriptor; 606 private final FunctionDescriptor getterDescriptor; 607 608 public CollectionElement( 609 Type type, 610 ResolvedCall<FunctionDescriptor> resolvedGetCall, 611 ResolvedCall<FunctionDescriptor> resolvedSetCall, 612 ExpressionCodegen codegen, 613 GenerationState state 614 ) { 615 super(type); 616 this.resolvedGetCall = resolvedGetCall; 617 this.resolvedSetCall = resolvedSetCall; 618 this.state = state; 619 this.setterDescriptor = resolvedSetCall == null ? null : resolvedSetCall.getResultingDescriptor(); 620 this.getterDescriptor = resolvedGetCall == null ? null : resolvedGetCall.getResultingDescriptor(); 621 this.setter = resolvedSetCall == null ? null : codegen.resolveToCallable(setterDescriptor, false); 622 this.getter = resolvedGetCall == null ? null : codegen.resolveToCallable(getterDescriptor, false); 623 this.codegen = codegen; 624 this.frame = codegen.myFrameMap; 625 } 626 627 @Override 628 public void put(Type type, InstructionAdapter v) { 629 if (getter == null) { 630 throw new UnsupportedOperationException("no getter specified"); 631 } 632 if (getter instanceof CallableMethod) { 633 ((CallableMethod) getter).invokeWithNotNullAssertion(v, state, resolvedGetCall); 634 } 635 else { 636 ((IntrinsicMethod) getter).generate(codegen, v, this.type, null, null, null); 637 } 638 coerceTo(type, v); 639 } 640 641 @Override 642 public void store(Type topOfStackType, InstructionAdapter v) { 643 if (setter == null) { 644 throw new UnsupportedOperationException("no setter specified"); 645 } 646 if (setter instanceof CallableMethod) { 647 CallableMethod method = (CallableMethod) setter; 648 Method asmMethod = method.getAsmMethod(); 649 Type[] argumentTypes = asmMethod.getArgumentTypes(); 650 coerce(topOfStackType, argumentTypes[argumentTypes.length - 1], v); 651 method.invokeWithNotNullAssertion(v, state, resolvedSetCall); 652 Type returnType = asmMethod.getReturnType(); 653 if (returnType != Type.VOID_TYPE) { 654 pop(v, returnType); 655 } 656 } 657 else { 658 //noinspection ConstantConditions 659 ((IntrinsicMethod) setter).generate(codegen, v, null, null, null, null); 660 } 661 } 662 663 @Override 664 public int receiverSize() { 665 if (isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) { 666 return 2; 667 } 668 else { 669 return -1; 670 } 671 } 672 673 @Override 674 public void dupReceiver(InstructionAdapter v) { 675 if (isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) { 676 v.dup2(); // collection and index 677 return; 678 } 679 680 FrameMap.Mark mark = frame.mark(); 681 682 // indexes 683 List<ValueParameterDescriptor> valueParameters = resolvedGetCall.getResultingDescriptor().getValueParameters(); 684 int firstParamIndex = -1; 685 for (int i = valueParameters.size() - 1; i >= 0; --i) { 686 Type type = codegen.typeMapper.mapType(valueParameters.get(i).getType()); 687 firstParamIndex = frame.enterTemp(type); 688 v.store(firstParamIndex, type); 689 } 690 691 ReceiverValue receiverParameter = resolvedGetCall.getReceiverArgument(); 692 int receiverIndex = -1; 693 if (receiverParameter.exists()) { 694 Type type = codegen.typeMapper.mapType(receiverParameter.getType()); 695 receiverIndex = frame.enterTemp(type); 696 v.store(receiverIndex, type); 697 } 698 699 ReceiverValue thisObject = resolvedGetCall.getThisObject(); 700 int thisIndex = -1; 701 if (thisObject.exists()) { 702 thisIndex = frame.enterTemp(OBJECT_TYPE); 703 v.store(thisIndex, OBJECT_TYPE); 704 } 705 706 // for setter 707 708 int realReceiverIndex; 709 Type realReceiverType; 710 if (receiverIndex != -1) { 711 realReceiverType = codegen.typeMapper.mapType(receiverParameter.getType()); 712 realReceiverIndex = receiverIndex; 713 } 714 else if (thisIndex != -1) { 715 realReceiverType = OBJECT_TYPE; 716 realReceiverIndex = thisIndex; 717 } 718 else { 719 throw new UnsupportedOperationException(); 720 } 721 722 if (resolvedSetCall.getThisObject().exists()) { 723 if (resolvedSetCall.getReceiverArgument().exists()) { 724 codegen.generateFromResolvedCall(resolvedSetCall.getThisObject(), OBJECT_TYPE); 725 } 726 v.load(realReceiverIndex, realReceiverType); 727 } 728 else { 729 if (resolvedSetCall.getReceiverArgument().exists()) { 730 v.load(realReceiverIndex, realReceiverType); 731 } 732 else { 733 throw new UnsupportedOperationException(); 734 } 735 } 736 737 int index = firstParamIndex; 738 for (ValueParameterDescriptor valueParameter : valueParameters) { 739 Type type = codegen.typeMapper.mapType(valueParameter.getType()); 740 v.load(index, type); 741 index -= type.getSize(); 742 } 743 744 // restoring original 745 if (thisIndex != -1) { 746 v.load(thisIndex, OBJECT_TYPE); 747 } 748 749 if (receiverIndex != -1) { 750 v.load(receiverIndex, realReceiverType); 751 } 752 753 index = firstParamIndex; 754 for (ValueParameterDescriptor valueParameter : valueParameters) { 755 Type type = codegen.typeMapper.mapType(valueParameter.getType()); 756 v.load(index, type); 757 index -= type.getSize(); 758 } 759 760 mark.dropTo(); 761 } 762 763 private boolean isStandardStack(ResolvedCall<?> call, int valueParamsSize) { 764 if (call == null) { 765 return true; 766 } 767 768 List<ValueParameterDescriptor> valueParameters = call.getResultingDescriptor().getValueParameters(); 769 if (valueParameters.size() != valueParamsSize) { 770 return false; 771 } 772 773 for (ValueParameterDescriptor valueParameter : valueParameters) { 774 if (codegen.typeMapper.mapType(valueParameter.getType()).getSize() != 1) { 775 return false; 776 } 777 } 778 779 if (call.getThisObject().exists()) { 780 if (call.getReceiverArgument().exists()) { 781 return false; 782 } 783 } 784 else { 785 if (codegen.typeMapper.mapType(call.getResultingDescriptor().getReceiverParameter().getType()) 786 .getSize() != 1) { 787 return false; 788 } 789 } 790 791 return true; 792 } 793 } 794 795 796 public static class Field extends StackValueWithSimpleReceiver { 797 public final Type owner; 798 public final String name; 799 800 public Field(Type type, Type owner, String name, boolean isStatic) { 801 super(type, isStatic); 802 this.owner = owner; 803 this.name = name; 804 } 805 806 @Override 807 public void put(Type type, InstructionAdapter v) { 808 v.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, owner.getInternalName(), name, this.type.getDescriptor()); 809 coerceTo(type, v); 810 } 811 812 @Override 813 public void store(Type topOfStackType, InstructionAdapter v) { 814 coerceFrom(topOfStackType, v); 815 v.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, owner.getInternalName(), name, this.type.getDescriptor()); 816 } 817 } 818 819 static class Property extends StackValueWithSimpleReceiver { 820 private final CallableMethod getter; 821 private final CallableMethod setter; 822 private final Type methodOwner; 823 824 private final PropertyDescriptor descriptor; 825 private final GenerationState state; 826 827 private final String fieldName; 828 829 public Property( 830 @NotNull PropertyDescriptor descriptor, @NotNull Type methodOwner, 831 @Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStatic, 832 @Nullable String fieldName, @NotNull Type type, @NotNull GenerationState state 833 ) { 834 super(type, isStatic); 835 this.methodOwner = methodOwner; 836 this.getter = getter; 837 this.setter = setter; 838 this.descriptor = descriptor; 839 this.state = state; 840 this.fieldName = fieldName; 841 } 842 843 @Override 844 public void put(Type type, InstructionAdapter v) { 845 if (getter == null) { 846 assert fieldName != null : "Property should have either a getter or a field name: " + descriptor; 847 v.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, methodOwner.getInternalName(), fieldName, this.type.getDescriptor()); 848 genNotNullAssertionForField(v, state, descriptor); 849 coerceTo(type, v); 850 } 851 else { 852 Method method = getter.getAsmMethod(); 853 v.visitMethodInsn(getter.getInvokeOpcode(), getter.getOwner().getInternalName(), method.getName(), method.getDescriptor()); 854 coerce(method.getReturnType(), type, v); 855 } 856 } 857 858 @Override 859 public void store(Type topOfStackType, InstructionAdapter v) { 860 coerceFrom(topOfStackType, v); 861 if (setter == null) { 862 assert fieldName != null : "Property should have either a setter or a field name: " + descriptor; 863 v.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, methodOwner.getInternalName(), fieldName, this.type.getDescriptor()); 864 } 865 else { 866 Method method = setter.getAsmMethod(); 867 v.visitMethodInsn(setter.getInvokeOpcode(), setter.getOwner().getInternalName(), method.getName(), method.getDescriptor()); 868 } 869 } 870 871 public boolean isPropertyWithBackingFieldInOuterClass() { 872 return descriptor instanceof AccessorForPropertyBackingFieldInOuterClass; 873 } 874 } 875 876 private static class Expression extends StackValue { 877 private final JetExpression expression; 878 private final ExpressionCodegen generator; 879 880 public Expression(Type type, JetExpression expression, ExpressionCodegen generator) { 881 super(type); 882 this.expression = expression; 883 this.generator = generator; 884 } 885 886 @Override 887 public void put(Type type, InstructionAdapter v) { 888 generator.gen(expression, type); 889 } 890 } 891 892 public static class Shared extends StackValue { 893 private final int index; 894 private boolean isReleaseOnPut = false; 895 896 public Shared(int index, Type type) { 897 super(type); 898 this.index = index; 899 } 900 901 public void releaseOnPut() { 902 isReleaseOnPut = true; 903 } 904 905 public int getIndex() { 906 return index; 907 } 908 909 @Override 910 public void put(Type type, InstructionAdapter v) { 911 v.load(index, OBJECT_TYPE); 912 Type refType = refType(this.type); 913 Type sharedType = sharedTypeForType(this.type); 914 v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor()); 915 coerceFrom(refType, v); 916 coerceTo(type, v); 917 if (isReleaseOnPut) { 918 v.aconst(null); 919 v.store(index, OBJECT_TYPE); 920 } 921 } 922 923 @Override 924 public void store(Type topOfStackType, InstructionAdapter v) { 925 coerceFrom(topOfStackType, v); 926 v.load(index, OBJECT_TYPE); 927 AsmUtil.swap(v, sharedTypeForType(this.type), topOfStackType); 928 Type refType = refType(this.type); 929 Type sharedType = sharedTypeForType(this.type); 930 v.visitFieldInsn(PUTFIELD, sharedType.getInternalName(), "element", refType.getDescriptor()); 931 } 932 } 933 934 public static Type sharedTypeForType(Type type) { 935 switch (type.getSort()) { 936 case Type.OBJECT: 937 case Type.ARRAY: 938 return OBJECT_REF_TYPE; 939 case Type.BYTE: 940 return Type.getObjectType("kotlin/jvm/internal/Ref$ByteRef"); 941 case Type.SHORT: 942 return Type.getObjectType("kotlin/jvm/internal/Ref$ShortRef"); 943 case Type.CHAR: 944 return Type.getObjectType("kotlin/jvm/internal/Ref$CharRef"); 945 case Type.INT: 946 return Type.getObjectType("kotlin/jvm/internal/Ref$IntRef"); 947 case Type.LONG: 948 return Type.getObjectType("kotlin/jvm/internal/Ref$LongRef"); 949 case Type.BOOLEAN: 950 return Type.getObjectType("kotlin/jvm/internal/Ref$BooleanRef"); 951 case Type.FLOAT: 952 return Type.getObjectType("kotlin/jvm/internal/Ref$FloatRef"); 953 case Type.DOUBLE: 954 return Type.getObjectType("kotlin/jvm/internal/Ref$DoubleRef"); 955 default: 956 throw new UnsupportedOperationException(); 957 } 958 } 959 960 public static Type refType(Type type) { 961 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 962 return OBJECT_TYPE; 963 } 964 965 return type; 966 } 967 968 static class FieldForSharedVar extends StackValueWithSimpleReceiver { 969 final Type owner; 970 final String name; 971 972 public FieldForSharedVar(Type type, Type owner, String name) { 973 super(type, false); 974 this.owner = owner; 975 this.name = name; 976 } 977 978 @Override 979 public void put(Type type, InstructionAdapter v) { 980 Type sharedType = sharedTypeForType(this.type); 981 Type refType = refType(this.type); 982 v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor()); 983 coerceFrom(refType, v); 984 coerceTo(type, v); 985 } 986 987 @Override 988 public void store(Type topOfStackType, InstructionAdapter v) { 989 coerceFrom(topOfStackType, v); 990 v.visitFieldInsn(PUTFIELD, sharedTypeForType(type).getInternalName(), "element", refType(type).getDescriptor()); 991 } 992 } 993 994 public static class Composed extends StackValue { 995 public final StackValue prefix; 996 public final StackValue suffix; 997 998 public Composed(StackValue prefix, StackValue suffix) { 999 super(suffix.type); 1000 this.prefix = prefix; 1001 this.suffix = suffix; 1002 } 1003 1004 @Override 1005 public void put(Type type, InstructionAdapter v) { 1006 prefix.put(prefix.type, v); 1007 suffix.put(type, v); 1008 } 1009 1010 @Override 1011 public void store(Type topOfStackType, InstructionAdapter v) { 1012 prefix.put(OBJECT_TYPE, v); 1013 suffix.store(topOfStackType, v); 1014 } 1015 } 1016 1017 private static class ThisOuter extends StackValue { 1018 private final ExpressionCodegen codegen; 1019 private final ClassDescriptor descriptor; 1020 private final boolean isSuper; 1021 private final boolean coerceType; 1022 1023 public ThisOuter(ExpressionCodegen codegen, ClassDescriptor descriptor, boolean isSuper, boolean coerceType) { 1024 super(OBJECT_TYPE); 1025 this.codegen = codegen; 1026 this.descriptor = descriptor; 1027 this.isSuper = isSuper; 1028 this.coerceType = coerceType; 1029 } 1030 1031 @Override 1032 public void put(Type type, InstructionAdapter v) { 1033 StackValue stackValue = codegen.generateThisOrOuter(descriptor, isSuper); 1034 stackValue.put(coerceType ? type : stackValue.type, v); 1035 } 1036 } 1037 1038 private static class PostIncrement extends StackValue { 1039 private final int index; 1040 private final int increment; 1041 1042 public PostIncrement(int index, int increment) { 1043 super(Type.INT_TYPE); 1044 this.index = index; 1045 this.increment = increment; 1046 } 1047 1048 @Override 1049 public void put(Type type, InstructionAdapter v) { 1050 if (!type.equals(Type.VOID_TYPE)) { 1051 v.load(index, Type.INT_TYPE); 1052 coerceTo(type, v); 1053 } 1054 v.iinc(index, increment); 1055 } 1056 } 1057 1058 private static class PreIncrement extends StackValue { 1059 private final int index; 1060 private final int increment; 1061 1062 public PreIncrement(int index, int increment) { 1063 super(Type.INT_TYPE); 1064 this.index = index; 1065 this.increment = increment; 1066 } 1067 1068 @Override 1069 public void put(Type type, InstructionAdapter v) { 1070 v.iinc(index, increment); 1071 if (!type.equals(Type.VOID_TYPE)) { 1072 v.load(index, Type.INT_TYPE); 1073 coerceTo(type, v); 1074 } 1075 } 1076 } 1077 1078 public static class CallReceiver extends StackValue { 1079 private final ResolvedCall<?> resolvedCall; 1080 final StackValue receiver; 1081 private final ExpressionCodegen codegen; 1082 private final CallableMethod callableMethod; 1083 private final boolean putReceiverArgumentOnStack; 1084 1085 public CallReceiver( 1086 ResolvedCall<?> resolvedCall, 1087 StackValue receiver, 1088 ExpressionCodegen codegen, 1089 CallableMethod callableMethod, 1090 boolean putReceiverArgumentOnStack 1091 ) { 1092 super(calcType(resolvedCall, codegen, callableMethod)); 1093 this.resolvedCall = resolvedCall; 1094 this.receiver = receiver; 1095 this.codegen = codegen; 1096 this.callableMethod = callableMethod; 1097 this.putReceiverArgumentOnStack = putReceiverArgumentOnStack; 1098 } 1099 1100 private static Type calcType(ResolvedCall<?> resolvedCall, ExpressionCodegen codegen, CallableMethod callableMethod) { 1101 ReceiverValue thisObject = resolvedCall.getThisObject(); 1102 ReceiverValue receiverArgument = resolvedCall.getReceiverArgument(); 1103 1104 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 1105 1106 if (receiverArgument.exists()) { 1107 if (callableMethod != null) { 1108 return callableMethod.getReceiverClass(); 1109 } 1110 else { 1111 return codegen.typeMapper.mapType(descriptor.getReceiverParameter().getType()); 1112 } 1113 } else if (thisObject.exists()) { 1114 if (callableMethod != null) { 1115 return callableMethod.getThisType(); 1116 } 1117 else { 1118 return codegen.typeMapper.mapType(descriptor.getExpectedThisObject().getType()); 1119 } 1120 } 1121 else if (isLocalFunCall(callableMethod)) { 1122 return callableMethod.getGenerateCalleeType(); 1123 } 1124 else { 1125 return Type.VOID_TYPE; 1126 } 1127 } 1128 1129 @Override 1130 public void put(Type type, InstructionAdapter v) { 1131 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 1132 1133 ReceiverValue thisObject = resolvedCall.getThisObject(); 1134 ReceiverValue receiverArgument = resolvedCall.getReceiverArgument(); 1135 int depth; 1136 if (thisObject.exists()) { 1137 if (receiverArgument.exists()) { 1138 Type resultType = callableMethod != null ? callableMethod.getOwner() : codegen.typeMapper 1139 .mapType(descriptor.getExpectedThisObject().getType()); 1140 1141 codegen.generateFromResolvedCall(thisObject, resultType); 1142 } 1143 else { 1144 genReceiver(v, thisObject, type, null, 0); 1145 } 1146 1147 depth = 1; 1148 } else if (isLocalFunCall(callableMethod)) { 1149 assert receiver == none() || receiverArgument.exists(): "Receiver should be present only for local extension function: " + callableMethod; 1150 StackValue value = codegen.findLocalOrCapturedValue(descriptor.getOriginal()); 1151 assert value != null : "Local fun should be found in locals or in captured params: " + resolvedCall; 1152 value.put(callableMethod.getGenerateCalleeType(), v); 1153 1154 depth = 1; 1155 } 1156 else { 1157 depth = 0; 1158 } 1159 1160 if (putReceiverArgumentOnStack && receiverArgument.exists()) { 1161 genReceiver(v, receiverArgument, type, descriptor.getReceiverParameter(), depth); 1162 } 1163 } 1164 1165 private void genReceiver( 1166 InstructionAdapter v, ReceiverValue receiverArgument, Type type, 1167 @Nullable ReceiverParameterDescriptor receiverParameter, int depth 1168 ) { 1169 if (receiver == StackValue.none()) { 1170 if (receiverParameter != null) { 1171 Type receiverType = codegen.typeMapper.mapType(receiverParameter.getType()); 1172 codegen.generateFromResolvedCall(receiverArgument, receiverType); 1173 StackValue.onStack(receiverType).put(type, v); 1174 } 1175 else { 1176 codegen.generateFromResolvedCall(receiverArgument, type); 1177 } 1178 } 1179 else { 1180 receiver.moveToTopOfStack(type, v, depth); 1181 } 1182 } 1183 } 1184 1185 public abstract static class StackValueWithSimpleReceiver extends StackValue { 1186 1187 public final boolean isStatic; 1188 1189 public StackValueWithSimpleReceiver(@NotNull Type type, boolean isStatic) { 1190 super(type); 1191 this.isStatic = isStatic; 1192 } 1193 1194 @Override 1195 public void dupReceiver(InstructionAdapter v) { 1196 if (!isStatic) { 1197 v.dup(); 1198 } 1199 } 1200 1201 @Override 1202 public int receiverSize() { 1203 return isStatic ? 0 : 1; 1204 } 1205 } 1206 }