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