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