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