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