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