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