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