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