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