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.jet.codegen.intrinsics.IntrinsicMethod; 027 import org.jetbrains.jet.codegen.state.GenerationState; 028 import org.jetbrains.jet.codegen.state.JetTypeMapper; 029 import org.jetbrains.jet.lang.descriptors.*; 030 import org.jetbrains.jet.lang.psi.JetExpression; 031 import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; 032 import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; 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(JET_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(JET_UNIT_TYPE)) { 244 if (fromType.equals(getType(Object.class))) { 245 v.checkcast(JET_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, AsmTypeConstants.JET_UNIT_TYPE.getInternalName(), "VALUE", AsmTypeConstants.JET_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) { 313 // Coerce this/super for traits to support traits with required classes 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; 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<? extends CallableDescriptor> resolvedCall, 329 StackValue receiver, 330 ExpressionCodegen codegen, 331 @Nullable CallableMethod callableMethod 332 ) { 333 if (resolvedCall.getThisObject().exists() || resolvedCall.getReceiverArgument().exists()) { 334 return new CallReceiver(resolvedCall, receiver, codegen, callableMethod, true); 335 } 336 return receiver; 337 } 338 339 public static StackValue receiverWithoutReceiverArgument(StackValue receiverWithParameter) { 340 if (receiverWithParameter instanceof CallReceiver) { 341 CallReceiver callReceiver = (CallReceiver) receiverWithParameter; 342 return new CallReceiver(callReceiver.resolvedCall, callReceiver.receiver, 343 callReceiver.codegen, callReceiver.callableMethod, false); 344 } 345 return receiverWithParameter; 346 } 347 348 public static Field singleton(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) { 349 FieldInfo info = FieldInfo.createForSingleton(classDescriptor, typeMapper); 350 return field(info.getFieldType(), Type.getObjectType(info.getOwnerInternalName()), info.getFieldName(), true); 351 } 352 353 private static class None extends StackValue { 354 public static final None INSTANCE = new None(); 355 356 private None() { 357 super(Type.VOID_TYPE); 358 } 359 360 @Override 361 public void put(Type type, InstructionAdapter v) { 362 coerceTo(type, v); 363 } 364 } 365 366 public static class Local extends StackValue { 367 final int index; 368 369 public Local(int index, Type type) { 370 super(type); 371 this.index = index; 372 373 if (index < 0) { 374 throw new IllegalStateException("local variable index must be non-negative"); 375 } 376 } 377 378 @Override 379 public void put(Type type, InstructionAdapter v) { 380 v.load(index, this.type); 381 coerceTo(type, v); 382 // TODO unbox 383 } 384 385 @Override 386 public void store(Type topOfStackType, InstructionAdapter v) { 387 coerceFrom(topOfStackType, v); 388 v.store(index, this.type); 389 } 390 } 391 392 public static class OnStack extends StackValue { 393 public OnStack(Type type) { 394 super(type); 395 } 396 397 @Override 398 public void put(Type type, InstructionAdapter v) { 399 coerceTo(type, v); 400 } 401 402 @Override 403 public void moveToTopOfStack(Type type, InstructionAdapter v, int depth) { 404 if (depth == 0) { 405 put(type, v); 406 } 407 else if (depth == 1) { 408 if (type.getSize() != 1) { 409 throw new UnsupportedOperationException("don't know how to move type " + type + " to top of stack"); 410 } 411 v.swap(); 412 } 413 else { 414 throw new UnsupportedOperationException("unsupported move-to-top depth " + depth); 415 } 416 } 417 } 418 419 public static class Constant extends StackValue { 420 @Nullable 421 private final Object value; 422 423 public Constant(@Nullable Object value, Type type) { 424 super(type); 425 this.value = value; 426 } 427 428 @Override 429 public void put(Type type, InstructionAdapter v) { 430 if (value instanceof Integer) { 431 v.iconst((Integer) value); 432 } 433 else if (value instanceof Long) { 434 v.lconst((Long) value); 435 } 436 else if (value instanceof Float) { 437 v.fconst((Float) value); 438 } 439 else if (value instanceof Double) { 440 v.dconst((Double) value); 441 } 442 else { 443 v.aconst(value); 444 } 445 446 coerceTo(type, v); 447 } 448 449 @Override 450 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { 451 if (value instanceof Boolean) { 452 boolean boolValue = (Boolean) value; 453 if (boolValue ^ jumpIfFalse) { 454 v.goTo(label); 455 } 456 } 457 else { 458 throw new UnsupportedOperationException("don't know how to generate this condjump"); 459 } 460 } 461 } 462 463 private static class NumberCompare extends StackValue { 464 protected final IElementType opToken; 465 private final Type operandType; 466 467 public NumberCompare(IElementType opToken, Type operandType) { 468 super(Type.BOOLEAN_TYPE); 469 this.opToken = opToken; 470 this.operandType = operandType; 471 } 472 473 @Override 474 public void put(Type type, InstructionAdapter v) { 475 putAsBoolean(v); 476 coerceTo(type, v); 477 } 478 479 @Override 480 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { 481 int opcode; 482 if (opToken == JetTokens.EQEQ) { 483 opcode = jumpIfFalse ? IFNE : IFEQ; 484 } 485 else if (opToken == JetTokens.EXCLEQ) { 486 opcode = jumpIfFalse ? IFEQ : IFNE; 487 } 488 else if (opToken == JetTokens.GT) { 489 opcode = jumpIfFalse ? IFLE : IFGT; 490 } 491 else if (opToken == JetTokens.GTEQ) { 492 opcode = jumpIfFalse ? IFLT : IFGE; 493 } 494 else if (opToken == JetTokens.LT) { 495 opcode = jumpIfFalse ? IFGE : IFLT; 496 } 497 else if (opToken == JetTokens.LTEQ) { 498 opcode = jumpIfFalse ? IFGT : IFLE; 499 } 500 else { 501 throw new UnsupportedOperationException("don't know how to generate this condjump"); 502 } 503 if (operandType == Type.FLOAT_TYPE || operandType == Type.DOUBLE_TYPE) { 504 if (opToken == JetTokens.GT || opToken == JetTokens.GTEQ) { 505 v.cmpg(operandType); 506 } 507 else { 508 v.cmpl(operandType); 509 } 510 } 511 else if (operandType == Type.LONG_TYPE) { 512 v.lcmp(); 513 } 514 else { 515 opcode += (IF_ICMPEQ - IFEQ); 516 } 517 v.visitJumpInsn(opcode, label); 518 } 519 } 520 521 private static class ObjectCompare extends NumberCompare { 522 public ObjectCompare(IElementType opToken, Type operandType) { 523 super(opToken, operandType); 524 } 525 526 @Override 527 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { 528 int opcode; 529 if (opToken == JetTokens.EQEQEQ) { 530 opcode = jumpIfFalse ? IF_ACMPNE : IF_ACMPEQ; 531 } 532 else if (opToken == JetTokens.EXCLEQEQEQ) { 533 opcode = jumpIfFalse ? IF_ACMPEQ : IF_ACMPNE; 534 } 535 else { 536 throw new UnsupportedOperationException("don't know how to generate this condjump"); 537 } 538 v.visitJumpInsn(opcode, label); 539 } 540 } 541 542 private static class Invert extends StackValue { 543 private final StackValue myOperand; 544 545 private Invert(StackValue operand) { 546 super(Type.BOOLEAN_TYPE); 547 myOperand = operand; 548 if (myOperand.type != Type.BOOLEAN_TYPE) { 549 throw new UnsupportedOperationException("operand of ! must be boolean"); 550 } 551 } 552 553 @Override 554 public void put(Type type, InstructionAdapter v) { 555 putAsBoolean(v); 556 coerceTo(type, v); 557 } 558 559 @Override 560 public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) { 561 myOperand.condJump(label, !jumpIfFalse, v); 562 } 563 } 564 565 private static class ArrayElement extends StackValue { 566 private final Type boxed; 567 568 public ArrayElement(Type type, boolean unbox) { 569 super(type); 570 this.boxed = unbox ? boxType(type) : type; 571 } 572 573 @Override 574 public void put(Type type, InstructionAdapter v) { 575 v.aload(boxed); // assumes array and index are on the stack 576 coerce(boxed, type, v); 577 } 578 579 @Override 580 public void store(Type topOfStackType, InstructionAdapter v) { 581 coerce(topOfStackType, boxed, v); 582 v.astore(boxed); 583 } 584 585 @Override 586 public void dupReceiver(InstructionAdapter v) { 587 v.dup2(); // array and index 588 } 589 590 @Override 591 public int receiverSize() { 592 return 2; 593 } 594 } 595 596 private static class CollectionElement extends StackValue { 597 private final Callable getter; 598 private final Callable setter; 599 private final ExpressionCodegen codegen; 600 private final GenerationState state; 601 private final FrameMap frame; 602 private final ResolvedCall<FunctionDescriptor> resolvedGetCall; 603 private final ResolvedCall<FunctionDescriptor> resolvedSetCall; 604 private final FunctionDescriptor setterDescriptor; 605 private final FunctionDescriptor getterDescriptor; 606 607 public CollectionElement( 608 Type type, 609 ResolvedCall<FunctionDescriptor> resolvedGetCall, 610 ResolvedCall<FunctionDescriptor> resolvedSetCall, 611 ExpressionCodegen codegen, 612 GenerationState state 613 ) { 614 super(type); 615 this.resolvedGetCall = resolvedGetCall; 616 this.resolvedSetCall = resolvedSetCall; 617 this.state = state; 618 this.setterDescriptor = resolvedSetCall == null ? null : resolvedSetCall.getResultingDescriptor(); 619 this.getterDescriptor = resolvedGetCall == null ? null : resolvedGetCall.getResultingDescriptor(); 620 this.setter = resolvedSetCall == null ? null : codegen.resolveToCallable(setterDescriptor, false); 621 this.getter = resolvedGetCall == null ? null : codegen.resolveToCallable(getterDescriptor, false); 622 this.codegen = codegen; 623 this.frame = codegen.myFrameMap; 624 } 625 626 @Override 627 public void put(Type type, InstructionAdapter v) { 628 if (getter == null) { 629 throw new UnsupportedOperationException("no getter specified"); 630 } 631 if (getter instanceof CallableMethod) { 632 ((CallableMethod) getter).invokeWithNotNullAssertion(v, state, resolvedGetCall); 633 } 634 else { 635 ((IntrinsicMethod) getter).generate(codegen, v, this.type, null, null, null); 636 } 637 coerceTo(type, v); 638 } 639 640 @Override 641 public void store(Type topOfStackType, InstructionAdapter v) { 642 if (setter == null) { 643 throw new UnsupportedOperationException("no setter specified"); 644 } 645 if (setter instanceof CallableMethod) { 646 CallableMethod method = (CallableMethod) setter; 647 Method asmMethod = method.getSignature().getAsmMethod(); 648 Type[] argumentTypes = asmMethod.getArgumentTypes(); 649 coerce(topOfStackType, argumentTypes[argumentTypes.length - 1], v); 650 method.invokeWithNotNullAssertion(v, state, resolvedSetCall); 651 Type returnType = asmMethod.getReturnType(); 652 if (returnType != Type.VOID_TYPE) { 653 pop(v, returnType); 654 } 655 } 656 else { 657 //noinspection ConstantConditions 658 ((IntrinsicMethod) setter).generate(codegen, v, null, null, null, null); 659 } 660 } 661 662 @Override 663 public int receiverSize() { 664 if (isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) { 665 return 2; 666 } 667 else { 668 return -1; 669 } 670 } 671 672 @Override 673 public void dupReceiver(InstructionAdapter v) { 674 if (isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) { 675 v.dup2(); // collection and index 676 return; 677 } 678 679 int size = 0; 680 // ugly hack: getting the last variable index 681 int lastIndex = frame.enterTemp(Type.INT_TYPE); 682 frame.leaveTemp(Type.INT_TYPE); 683 684 // indexes 685 List<ValueParameterDescriptor> valueParameters = resolvedGetCall.getResultingDescriptor().getValueParameters(); 686 int firstParamIndex = -1; 687 for (int i = valueParameters.size() - 1; i >= 0; --i) { 688 Type type = codegen.typeMapper.mapType(valueParameters.get(i).getType()); 689 int sz = type.getSize(); 690 frame.enterTemp(type); 691 lastIndex += sz; 692 size += sz; 693 v.store((firstParamIndex = lastIndex) - sz, type); 694 } 695 696 ReceiverValue receiverParameter = resolvedGetCall.getReceiverArgument(); 697 int receiverIndex = -1; 698 if (receiverParameter.exists()) { 699 Type type = codegen.typeMapper.mapType(receiverParameter.getType()); 700 int sz = type.getSize(); 701 frame.enterTemp(type); 702 lastIndex += sz; 703 size += sz; 704 v.store((receiverIndex = lastIndex) - sz, type); 705 } 706 707 ReceiverValue thisObject = resolvedGetCall.getThisObject(); 708 int thisIndex = -1; 709 if (thisObject.exists()) { 710 frame.enterTemp(OBJECT_TYPE); 711 lastIndex++; 712 size++; 713 v.store((thisIndex = lastIndex) - 1, OBJECT_TYPE); 714 } 715 716 // for setter 717 718 int realReceiverIndex; 719 Type realReceiverType; 720 if (receiverIndex != -1) { 721 realReceiverType = codegen.typeMapper.mapType(receiverParameter.getType()); 722 realReceiverIndex = receiverIndex; 723 } 724 else if (thisIndex != -1) { 725 realReceiverType = OBJECT_TYPE; 726 realReceiverIndex = thisIndex; 727 } 728 else { 729 throw new UnsupportedOperationException(); 730 } 731 732 if (resolvedSetCall.getThisObject().exists()) { 733 if (resolvedSetCall.getReceiverArgument().exists()) { 734 codegen.generateFromResolvedCall(resolvedSetCall.getThisObject(), OBJECT_TYPE); 735 } 736 v.load(realReceiverIndex - realReceiverType.getSize(), realReceiverType); 737 } 738 else { 739 if (resolvedSetCall.getReceiverArgument().exists()) { 740 v.load(realReceiverIndex - realReceiverType.getSize(), realReceiverType); 741 } 742 else { 743 throw new UnsupportedOperationException(); 744 } 745 } 746 747 int index = firstParamIndex; 748 for (ValueParameterDescriptor valueParameter : valueParameters) { 749 Type type = codegen.typeMapper.mapType(valueParameter.getType()); 750 int sz = type.getSize(); 751 v.load(index - sz, type); 752 index -= sz; 753 } 754 755 // restoring original 756 if (thisIndex != -1) { 757 v.load(thisIndex - 1, OBJECT_TYPE); 758 } 759 760 if (receiverIndex != -1) { 761 v.load(receiverIndex - realReceiverType.getSize(), realReceiverType); 762 } 763 764 index = firstParamIndex; 765 for (ValueParameterDescriptor valueParameter : valueParameters) { 766 Type type = codegen.typeMapper.mapType(valueParameter.getType()); 767 int sz = type.getSize(); 768 v.load(index - sz, type); 769 index -= sz; 770 } 771 772 for (int i = 0; i < size; i++) { 773 frame.leaveTemp(OBJECT_TYPE); 774 } 775 } 776 777 private boolean isStandardStack(ResolvedCall call, int valueParamsSize) { 778 if (call == null) { 779 return true; 780 } 781 782 List<ValueParameterDescriptor> valueParameters = call.getResultingDescriptor().getValueParameters(); 783 if (valueParameters.size() != valueParamsSize) { 784 return false; 785 } 786 787 for (ValueParameterDescriptor valueParameter : valueParameters) { 788 if (codegen.typeMapper.mapType(valueParameter.getType()).getSize() != 1) { 789 return false; 790 } 791 } 792 793 if (call.getThisObject().exists()) { 794 if (call.getReceiverArgument().exists()) { 795 return false; 796 } 797 } 798 else { 799 if (codegen.typeMapper.mapType(call.getResultingDescriptor().getReceiverParameter().getType()) 800 .getSize() != 1) { 801 return false; 802 } 803 } 804 805 return true; 806 } 807 } 808 809 810 static class Field extends StackValueWithSimpleReceiver { 811 final Type owner; 812 final String name; 813 814 public Field(Type type, Type owner, String name, boolean isStatic) { 815 super(type, isStatic); 816 this.owner = owner; 817 this.name = name; 818 } 819 820 @Override 821 public void put(Type type, InstructionAdapter v) { 822 v.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, owner.getInternalName(), name, this.type.getDescriptor()); 823 coerceTo(type, v); 824 } 825 826 @Override 827 public void store(Type topOfStackType, InstructionAdapter v) { 828 coerceFrom(topOfStackType, v); 829 v.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, owner.getInternalName(), name, this.type.getDescriptor()); 830 } 831 } 832 833 static class Property extends StackValueWithSimpleReceiver { 834 @Nullable 835 private final CallableMethod getter; 836 @Nullable 837 private final CallableMethod setter; 838 @NotNull 839 public final Type methodOwner; 840 841 @NotNull 842 private final PropertyDescriptor descriptor; 843 @NotNull 844 private final GenerationState state; 845 846 private final String name; 847 848 public Property( 849 @NotNull PropertyDescriptor descriptor, @NotNull Type methodOwner, 850 @Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStatic, 851 @NotNull String name, @NotNull Type type, @NotNull GenerationState state 852 ) { 853 super(type, isStatic); 854 this.methodOwner = methodOwner; 855 this.getter = getter; 856 this.setter = setter; 857 this.descriptor = descriptor; 858 this.state = state; 859 this.name = name; 860 } 861 862 @Override 863 public void put(Type type, InstructionAdapter v) { 864 if (getter == null) { 865 v.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, methodOwner.getInternalName(), getPropertyName(), 866 this.type.getDescriptor()); 867 genNotNullAssertionForField(v, state, descriptor); 868 } 869 else { 870 Method method = getter.getSignature().getAsmMethod(); 871 v.visitMethodInsn(getter.getInvokeOpcode(), getter.getOwner().getInternalName(), method.getName(), method.getDescriptor()); 872 } 873 coerceTo(type, v); 874 } 875 876 @Override 877 public void store(Type topOfStackType, InstructionAdapter v) { 878 coerceFrom(topOfStackType, v); 879 if (setter == null) { 880 v.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, methodOwner.getInternalName(), getPropertyName(), 881 this.type.getDescriptor()); } 882 else { 883 Method method = setter.getSignature().getAsmMethod(); 884 v.visitMethodInsn(setter.getInvokeOpcode(), setter.getOwner().getInternalName(), method.getName(), method.getDescriptor()); 885 } 886 } 887 888 private String getPropertyName() { 889 return name; 890 } 891 892 public boolean isPropertyWithBackingFieldInOuterClass() { 893 return descriptor instanceof AccessorForPropertyBackingFieldInOuterClass; 894 } 895 } 896 897 private static class Expression extends StackValue { 898 private final JetExpression expression; 899 private final ExpressionCodegen generator; 900 901 public Expression(Type type, JetExpression expression, ExpressionCodegen generator) { 902 super(type); 903 this.expression = expression; 904 this.generator = generator; 905 } 906 907 @Override 908 public void put(Type type, InstructionAdapter v) { 909 generator.gen(expression, type); 910 } 911 } 912 913 public static class Shared extends StackValue { 914 private final int index; 915 private boolean isReleaseOnPut = false; 916 917 public Shared(int index, Type type) { 918 super(type); 919 this.index = index; 920 } 921 922 public void releaseOnPut() { 923 isReleaseOnPut = true; 924 } 925 926 public int getIndex() { 927 return index; 928 } 929 930 @Override 931 public void put(Type type, InstructionAdapter v) { 932 v.load(index, OBJECT_TYPE); 933 Type refType = refType(this.type); 934 Type sharedType = sharedTypeForType(this.type); 935 v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "ref", refType.getDescriptor()); 936 coerceFrom(refType, v); 937 coerceTo(type, v); 938 if (isReleaseOnPut) { 939 v.aconst(null); 940 v.store(index, OBJECT_TYPE); 941 } 942 } 943 944 @Override 945 public void store(Type topOfStackType, InstructionAdapter v) { 946 coerceFrom(topOfStackType, v); 947 v.load(index, OBJECT_TYPE); 948 AsmUtil.swap(v, sharedTypeForType(this.type), topOfStackType); 949 Type refType = refType(this.type); 950 Type sharedType = sharedTypeForType(this.type); 951 v.visitFieldInsn(PUTFIELD, sharedType.getInternalName(), "ref", refType.getDescriptor()); 952 } 953 } 954 955 public static Type sharedTypeForType(Type type) { 956 switch (type.getSort()) { 957 case Type.OBJECT: 958 case Type.ARRAY: 959 return JET_SHARED_VAR_TYPE; 960 961 case Type.BYTE: 962 return JET_SHARED_BYTE_TYPE; 963 964 case Type.SHORT: 965 return JET_SHARED_SHORT_TYPE; 966 967 case Type.CHAR: 968 return JET_SHARED_CHAR_TYPE; 969 970 case Type.INT: 971 return JET_SHARED_INT_TYPE; 972 973 case Type.LONG: 974 return JET_SHARED_LONG_TYPE; 975 976 case Type.BOOLEAN: 977 return JET_SHARED_BOOLEAN_TYPE; 978 979 case Type.FLOAT: 980 return JET_SHARED_FLOAT_TYPE; 981 982 case Type.DOUBLE: 983 return JET_SHARED_DOUBLE_TYPE; 984 985 default: 986 throw new UnsupportedOperationException(); 987 } 988 } 989 990 public static Type refType(Type type) { 991 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 992 return OBJECT_TYPE; 993 } 994 995 return type; 996 } 997 998 static class FieldForSharedVar extends StackValueWithSimpleReceiver { 999 final Type owner; 1000 final String name; 1001 1002 public FieldForSharedVar(Type type, Type owner, String name) { 1003 super(type, false); 1004 this.owner = owner; 1005 this.name = name; 1006 } 1007 1008 @Override 1009 public void put(Type type, InstructionAdapter v) { 1010 Type sharedType = sharedTypeForType(this.type); 1011 Type refType = refType(this.type); 1012 v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "ref", refType.getDescriptor()); 1013 coerceFrom(refType, v); 1014 coerceTo(type, v); 1015 } 1016 1017 @Override 1018 public void store(Type topOfStackType, InstructionAdapter v) { 1019 coerceFrom(topOfStackType, v); 1020 v.visitFieldInsn(PUTFIELD, sharedTypeForType(type).getInternalName(), "ref", refType(type).getDescriptor()); 1021 } 1022 } 1023 1024 public static class Composed extends StackValue { 1025 public final StackValue prefix; 1026 public final StackValue suffix; 1027 1028 public Composed(StackValue prefix, StackValue suffix) { 1029 super(suffix.type); 1030 this.prefix = prefix; 1031 this.suffix = suffix; 1032 } 1033 1034 @Override 1035 public void put(Type type, InstructionAdapter v) { 1036 prefix.put(prefix.type, v); 1037 suffix.put(type, v); 1038 } 1039 1040 @Override 1041 public void store(Type topOfStackType, InstructionAdapter v) { 1042 prefix.put(OBJECT_TYPE, v); 1043 suffix.store(topOfStackType, v); 1044 } 1045 } 1046 1047 private static class ThisOuter extends StackValue { 1048 private final ExpressionCodegen codegen; 1049 private final ClassDescriptor descriptor; 1050 private final boolean isSuper; 1051 private final boolean coerceType; 1052 1053 public ThisOuter(ExpressionCodegen codegen, ClassDescriptor descriptor, boolean isSuper, boolean coerceType) { 1054 super(OBJECT_TYPE); 1055 this.codegen = codegen; 1056 this.descriptor = descriptor; 1057 this.isSuper = isSuper; 1058 this.coerceType = coerceType; 1059 } 1060 1061 @Override 1062 public void put(Type type, InstructionAdapter v) { 1063 StackValue stackValue = codegen.generateThisOrOuter(descriptor, isSuper); 1064 stackValue.put(coerceType ? type : stackValue.type, v); 1065 } 1066 } 1067 1068 private static class PostIncrement extends StackValue { 1069 private final int index; 1070 private final int increment; 1071 1072 public PostIncrement(int index, int increment) { 1073 super(Type.INT_TYPE); 1074 this.index = index; 1075 this.increment = increment; 1076 } 1077 1078 @Override 1079 public void put(Type type, InstructionAdapter v) { 1080 if (!type.equals(Type.VOID_TYPE)) { 1081 v.load(index, Type.INT_TYPE); 1082 coerceTo(type, v); 1083 } 1084 v.iinc(index, increment); 1085 } 1086 } 1087 1088 private static class PreIncrement extends StackValue { 1089 private final int index; 1090 private final int increment; 1091 1092 public PreIncrement(int index, int increment) { 1093 super(Type.INT_TYPE); 1094 this.index = index; 1095 this.increment = increment; 1096 } 1097 1098 @Override 1099 public void put(Type type, InstructionAdapter v) { 1100 v.iinc(index, increment); 1101 if (!type.equals(Type.VOID_TYPE)) { 1102 v.load(index, Type.INT_TYPE); 1103 coerceTo(type, v); 1104 } 1105 } 1106 } 1107 1108 public static class CallReceiver extends StackValue { 1109 private final ResolvedCall<? extends CallableDescriptor> resolvedCall; 1110 final StackValue receiver; 1111 private final ExpressionCodegen codegen; 1112 private final CallableMethod callableMethod; 1113 private final boolean putReceiverArgumentOnStack; 1114 1115 public CallReceiver( 1116 ResolvedCall<? extends CallableDescriptor> resolvedCall, 1117 StackValue receiver, 1118 ExpressionCodegen codegen, 1119 CallableMethod callableMethod, 1120 boolean putReceiverArgumentOnStack 1121 ) { 1122 super(calcType(resolvedCall, codegen, callableMethod)); 1123 this.resolvedCall = resolvedCall; 1124 this.receiver = receiver; 1125 this.codegen = codegen; 1126 this.callableMethod = callableMethod; 1127 this.putReceiverArgumentOnStack = putReceiverArgumentOnStack; 1128 } 1129 1130 private static Type calcType( 1131 ResolvedCall<? extends CallableDescriptor> resolvedCall, 1132 ExpressionCodegen codegen, 1133 CallableMethod callableMethod 1134 ) { 1135 ReceiverValue thisObject = resolvedCall.getThisObject(); 1136 ReceiverValue receiverArgument = resolvedCall.getReceiverArgument(); 1137 1138 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 1139 1140 if (thisObject.exists()) { 1141 if (callableMethod != null) { 1142 if (receiverArgument.exists()) { 1143 return callableMethod.getReceiverClass(); 1144 } 1145 else { 1146 //noinspection ConstantConditions 1147 return callableMethod.getThisType(); 1148 } 1149 } 1150 else { 1151 if (receiverArgument.exists()) { 1152 return codegen.typeMapper.mapType(descriptor.getReceiverParameter().getType()); 1153 } 1154 else { 1155 return codegen.typeMapper.mapType(descriptor.getExpectedThisObject().getType()); 1156 } 1157 } 1158 } 1159 else { 1160 if (receiverArgument.exists()) { 1161 if (callableMethod != null) { 1162 return callableMethod.getReceiverClass(); 1163 } 1164 else { 1165 return codegen.typeMapper.mapType(descriptor.getReceiverParameter().getType()); 1166 } 1167 } 1168 else { 1169 return Type.VOID_TYPE; 1170 } 1171 } 1172 } 1173 1174 @Override 1175 public void put(Type type, InstructionAdapter v) { 1176 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 1177 1178 ReceiverValue thisObject = resolvedCall.getThisObject(); 1179 ReceiverValue receiverArgument = resolvedCall.getReceiverArgument(); 1180 if (thisObject.exists()) { 1181 if (receiverArgument.exists()) { 1182 if (callableMethod != null) { 1183 codegen.generateFromResolvedCall(thisObject, callableMethod.getOwner()); 1184 } 1185 else { 1186 codegen.generateFromResolvedCall(thisObject, codegen.typeMapper 1187 .mapType(descriptor.getExpectedThisObject().getType())); 1188 } 1189 if (putReceiverArgumentOnStack) { 1190 genReceiver(v, receiverArgument, type, descriptor.getReceiverParameter(), 1); 1191 } 1192 } 1193 else { 1194 genReceiver(v, thisObject, type, null, 0); 1195 } 1196 } 1197 else { 1198 if (putReceiverArgumentOnStack && receiverArgument.exists()) { 1199 genReceiver(v, receiverArgument, type, descriptor.getReceiverParameter(), 0); 1200 } 1201 } 1202 } 1203 1204 private void genReceiver( 1205 InstructionAdapter v, ReceiverValue receiverArgument, Type type, 1206 @Nullable ReceiverParameterDescriptor receiverParameter, int depth 1207 ) { 1208 if (receiver == StackValue.none()) { 1209 if (receiverParameter != null) { 1210 Type receiverType = codegen.typeMapper.mapType(receiverParameter.getType()); 1211 codegen.generateFromResolvedCall(receiverArgument, receiverType); 1212 StackValue.onStack(receiverType).put(type, v); 1213 } 1214 else { 1215 codegen.generateFromResolvedCall(receiverArgument, type); 1216 } 1217 } 1218 else { 1219 receiver.moveToTopOfStack(type, v, depth); 1220 } 1221 } 1222 } 1223 1224 public abstract static class StackValueWithSimpleReceiver extends StackValue { 1225 1226 protected final boolean isStatic; 1227 1228 public StackValueWithSimpleReceiver(@NotNull Type type, boolean isStatic) { 1229 super(type); 1230 this.isStatic = isStatic; 1231 } 1232 1233 @Override 1234 public void dupReceiver(InstructionAdapter v) { 1235 if (!isStatic) { 1236 v.dup(); 1237 } 1238 } 1239 1240 @Override 1241 public int receiverSize() { 1242 return isStatic ? 0 : 1; 1243 } 1244 } 1245 }