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