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