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