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