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
017package org.jetbrains.jet.codegen;
018
019import com.intellij.psi.tree.IElementType;
020import org.jetbrains.annotations.NotNull;
021import org.jetbrains.annotations.Nullable;
022import org.jetbrains.asm4.Label;
023import org.jetbrains.asm4.Type;
024import org.jetbrains.asm4.commons.InstructionAdapter;
025import org.jetbrains.asm4.commons.Method;
026import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod;
027import org.jetbrains.jet.codegen.state.GenerationState;
028import org.jetbrains.jet.codegen.state.JetTypeMapper;
029import org.jetbrains.jet.lang.descriptors.*;
030import org.jetbrains.jet.lang.psi.JetExpression;
031import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
032import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
033import org.jetbrains.jet.lang.resolve.java.JvmClassName;
034import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType;
035import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
036import org.jetbrains.jet.lexer.JetTokens;
037
038import java.util.List;
039
040import static org.jetbrains.asm4.Opcodes.*;
041import static org.jetbrains.jet.codegen.AsmUtil.*;
042import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*;
043
044public 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}