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 @NotNull String name, 148 @Nullable CallableMethod getter, 149 @Nullable CallableMethod setter, 150 GenerationState state 151 ) { 152 return new Property(descriptor, methodOwner, getter, setter, isStatic, name, 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 @Nullable 821 private final CallableMethod getter; 822 @Nullable 823 private final CallableMethod setter; 824 @NotNull 825 public final Type methodOwner; 826 827 @NotNull 828 private final PropertyDescriptor descriptor; 829 @NotNull 830 private final GenerationState state; 831 832 private final String name; 833 834 public Property( 835 @NotNull PropertyDescriptor descriptor, @NotNull Type methodOwner, 836 @Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStatic, 837 @NotNull String name, @NotNull Type type, @NotNull GenerationState state 838 ) { 839 super(type, isStatic); 840 this.methodOwner = methodOwner; 841 this.getter = getter; 842 this.setter = setter; 843 this.descriptor = descriptor; 844 this.state = state; 845 this.name = name; 846 } 847 848 @Override 849 public void put(Type type, InstructionAdapter v) { 850 if (getter == null) { 851 v.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, methodOwner.getInternalName(), getPropertyName(), 852 this.type.getDescriptor()); 853 genNotNullAssertionForField(v, state, descriptor); 854 coerceTo(type, v); 855 } 856 else { 857 Method method = getter.getAsmMethod(); 858 v.visitMethodInsn(getter.getInvokeOpcode(), getter.getOwner().getInternalName(), method.getName(), method.getDescriptor()); 859 coerce(method.getReturnType(), type, v); 860 } 861 } 862 863 @Override 864 public void store(Type topOfStackType, InstructionAdapter v) { 865 coerceFrom(topOfStackType, v); 866 if (setter == null) { 867 v.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, methodOwner.getInternalName(), getPropertyName(), 868 this.type.getDescriptor()); } 869 else { 870 Method method = setter.getAsmMethod(); 871 v.visitMethodInsn(setter.getInvokeOpcode(), setter.getOwner().getInternalName(), method.getName(), method.getDescriptor()); 872 } 873 } 874 875 private String getPropertyName() { 876 return name; 877 } 878 879 public boolean isPropertyWithBackingFieldInOuterClass() { 880 return descriptor instanceof AccessorForPropertyBackingFieldInOuterClass; 881 } 882 } 883 884 private static class Expression extends StackValue { 885 private final JetExpression expression; 886 private final ExpressionCodegen generator; 887 888 public Expression(Type type, JetExpression expression, ExpressionCodegen generator) { 889 super(type); 890 this.expression = expression; 891 this.generator = generator; 892 } 893 894 @Override 895 public void put(Type type, InstructionAdapter v) { 896 generator.gen(expression, type); 897 } 898 } 899 900 public static class Shared extends StackValue { 901 private final int index; 902 private boolean isReleaseOnPut = false; 903 904 public Shared(int index, Type type) { 905 super(type); 906 this.index = index; 907 } 908 909 public void releaseOnPut() { 910 isReleaseOnPut = true; 911 } 912 913 public int getIndex() { 914 return index; 915 } 916 917 @Override 918 public void put(Type type, InstructionAdapter v) { 919 v.load(index, OBJECT_TYPE); 920 Type refType = refType(this.type); 921 Type sharedType = sharedTypeForType(this.type); 922 v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor()); 923 coerceFrom(refType, v); 924 coerceTo(type, v); 925 if (isReleaseOnPut) { 926 v.aconst(null); 927 v.store(index, OBJECT_TYPE); 928 } 929 } 930 931 @Override 932 public void store(Type topOfStackType, InstructionAdapter v) { 933 coerceFrom(topOfStackType, v); 934 v.load(index, OBJECT_TYPE); 935 AsmUtil.swap(v, sharedTypeForType(this.type), topOfStackType); 936 Type refType = refType(this.type); 937 Type sharedType = sharedTypeForType(this.type); 938 v.visitFieldInsn(PUTFIELD, sharedType.getInternalName(), "element", refType.getDescriptor()); 939 } 940 } 941 942 public static Type sharedTypeForType(Type type) { 943 switch (type.getSort()) { 944 case Type.OBJECT: 945 case Type.ARRAY: 946 return OBJECT_REF_TYPE; 947 case Type.BYTE: 948 return Type.getObjectType("kotlin/jvm/internal/Ref$ByteRef"); 949 case Type.SHORT: 950 return Type.getObjectType("kotlin/jvm/internal/Ref$ShortRef"); 951 case Type.CHAR: 952 return Type.getObjectType("kotlin/jvm/internal/Ref$CharRef"); 953 case Type.INT: 954 return Type.getObjectType("kotlin/jvm/internal/Ref$IntRef"); 955 case Type.LONG: 956 return Type.getObjectType("kotlin/jvm/internal/Ref$LongRef"); 957 case Type.BOOLEAN: 958 return Type.getObjectType("kotlin/jvm/internal/Ref$BooleanRef"); 959 case Type.FLOAT: 960 return Type.getObjectType("kotlin/jvm/internal/Ref$FloatRef"); 961 case Type.DOUBLE: 962 return Type.getObjectType("kotlin/jvm/internal/Ref$DoubleRef"); 963 default: 964 throw new UnsupportedOperationException(); 965 } 966 } 967 968 public static Type refType(Type type) { 969 if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) { 970 return OBJECT_TYPE; 971 } 972 973 return type; 974 } 975 976 static class FieldForSharedVar extends StackValueWithSimpleReceiver { 977 final Type owner; 978 final String name; 979 980 public FieldForSharedVar(Type type, Type owner, String name) { 981 super(type, false); 982 this.owner = owner; 983 this.name = name; 984 } 985 986 @Override 987 public void put(Type type, InstructionAdapter v) { 988 Type sharedType = sharedTypeForType(this.type); 989 Type refType = refType(this.type); 990 v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor()); 991 coerceFrom(refType, v); 992 coerceTo(type, v); 993 } 994 995 @Override 996 public void store(Type topOfStackType, InstructionAdapter v) { 997 coerceFrom(topOfStackType, v); 998 v.visitFieldInsn(PUTFIELD, sharedTypeForType(type).getInternalName(), "element", refType(type).getDescriptor()); 999 } 1000 } 1001 1002 public static class Composed extends StackValue { 1003 public final StackValue prefix; 1004 public final StackValue suffix; 1005 1006 public Composed(StackValue prefix, StackValue suffix) { 1007 super(suffix.type); 1008 this.prefix = prefix; 1009 this.suffix = suffix; 1010 } 1011 1012 @Override 1013 public void put(Type type, InstructionAdapter v) { 1014 prefix.put(prefix.type, v); 1015 suffix.put(type, v); 1016 } 1017 1018 @Override 1019 public void store(Type topOfStackType, InstructionAdapter v) { 1020 prefix.put(OBJECT_TYPE, v); 1021 suffix.store(topOfStackType, v); 1022 } 1023 } 1024 1025 private static class ThisOuter extends StackValue { 1026 private final ExpressionCodegen codegen; 1027 private final ClassDescriptor descriptor; 1028 private final boolean isSuper; 1029 private final boolean coerceType; 1030 1031 public ThisOuter(ExpressionCodegen codegen, ClassDescriptor descriptor, boolean isSuper, boolean coerceType) { 1032 super(OBJECT_TYPE); 1033 this.codegen = codegen; 1034 this.descriptor = descriptor; 1035 this.isSuper = isSuper; 1036 this.coerceType = coerceType; 1037 } 1038 1039 @Override 1040 public void put(Type type, InstructionAdapter v) { 1041 StackValue stackValue = codegen.generateThisOrOuter(descriptor, isSuper); 1042 stackValue.put(coerceType ? type : stackValue.type, v); 1043 } 1044 } 1045 1046 private static class PostIncrement extends StackValue { 1047 private final int index; 1048 private final int increment; 1049 1050 public PostIncrement(int index, int increment) { 1051 super(Type.INT_TYPE); 1052 this.index = index; 1053 this.increment = increment; 1054 } 1055 1056 @Override 1057 public void put(Type type, InstructionAdapter v) { 1058 if (!type.equals(Type.VOID_TYPE)) { 1059 v.load(index, Type.INT_TYPE); 1060 coerceTo(type, v); 1061 } 1062 v.iinc(index, increment); 1063 } 1064 } 1065 1066 private static class PreIncrement extends StackValue { 1067 private final int index; 1068 private final int increment; 1069 1070 public PreIncrement(int index, int increment) { 1071 super(Type.INT_TYPE); 1072 this.index = index; 1073 this.increment = increment; 1074 } 1075 1076 @Override 1077 public void put(Type type, InstructionAdapter v) { 1078 v.iinc(index, increment); 1079 if (!type.equals(Type.VOID_TYPE)) { 1080 v.load(index, Type.INT_TYPE); 1081 coerceTo(type, v); 1082 } 1083 } 1084 } 1085 1086 public static class CallReceiver extends StackValue { 1087 private final ResolvedCall<?> resolvedCall; 1088 final StackValue receiver; 1089 private final ExpressionCodegen codegen; 1090 private final CallableMethod callableMethod; 1091 private final boolean putReceiverArgumentOnStack; 1092 1093 public CallReceiver( 1094 ResolvedCall<?> resolvedCall, 1095 StackValue receiver, 1096 ExpressionCodegen codegen, 1097 CallableMethod callableMethod, 1098 boolean putReceiverArgumentOnStack 1099 ) { 1100 super(calcType(resolvedCall, codegen, callableMethod)); 1101 this.resolvedCall = resolvedCall; 1102 this.receiver = receiver; 1103 this.codegen = codegen; 1104 this.callableMethod = callableMethod; 1105 this.putReceiverArgumentOnStack = putReceiverArgumentOnStack; 1106 } 1107 1108 private static Type calcType(ResolvedCall<?> resolvedCall, ExpressionCodegen codegen, CallableMethod callableMethod) { 1109 ReceiverValue thisObject = resolvedCall.getThisObject(); 1110 ReceiverValue receiverArgument = resolvedCall.getReceiverArgument(); 1111 1112 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 1113 1114 if (receiverArgument.exists()) { 1115 if (callableMethod != null) { 1116 return callableMethod.getReceiverClass(); 1117 } 1118 else { 1119 return codegen.typeMapper.mapType(descriptor.getReceiverParameter().getType()); 1120 } 1121 } else if (thisObject.exists()) { 1122 if (callableMethod != null) { 1123 return callableMethod.getThisType(); 1124 } 1125 else { 1126 return codegen.typeMapper.mapType(descriptor.getExpectedThisObject().getType()); 1127 } 1128 } 1129 else if (isLocalFunCall(callableMethod)) { 1130 return callableMethod.getGenerateCalleeType(); 1131 } 1132 else { 1133 return Type.VOID_TYPE; 1134 } 1135 } 1136 1137 @Override 1138 public void put(Type type, InstructionAdapter v) { 1139 CallableDescriptor descriptor = resolvedCall.getResultingDescriptor(); 1140 1141 ReceiverValue thisObject = resolvedCall.getThisObject(); 1142 ReceiverValue receiverArgument = resolvedCall.getReceiverArgument(); 1143 int depth; 1144 if (thisObject.exists()) { 1145 if (receiverArgument.exists()) { 1146 Type resultType = callableMethod != null ? callableMethod.getOwner() : codegen.typeMapper 1147 .mapType(descriptor.getExpectedThisObject().getType()); 1148 1149 codegen.generateFromResolvedCall(thisObject, resultType); 1150 } 1151 else { 1152 genReceiver(v, thisObject, type, null, 0); 1153 } 1154 1155 depth = 1; 1156 } else if (isLocalFunCall(callableMethod)) { 1157 assert receiver == none() || receiverArgument.exists(): "Receiver should be present only for local extension function: " + callableMethod; 1158 StackValue value = codegen.findLocalOrCapturedValue(descriptor.getOriginal()); 1159 assert value != null : "Local fun should be found in locals or in captured params: " + resolvedCall; 1160 value.put(callableMethod.getGenerateCalleeType(), v); 1161 1162 depth = 1; 1163 } 1164 else { 1165 depth = 0; 1166 } 1167 1168 if (putReceiverArgumentOnStack && receiverArgument.exists()) { 1169 genReceiver(v, receiverArgument, type, descriptor.getReceiverParameter(), depth); 1170 } 1171 } 1172 1173 private void genReceiver( 1174 InstructionAdapter v, ReceiverValue receiverArgument, Type type, 1175 @Nullable ReceiverParameterDescriptor receiverParameter, int depth 1176 ) { 1177 if (receiver == StackValue.none()) { 1178 if (receiverParameter != null) { 1179 Type receiverType = codegen.typeMapper.mapType(receiverParameter.getType()); 1180 codegen.generateFromResolvedCall(receiverArgument, receiverType); 1181 StackValue.onStack(receiverType).put(type, v); 1182 } 1183 else { 1184 codegen.generateFromResolvedCall(receiverArgument, type); 1185 } 1186 } 1187 else { 1188 receiver.moveToTopOfStack(type, v, depth); 1189 } 1190 } 1191 } 1192 1193 public abstract static class StackValueWithSimpleReceiver extends StackValue { 1194 1195 public final boolean isStatic; 1196 1197 public StackValueWithSimpleReceiver(@NotNull Type type, boolean isStatic) { 1198 super(type); 1199 this.isStatic = isStatic; 1200 } 1201 1202 @Override 1203 public void dupReceiver(InstructionAdapter v) { 1204 if (!isStatic) { 1205 v.dup(); 1206 } 1207 } 1208 1209 @Override 1210 public int receiverSize() { 1211 return isStatic ? 0 : 1; 1212 } 1213 } 1214 }