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