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