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 smartcasted.
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.getThisObject().exists() || resolvedCall.getReceiverArgument().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        private static class None extends StackValue {
362            public static final None INSTANCE = new None();
363    
364            private None() {
365                super(Type.VOID_TYPE);
366            }
367    
368            @Override
369            public void put(Type type, InstructionAdapter v) {
370                coerceTo(type, v);
371            }
372        }
373    
374        public static class Local extends StackValue {
375            public final int index;
376    
377            private Local(int index, Type type) {
378                super(type);
379                this.index = index;
380    
381                if (index < 0) {
382                    throw new IllegalStateException("local variable index must be non-negative");
383                }
384            }
385    
386            @Override
387            public void put(Type type, InstructionAdapter v) {
388                v.load(index, this.type);
389                coerceTo(type, v);
390                // TODO unbox
391            }
392    
393            @Override
394            public void store(Type topOfStackType, InstructionAdapter v) {
395                coerceFrom(topOfStackType, v);
396                v.store(index, this.type);
397            }
398        }
399    
400        public static class OnStack extends StackValue {
401            public OnStack(Type type) {
402                super(type);
403            }
404    
405            @Override
406            public void put(Type type, InstructionAdapter v) {
407                coerceTo(type, v);
408            }
409    
410            @Override
411            public void moveToTopOfStack(Type type, InstructionAdapter v, int depth) {
412                if (depth == 0) {
413                    put(type, v);
414                }
415                else if (depth == 1) {
416                    if (type.getSize() != 1) {
417                        throw new UnsupportedOperationException("don't know how to move type " + type + " to top of stack");
418                    }
419                    v.swap();
420                }
421                else {
422                    throw new UnsupportedOperationException("unsupported move-to-top depth " + depth);
423                }
424            }
425        }
426    
427        public static class Constant extends StackValue {
428            @Nullable
429            private final Object value;
430    
431            public Constant(@Nullable Object value, Type type) {
432                super(type);
433                this.value = value;
434            }
435    
436            @Override
437            public void put(Type type, InstructionAdapter v) {
438                if (value instanceof Integer) {
439                    v.iconst((Integer) value);
440                }
441                else if (value instanceof Long) {
442                    v.lconst((Long) value);
443                }
444                else if (value instanceof Float) {
445                    v.fconst((Float) value);
446                }
447                else if (value instanceof Double) {
448                    v.dconst((Double) value);
449                }
450                else {
451                    v.aconst(value);
452                }
453    
454                coerceTo(type, v);
455            }
456    
457            @Override
458            public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
459                if (value instanceof Boolean) {
460                    boolean boolValue = (Boolean) value;
461                    if (boolValue ^ jumpIfFalse) {
462                        v.goTo(label);
463                    }
464                }
465                else {
466                    throw new UnsupportedOperationException("don't know how to generate this condjump");
467                }
468            }
469        }
470    
471        private static class NumberCompare extends StackValue {
472            protected final IElementType opToken;
473            private final Type operandType;
474    
475            public NumberCompare(IElementType opToken, Type operandType) {
476                super(Type.BOOLEAN_TYPE);
477                this.opToken = opToken;
478                this.operandType = operandType;
479            }
480    
481            @Override
482            public void put(Type type, InstructionAdapter v) {
483                putAsBoolean(v);
484                coerceTo(type, v);
485            }
486    
487            @Override
488            public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
489                int opcode;
490                if (opToken == JetTokens.EQEQ) {
491                    opcode = jumpIfFalse ? IFNE : IFEQ;
492                }
493                else if (opToken == JetTokens.EXCLEQ) {
494                    opcode = jumpIfFalse ? IFEQ : IFNE;
495                }
496                else if (opToken == JetTokens.GT) {
497                    opcode = jumpIfFalse ? IFLE : IFGT;
498                }
499                else if (opToken == JetTokens.GTEQ) {
500                    opcode = jumpIfFalse ? IFLT : IFGE;
501                }
502                else if (opToken == JetTokens.LT) {
503                    opcode = jumpIfFalse ? IFGE : IFLT;
504                }
505                else if (opToken == JetTokens.LTEQ) {
506                    opcode = jumpIfFalse ? IFGT : IFLE;
507                }
508                else {
509                    throw new UnsupportedOperationException("don't know how to generate this condjump");
510                }
511                if (operandType == Type.FLOAT_TYPE || operandType == Type.DOUBLE_TYPE) {
512                    if (opToken == JetTokens.GT || opToken == JetTokens.GTEQ) {
513                        v.cmpl(operandType);
514                    }
515                    else {
516                        v.cmpg(operandType);
517                    }
518                }
519                else if (operandType == Type.LONG_TYPE) {
520                    v.lcmp();
521                }
522                else {
523                    opcode += (IF_ICMPEQ - IFEQ);
524                }
525                v.visitJumpInsn(opcode, label);
526            }
527        }
528    
529        private static class ObjectCompare extends NumberCompare {
530            public ObjectCompare(IElementType opToken, Type operandType) {
531                super(opToken, operandType);
532            }
533    
534            @Override
535            public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
536                int opcode;
537                if (opToken == JetTokens.EQEQEQ) {
538                    opcode = jumpIfFalse ? IF_ACMPNE : IF_ACMPEQ;
539                }
540                else if (opToken == JetTokens.EXCLEQEQEQ) {
541                    opcode = jumpIfFalse ? IF_ACMPEQ : IF_ACMPNE;
542                }
543                else {
544                    throw new UnsupportedOperationException("don't know how to generate this condjump");
545                }
546                v.visitJumpInsn(opcode, label);
547            }
548        }
549    
550        private static class Invert extends StackValue {
551            private final StackValue myOperand;
552    
553            private Invert(StackValue operand) {
554                super(Type.BOOLEAN_TYPE);
555                myOperand = operand;
556                if (myOperand.type != Type.BOOLEAN_TYPE) {
557                    throw new UnsupportedOperationException("operand of ! must be boolean");
558                }
559            }
560    
561            @Override
562            public void put(Type type, InstructionAdapter v) {
563                putAsBoolean(v);
564                coerceTo(type, v);
565            }
566    
567            @Override
568            public void condJump(Label label, boolean jumpIfFalse, InstructionAdapter v) {
569                myOperand.condJump(label, !jumpIfFalse, v);
570            }
571        }
572    
573        private static class ArrayElement extends StackValue {
574            public ArrayElement(Type type) {
575                super(type);
576            }
577    
578            @Override
579            public void put(Type type, InstructionAdapter v) {
580                v.aload(this.type);    // assumes array and index are on the stack
581                coerceTo(type, v);
582            }
583    
584            @Override
585            public void store(Type topOfStackType, InstructionAdapter v) {
586                coerceFrom(topOfStackType, v);
587                v.astore(this.type);
588            }
589    
590            @Override
591            public void dupReceiver(InstructionAdapter v) {
592                v.dup2();   // array and index
593            }
594    
595            @Override
596            public int receiverSize() {
597                return 2;
598            }
599        }
600    
601        private static class CollectionElement extends StackValue {
602            private final Callable getter;
603            private final Callable setter;
604            private final ExpressionCodegen codegen;
605            private final GenerationState state;
606            private final FrameMap frame;
607            private final ResolvedCall<FunctionDescriptor> resolvedGetCall;
608            private final ResolvedCall<FunctionDescriptor> resolvedSetCall;
609            private final FunctionDescriptor setterDescriptor;
610            private final FunctionDescriptor getterDescriptor;
611    
612            public CollectionElement(
613                    Type type,
614                    ResolvedCall<FunctionDescriptor> resolvedGetCall,
615                    ResolvedCall<FunctionDescriptor> resolvedSetCall,
616                    ExpressionCodegen codegen,
617                    GenerationState state
618            ) {
619                super(type);
620                this.resolvedGetCall = resolvedGetCall;
621                this.resolvedSetCall = resolvedSetCall;
622                this.state = state;
623                this.setterDescriptor = resolvedSetCall == null ? null : resolvedSetCall.getResultingDescriptor();
624                this.getterDescriptor = resolvedGetCall == null ? null : resolvedGetCall.getResultingDescriptor();
625                this.setter = resolvedSetCall == null ? null : codegen.resolveToCallable(setterDescriptor, false);
626                this.getter = resolvedGetCall == null ? null : codegen.resolveToCallable(getterDescriptor, false);
627                this.codegen = codegen;
628                this.frame = codegen.myFrameMap;
629            }
630    
631            @Override
632            public void put(Type type, InstructionAdapter v) {
633                if (getter == null) {
634                    throw new UnsupportedOperationException("no getter specified");
635                }
636                if (getter instanceof CallableMethod) {
637                    ((CallableMethod) getter).invokeWithNotNullAssertion(v, state, resolvedGetCall);
638                }
639                else {
640                    ((IntrinsicMethod) getter).generate(codegen, v, this.type, null, null, null);
641                }
642                coerceTo(type, v);
643            }
644    
645            @Override
646            public void store(Type topOfStackType, InstructionAdapter v) {
647                if (setter == null) {
648                    throw new UnsupportedOperationException("no setter specified");
649                }
650                if (setter instanceof CallableMethod) {
651                    CallableMethod method = (CallableMethod) setter;
652                    Method asmMethod = method.getAsmMethod();
653                    Type[] argumentTypes = asmMethod.getArgumentTypes();
654                    coerce(topOfStackType, argumentTypes[argumentTypes.length - 1], v);
655                    method.invokeWithNotNullAssertion(v, state, resolvedSetCall);
656                    Type returnType = asmMethod.getReturnType();
657                    if (returnType != Type.VOID_TYPE) {
658                        pop(v, returnType);
659                    }
660                }
661                else {
662                    //noinspection ConstantConditions
663                    ((IntrinsicMethod) setter).generate(codegen, v, null, null, null, null);
664                }
665            }
666    
667            @Override
668            public int receiverSize() {
669                if (isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) {
670                    return 2;
671                }
672                else {
673                    return -1;
674                }
675            }
676    
677            @Override
678            public void dupReceiver(InstructionAdapter v) {
679                if (isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) {
680                    v.dup2();   // collection and index
681                    return;
682                }
683    
684                FrameMap.Mark mark = frame.mark();
685    
686                // indexes
687                List<ValueParameterDescriptor> valueParameters = resolvedGetCall.getResultingDescriptor().getValueParameters();
688                int firstParamIndex = -1;
689                for (int i = valueParameters.size() - 1; i >= 0; --i) {
690                    Type type = codegen.typeMapper.mapType(valueParameters.get(i).getType());
691                    firstParamIndex = frame.enterTemp(type);
692                    v.store(firstParamIndex, type);
693                }
694    
695                ReceiverValue receiverParameter = resolvedGetCall.getReceiverArgument();
696                int receiverIndex = -1;
697                if (receiverParameter.exists()) {
698                    Type type = codegen.typeMapper.mapType(receiverParameter.getType());
699                    receiverIndex = frame.enterTemp(type);
700                    v.store(receiverIndex, type);
701                }
702    
703                ReceiverValue thisObject = resolvedGetCall.getThisObject();
704                int thisIndex = -1;
705                if (thisObject.exists()) {
706                    thisIndex = frame.enterTemp(OBJECT_TYPE);
707                    v.store(thisIndex, OBJECT_TYPE);
708                }
709    
710                // for setter
711    
712                int realReceiverIndex;
713                Type realReceiverType;
714                if (receiverIndex != -1) {
715                    realReceiverType = codegen.typeMapper.mapType(receiverParameter.getType());
716                    realReceiverIndex = receiverIndex;
717                }
718                else if (thisIndex != -1) {
719                    realReceiverType = OBJECT_TYPE;
720                    realReceiverIndex = thisIndex;
721                }
722                else {
723                    throw new UnsupportedOperationException();
724                }
725    
726                if (resolvedSetCall.getThisObject().exists()) {
727                    if (resolvedSetCall.getReceiverArgument().exists()) {
728                        codegen.generateReceiverValue(resolvedSetCall.getThisObject(), OBJECT_TYPE);
729                    }
730                    v.load(realReceiverIndex, realReceiverType);
731                }
732                else {
733                    if (resolvedSetCall.getReceiverArgument().exists()) {
734                        v.load(realReceiverIndex, realReceiverType);
735                    }
736                    else {
737                        throw new UnsupportedOperationException();
738                    }
739                }
740    
741                int index = firstParamIndex;
742                for (ValueParameterDescriptor valueParameter : valueParameters) {
743                    Type type = codegen.typeMapper.mapType(valueParameter.getType());
744                    v.load(index, type);
745                    index -= type.getSize();
746                }
747    
748                // restoring original
749                if (thisIndex != -1) {
750                    v.load(thisIndex, OBJECT_TYPE);
751                }
752    
753                if (receiverIndex != -1) {
754                    v.load(receiverIndex, realReceiverType);
755                }
756    
757                index = firstParamIndex;
758                for (ValueParameterDescriptor valueParameter : valueParameters) {
759                    Type type = codegen.typeMapper.mapType(valueParameter.getType());
760                    v.load(index, type);
761                    index -= type.getSize();
762                }
763    
764                mark.dropTo();
765            }
766    
767            private boolean isStandardStack(ResolvedCall<?> call, int valueParamsSize) {
768                if (call == null) {
769                    return true;
770                }
771    
772                List<ValueParameterDescriptor> valueParameters = call.getResultingDescriptor().getValueParameters();
773                if (valueParameters.size() != valueParamsSize) {
774                    return false;
775                }
776    
777                for (ValueParameterDescriptor valueParameter : valueParameters) {
778                    if (codegen.typeMapper.mapType(valueParameter.getType()).getSize() != 1) {
779                        return false;
780                    }
781                }
782    
783                if (call.getThisObject().exists()) {
784                    if (call.getReceiverArgument().exists()) {
785                        return false;
786                    }
787                }
788                else {
789                    if (codegen.typeMapper.mapType(call.getResultingDescriptor().getReceiverParameter().getType())
790                                .getSize() != 1) {
791                        return false;
792                    }
793                }
794    
795                return true;
796            }
797        }
798    
799    
800        public static class Field extends StackValueWithSimpleReceiver {
801            public final Type owner;
802            public final String name;
803    
804            public Field(Type type, Type owner, String name, boolean isStatic) {
805                super(type, isStatic);
806                this.owner = owner;
807                this.name = name;
808            }
809    
810            @Override
811            public void put(Type type, InstructionAdapter v) {
812                v.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, owner.getInternalName(), name, this.type.getDescriptor());
813                coerceTo(type, v);
814            }
815    
816            @Override
817            public void store(Type topOfStackType, InstructionAdapter v) {
818                coerceFrom(topOfStackType, v);
819                v.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, owner.getInternalName(), name, this.type.getDescriptor());
820            }
821        }
822    
823        static class Property extends StackValueWithSimpleReceiver {
824            private final CallableMethod getter;
825            private final CallableMethod setter;
826            private final Type methodOwner;
827    
828            private final PropertyDescriptor descriptor;
829            private final GenerationState state;
830    
831            private final String fieldName;
832    
833            public Property(
834                    @NotNull PropertyDescriptor descriptor, @NotNull Type methodOwner,
835                    @Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStatic,
836                    @Nullable String fieldName, @NotNull Type type, @NotNull GenerationState state
837            ) {
838                super(type, isStatic);
839                this.methodOwner = methodOwner;
840                this.getter = getter;
841                this.setter = setter;
842                this.descriptor = descriptor;
843                this.state = state;
844                this.fieldName = fieldName;
845            }
846    
847            @Override
848            public void put(Type type, InstructionAdapter v) {
849                if (getter == null) {
850                    assert fieldName != null : "Property should have either a getter or a field name: " + descriptor;
851                    v.visitFieldInsn(isStatic ? GETSTATIC : GETFIELD, methodOwner.getInternalName(), fieldName, this.type.getDescriptor());
852                    genNotNullAssertionForField(v, state, descriptor);
853                    coerceTo(type, v);
854                }
855                else {
856                    getter.invokeWithoutAssertions(v);
857                    coerce(getter.getAsmMethod().getReturnType(), type, v);
858                }
859            }
860    
861            @Override
862            public void store(Type topOfStackType, InstructionAdapter v) {
863                coerceFrom(topOfStackType, v);
864                if (setter == null) {
865                    assert fieldName != null : "Property should have either a setter or a field name: " + descriptor;
866                    v.visitFieldInsn(isStatic ? PUTSTATIC : PUTFIELD, methodOwner.getInternalName(), fieldName, this.type.getDescriptor());
867                }
868                else {
869                    setter.invokeWithoutAssertions(v);
870                }
871            }
872    
873            public boolean isPropertyWithBackingFieldInOuterClass() {
874                return descriptor instanceof AccessorForPropertyBackingFieldInOuterClass;
875            }
876        }
877    
878        private static class Expression extends StackValue {
879            private final JetExpression expression;
880            private final ExpressionCodegen generator;
881    
882            public Expression(Type type, JetExpression expression, ExpressionCodegen generator) {
883                super(type);
884                this.expression = expression;
885                this.generator = generator;
886            }
887    
888            @Override
889            public void put(Type type, InstructionAdapter v) {
890                generator.gen(expression, type);
891            }
892        }
893    
894        public static class Shared extends StackValue {
895            private final int index;
896            private boolean isReleaseOnPut = false;
897    
898            public Shared(int index, Type type) {
899                super(type);
900                this.index = index;
901            }
902    
903            public void releaseOnPut() {
904                isReleaseOnPut = true;
905            }
906    
907            public int getIndex() {
908                return index;
909            }
910    
911            @Override
912            public void put(Type type, InstructionAdapter v) {
913                v.load(index, OBJECT_TYPE);
914                Type refType = refType(this.type);
915                Type sharedType = sharedTypeForType(this.type);
916                v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
917                coerceFrom(refType, v);
918                coerceTo(type, v);
919                if (isReleaseOnPut) {
920                    v.aconst(null);
921                    v.store(index, OBJECT_TYPE);
922                }
923            }
924    
925            @Override
926            public void store(Type topOfStackType, InstructionAdapter v) {
927                coerceFrom(topOfStackType, v);
928                v.load(index, OBJECT_TYPE);
929                AsmUtil.swap(v, sharedTypeForType(this.type), topOfStackType);
930                Type refType = refType(this.type);
931                Type sharedType = sharedTypeForType(this.type);
932                v.visitFieldInsn(PUTFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
933            }
934        }
935    
936        @NotNull
937        public static Type sharedTypeForType(@NotNull Type type) {
938            switch (type.getSort()) {
939                case Type.OBJECT:
940                case Type.ARRAY:
941                    return OBJECT_REF_TYPE;
942                case Type.BYTE:
943                    return Type.getObjectType("kotlin/jvm/internal/Ref$ByteRef");
944                case Type.SHORT:
945                    return Type.getObjectType("kotlin/jvm/internal/Ref$ShortRef");
946                case Type.CHAR:
947                    return Type.getObjectType("kotlin/jvm/internal/Ref$CharRef");
948                case Type.INT:
949                    return Type.getObjectType("kotlin/jvm/internal/Ref$IntRef");
950                case Type.LONG:
951                    return Type.getObjectType("kotlin/jvm/internal/Ref$LongRef");
952                case Type.BOOLEAN:
953                    return Type.getObjectType("kotlin/jvm/internal/Ref$BooleanRef");
954                case Type.FLOAT:
955                    return Type.getObjectType("kotlin/jvm/internal/Ref$FloatRef");
956                case Type.DOUBLE:
957                    return Type.getObjectType("kotlin/jvm/internal/Ref$DoubleRef");
958                default:
959                    throw new UnsupportedOperationException();
960            }
961        }
962    
963        public static Type refType(Type type) {
964            if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
965                return OBJECT_TYPE;
966            }
967    
968            return type;
969        }
970    
971        static class FieldForSharedVar extends StackValueWithSimpleReceiver {
972            final Type owner;
973            final String name;
974    
975            public FieldForSharedVar(Type type, Type owner, String name) {
976                super(type, false);
977                this.owner = owner;
978                this.name = name;
979            }
980    
981            @Override
982            public void put(Type type, InstructionAdapter v) {
983                Type sharedType = sharedTypeForType(this.type);
984                Type refType = refType(this.type);
985                v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
986                coerceFrom(refType, v);
987                coerceTo(type, v);
988            }
989    
990            @Override
991            public void store(Type topOfStackType, InstructionAdapter v) {
992                coerceFrom(topOfStackType, v);
993                v.visitFieldInsn(PUTFIELD, sharedTypeForType(type).getInternalName(), "element", refType(type).getDescriptor());
994            }
995        }
996    
997        public static class Composed extends StackValue {
998            public final StackValue prefix;
999            public final StackValue suffix;
1000    
1001            public Composed(StackValue prefix, StackValue suffix) {
1002                super(suffix.type);
1003                this.prefix = prefix;
1004                this.suffix = suffix;
1005            }
1006    
1007            @Override
1008            public void put(Type type, InstructionAdapter v) {
1009                prefix.put(prefix.type, v);
1010                suffix.put(type, v);
1011            }
1012    
1013            @Override
1014            public void store(Type topOfStackType, InstructionAdapter v) {
1015                prefix.put(OBJECT_TYPE, v);
1016                suffix.store(topOfStackType, v);
1017            }
1018        }
1019    
1020        private static class ThisOuter extends StackValue {
1021            private final ExpressionCodegen codegen;
1022            private final ClassDescriptor descriptor;
1023            private final boolean isSuper;
1024            private final boolean coerceType;
1025    
1026            public ThisOuter(ExpressionCodegen codegen, ClassDescriptor descriptor, boolean isSuper, boolean coerceType) {
1027                super(OBJECT_TYPE);
1028                this.codegen = codegen;
1029                this.descriptor = descriptor;
1030                this.isSuper = isSuper;
1031                this.coerceType = coerceType;
1032            }
1033    
1034            @Override
1035            public void put(Type type, InstructionAdapter v) {
1036                StackValue stackValue = codegen.generateThisOrOuter(descriptor, isSuper);
1037                stackValue.put(coerceType ? type : stackValue.type, v);
1038            }
1039        }
1040    
1041        private static class PostIncrement extends StackValue {
1042            private final int index;
1043            private final int increment;
1044    
1045            public PostIncrement(int index, int increment) {
1046                super(Type.INT_TYPE);
1047                this.index = index;
1048                this.increment = increment;
1049            }
1050    
1051            @Override
1052            public void put(Type type, InstructionAdapter v) {
1053                if (!type.equals(Type.VOID_TYPE)) {
1054                    v.load(index, Type.INT_TYPE);
1055                    coerceTo(type, v);
1056                }
1057                v.iinc(index, increment);
1058            }
1059        }
1060    
1061        private static class PreIncrement extends StackValue {
1062            private final int index;
1063            private final int increment;
1064    
1065            public PreIncrement(int index, int increment) {
1066                super(Type.INT_TYPE);
1067                this.index = index;
1068                this.increment = increment;
1069            }
1070    
1071            @Override
1072            public void put(Type type, InstructionAdapter v) {
1073                v.iinc(index, increment);
1074                if (!type.equals(Type.VOID_TYPE)) {
1075                    v.load(index, Type.INT_TYPE);
1076                    coerceTo(type, v);
1077                }
1078            }
1079        }
1080    
1081        public static class CallReceiver extends StackValue {
1082            private final ResolvedCall<?> resolvedCall;
1083            private final StackValue receiver;
1084            private final ExpressionCodegen codegen;
1085            private final CallableMethod callableMethod;
1086            private final boolean putReceiverArgumentOnStack;
1087    
1088            public CallReceiver(
1089                    @NotNull ResolvedCall<?> resolvedCall,
1090                    @NotNull StackValue receiver,
1091                    @NotNull ExpressionCodegen codegen,
1092                    @Nullable CallableMethod callableMethod,
1093                    boolean putReceiverArgumentOnStack
1094            ) {
1095                super(calcType(resolvedCall, codegen.typeMapper, callableMethod));
1096                this.resolvedCall = resolvedCall;
1097                this.receiver = receiver;
1098                this.codegen = codegen;
1099                this.callableMethod = callableMethod;
1100                this.putReceiverArgumentOnStack = putReceiverArgumentOnStack;
1101            }
1102    
1103            private static Type calcType(
1104                    @NotNull ResolvedCall<?> resolvedCall,
1105                    @NotNull JetTypeMapper typeMapper,
1106                    @Nullable CallableMethod callableMethod
1107            ) {
1108                CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
1109    
1110                ReceiverParameterDescriptor expectedThisObject = descriptor.getExpectedThisObject();
1111                ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter();
1112    
1113                if (receiverParameter != null) {
1114                    return callableMethod != null ? callableMethod.getReceiverClass() : typeMapper.mapType(receiverParameter.getType());
1115                }
1116                else if (expectedThisObject != null) {
1117                    return callableMethod != null ? callableMethod.getThisType() : typeMapper.mapType(expectedThisObject.getType());
1118                }
1119                else if (isLocalFunCall(callableMethod)) {
1120                    return callableMethod.getGenerateCalleeType();
1121                }
1122    
1123                return Type.VOID_TYPE;
1124            }
1125    
1126            @Override
1127            public void put(Type type, InstructionAdapter v) {
1128                CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
1129    
1130                ReceiverValue thisObject = resolvedCall.getThisObject();
1131                ReceiverValue receiverArgument = resolvedCall.getReceiverArgument();
1132                int depth = 0;
1133                if (thisObject.exists()) {
1134                    if (!AnnotationsPackage.isPlatformStaticInObject(descriptor)) {
1135                        if (receiverArgument.exists()) {
1136                            //noinspection ConstantConditions
1137                            Type resultType =
1138                                    callableMethod != null ?
1139                                    callableMethod.getOwner() :
1140                                    codegen.typeMapper.mapType(descriptor.getExpectedThisObject().getType());
1141    
1142                            codegen.generateReceiverValue(thisObject, resultType);
1143                        }
1144                        else {
1145                            genReceiver(v, thisObject, type, null, 0);
1146                        }
1147                        depth = 1;
1148                    }
1149                }
1150                else if (isLocalFunCall(callableMethod)) {
1151                    assert receiver == none() || receiverArgument.exists() :
1152                            "Receiver should be present only for local extension function: " + callableMethod;
1153                    StackValue value = codegen.findLocalOrCapturedValue(descriptor.getOriginal());
1154                    assert value != null : "Local fun should be found in locals or in captured params: " + resolvedCall;
1155                    value.put(callableMethod.getGenerateCalleeType(), v);
1156    
1157                    depth = 1;
1158                }
1159    
1160                if (putReceiverArgumentOnStack && receiverArgument.exists()) {
1161                    genReceiver(v, receiverArgument, type, descriptor.getReceiverParameter(), depth);
1162                }
1163            }
1164    
1165            private void genReceiver(
1166                    @NotNull InstructionAdapter v,
1167                    @NotNull ReceiverValue receiverArgument,
1168                    @NotNull Type type,
1169                    @Nullable ReceiverParameterDescriptor receiverParameter,
1170                    int depth
1171            ) {
1172                if (receiver == StackValue.none()) {
1173                    if (receiverParameter != null) {
1174                        Type receiverType = codegen.typeMapper.mapType(receiverParameter.getType());
1175                        codegen.generateReceiverValue(receiverArgument, receiverType);
1176                        StackValue.onStack(receiverType).put(type, v);
1177                    }
1178                    else {
1179                        codegen.generateReceiverValue(receiverArgument, type);
1180                    }
1181                }
1182                else {
1183                    receiver.moveToTopOfStack(type, v, depth);
1184                }
1185            }
1186        }
1187    
1188        public abstract static class StackValueWithSimpleReceiver extends StackValue {
1189    
1190            public final boolean isStatic;
1191    
1192            public StackValueWithSimpleReceiver(@NotNull Type type, boolean isStatic) {
1193                super(type);
1194                this.isStatic = isStatic;
1195            }
1196    
1197            @Override
1198            public void dupReceiver(InstructionAdapter v) {
1199                if (!isStatic) {
1200                    v.dup();
1201                }
1202            }
1203    
1204            @Override
1205            public int receiverSize() {
1206                return isStatic ? 0 : 1;
1207            }
1208        }
1209    }