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