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