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