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