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 kotlin.Function1;
021    import kotlin.Unit;
022    import org.jetbrains.annotations.Contract;
023    import org.jetbrains.annotations.NotNull;
024    import org.jetbrains.annotations.Nullable;
025    import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod;
026    import org.jetbrains.jet.codegen.state.GenerationState;
027    import org.jetbrains.jet.codegen.state.JetTypeMapper;
028    import org.jetbrains.jet.lang.descriptors.*;
029    import org.jetbrains.jet.lang.psi.JetArrayAccessExpression;
030    import org.jetbrains.jet.lang.psi.JetExpression;
031    import org.jetbrains.jet.lang.resolve.annotations.AnnotationsPackage;
032    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
033    import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
034    import org.jetbrains.jet.lang.resolve.java.JvmAbi;
035    import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterKind;
036    import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodParameterSignature;
037    import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
038    import org.jetbrains.jet.lexer.JetTokens;
039    import org.jetbrains.org.objectweb.asm.Label;
040    import org.jetbrains.org.objectweb.asm.Type;
041    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
042    import org.jetbrains.org.objectweb.asm.commons.Method;
043    
044    import java.util.Collections;
045    import java.util.List;
046    
047    import static org.jetbrains.jet.codegen.AsmUtil.*;
048    import static org.jetbrains.jet.lang.resolve.java.AsmTypeConstants.*;
049    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
050    
051    public abstract class StackValue {
052    
053        private static final String NULLABLE_BYTE_TYPE_NAME = "java/lang/Byte";
054        private static final String NULLABLE_SHORT_TYPE_NAME = "java/lang/Short";
055        private static final String NULLABLE_LONG_TYPE_NAME = "java/lang/Long";
056    
057        public static final StackValue.Local LOCAL_0 = local(0, OBJECT_TYPE);
058        private static final StackValue UNIT = operation(UNIT_TYPE, new Function1<InstructionAdapter, Unit>() {
059            @Override
060            public Unit invoke(InstructionAdapter v) {
061                v.visitFieldInsn(GETSTATIC, UNIT_TYPE.getInternalName(), JvmAbi.INSTANCE_FIELD, UNIT_TYPE.getDescriptor());
062                return null;
063            }
064        });
065    
066        @NotNull
067        public final Type type;
068        private final boolean canHaveSideEffects;
069    
070        protected StackValue(@NotNull Type type) {
071            this(type, true);
072        }
073    
074        protected StackValue(@NotNull Type type, boolean canHaveSideEffects) {
075            this.type = type;
076            this.canHaveSideEffects = canHaveSideEffects;
077        }
078    
079        /**
080         * 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
081         * JVM stack after this value was generated.
082         *
083         * @param type  the type as which the value should be put
084         * @param v     the visitor used to genClassOrObject the instructions
085         * @param depth the number of new values put onto the stack
086         */
087        public void moveToTopOfStack(@NotNull Type type, @NotNull InstructionAdapter v, int depth) {
088            put(type, v);
089        }
090    
091        public void put(@NotNull Type type, @NotNull InstructionAdapter v) {
092            put(type, v, false);
093        }
094    
095        public void put(@NotNull Type type, @NotNull InstructionAdapter v, boolean skipReceiver) {
096            if (!skipReceiver) {
097                putReceiver(v, true);
098            }
099            putSelector(type, v);
100        }
101    
102        public abstract void putSelector(@NotNull Type type, @NotNull InstructionAdapter v);
103    
104        public boolean isNonStaticAccess(boolean isRead) {
105            return false;
106        }
107    
108    
109        public void putReceiver(@NotNull InstructionAdapter v, boolean isRead) {
110            //by default there is no receiver
111            //if you have it inherit StackValueWithSimpleReceiver
112        }
113    
114        public void dup(@NotNull InstructionAdapter v, boolean withReceiver) {
115            if (!Type.VOID_TYPE.equals(type)) {
116                AsmUtil.dup(v, type);
117            }
118        }
119    
120        public void store(@NotNull StackValue value, @NotNull InstructionAdapter v) {
121            store(value, v, false);
122        }
123    
124        public boolean canHaveSideEffects() {
125            return canHaveSideEffects;
126        }
127    
128        public void store(@NotNull StackValue value, @NotNull InstructionAdapter v, boolean skipReceiver) {
129            if (!skipReceiver) {
130                putReceiver(v, false);
131            }
132            value.put(value.type, v);
133            storeSelector(value.type, v);
134        }
135    
136        protected void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
137            throw new UnsupportedOperationException("Cannot store to value " + this);
138        }
139    
140        public void condJump(@NotNull Label label, boolean jumpIfFalse, @NotNull InstructionAdapter v) {
141            put(this.type, v);
142            coerceTo(Type.BOOLEAN_TYPE, v);
143            if (jumpIfFalse) {
144                v.ifeq(label);
145            }
146            else {
147                v.ifne(label);
148            }
149        }
150    
151        @NotNull
152        public static Local local(int index, @NotNull Type type) {
153            return new Local(index, type);
154        }
155    
156        @NotNull
157        public static StackValue shared(int index, @NotNull Type type) {
158            return new Shared(index, type);
159        }
160    
161        @NotNull
162        public static StackValue onStack(@NotNull Type type) {
163            return type == Type.VOID_TYPE ? none() : new OnStack(type);
164        }
165    
166        @NotNull
167        public static StackValue constant(@Nullable Object value, @NotNull Type type) {
168            return new Constant(value, type);
169        }
170    
171        @NotNull
172        public static StackValue cmp(@NotNull IElementType opToken, @NotNull Type type, StackValue left, StackValue right) {
173            return type.getSort() == Type.OBJECT ? new ObjectCompare(opToken, type, left, right) : new NumberCompare(opToken, type, left, right);
174        }
175    
176        @NotNull
177        public static StackValue not(@NotNull StackValue stackValue) {
178            return new Invert(stackValue);
179        }
180    
181        @NotNull
182        public static StackValue arrayElement(@NotNull Type type, StackValue array, StackValue index) {
183            return new ArrayElement(type, array, index);
184        }
185    
186        @NotNull
187        public static StackValue collectionElement(
188                StackValue collectionElementReceiver,
189                Type type,
190                ResolvedCall<FunctionDescriptor> getter,
191                ResolvedCall<FunctionDescriptor> setter,
192                ExpressionCodegen codegen,
193                GenerationState state
194        ) {
195            return new CollectionElement(collectionElementReceiver, type, getter, setter, codegen, state);
196        }
197    
198        @NotNull
199        public static Field field(@NotNull Type type, @NotNull Type owner, @NotNull String name, boolean isStatic, @NotNull StackValue receiver) {
200            return new Field(type, owner, name, isStatic, receiver);
201        }
202    
203        @NotNull
204        public static Field field(@NotNull StackValue.Field field, @NotNull StackValue newReceiver) {
205            return new Field(field.type, field.owner, field.name, field.isStaticPut, newReceiver);
206        }
207    
208    
209        @NotNull
210        public static StackValue changeReceiverForFieldAndSharedVar(@NotNull StackValueWithSimpleReceiver stackValue, @Nullable StackValue newReceiver) {
211            //TODO static check
212            if (newReceiver != null) {
213                if (!stackValue.isStaticPut) {
214                    if (stackValue instanceof Field) {
215                        return field((Field) stackValue, newReceiver);
216                    }
217                    else if (stackValue instanceof FieldForSharedVar) {
218                        return fieldForSharedVar((FieldForSharedVar) stackValue, newReceiver);
219                    }
220                }
221            }
222            return stackValue;
223        }
224    
225        @NotNull
226        public static Property property(
227                @NotNull PropertyDescriptor descriptor,
228                @NotNull Type backingFieldOwner,
229                @NotNull Type type,
230                boolean isStaticBackingField,
231                @Nullable String fieldName,
232                @Nullable CallableMethod getter,
233                @Nullable CallableMethod setter,
234                GenerationState state,
235                @NotNull StackValue receiver
236        ) {
237            return new Property(descriptor, backingFieldOwner, getter, setter, isStaticBackingField, fieldName, type, state, receiver);
238        }
239    
240        @NotNull
241        public static StackValue expression(Type type, JetExpression expression, ExpressionCodegen generator) {
242            return new Expression(type, expression, generator);
243        }
244    
245        private static void box(Type type, Type toType, InstructionAdapter v) {
246            if (type == Type.BYTE_TYPE || toType.getInternalName().equals(NULLABLE_BYTE_TYPE_NAME) && type == Type.INT_TYPE) {
247                v.cast(type, Type.BYTE_TYPE);
248                v.invokestatic(NULLABLE_BYTE_TYPE_NAME, "valueOf", "(B)L" + NULLABLE_BYTE_TYPE_NAME + ";", false);
249            }
250            else if (type == Type.SHORT_TYPE || toType.getInternalName().equals(NULLABLE_SHORT_TYPE_NAME) && type == Type.INT_TYPE) {
251                v.cast(type, Type.SHORT_TYPE);
252                v.invokestatic(NULLABLE_SHORT_TYPE_NAME, "valueOf", "(S)L" + NULLABLE_SHORT_TYPE_NAME + ";", false);
253            }
254            else if (type == Type.LONG_TYPE || toType.getInternalName().equals(NULLABLE_LONG_TYPE_NAME) && type == Type.INT_TYPE) {
255                v.cast(type, Type.LONG_TYPE);
256                v.invokestatic(NULLABLE_LONG_TYPE_NAME, "valueOf", "(J)L" + NULLABLE_LONG_TYPE_NAME + ";", false);
257            }
258            else if (type == Type.INT_TYPE) {
259                v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
260            }
261            else if (type == Type.BOOLEAN_TYPE) {
262                v.invokestatic("java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;", false);
263            }
264            else if (type == Type.CHAR_TYPE) {
265                v.invokestatic("java/lang/Character", "valueOf", "(C)Ljava/lang/Character;", false);
266            }
267            else if (type == Type.FLOAT_TYPE) {
268                v.invokestatic("java/lang/Float", "valueOf", "(F)Ljava/lang/Float;", false);
269            }
270            else if (type == Type.DOUBLE_TYPE) {
271                v.invokestatic("java/lang/Double", "valueOf", "(D)Ljava/lang/Double;", false);
272            }
273        }
274    
275        private static void unbox(Type type, InstructionAdapter v) {
276            if (type == Type.INT_TYPE) {
277                v.invokevirtual("java/lang/Number", "intValue", "()I", false);
278            }
279            else if (type == Type.BOOLEAN_TYPE) {
280                v.invokevirtual("java/lang/Boolean", "booleanValue", "()Z", false);
281            }
282            else if (type == Type.CHAR_TYPE) {
283                v.invokevirtual("java/lang/Character", "charValue", "()C", false);
284            }
285            else if (type == Type.SHORT_TYPE) {
286                v.invokevirtual("java/lang/Number", "shortValue", "()S", false);
287            }
288            else if (type == Type.LONG_TYPE) {
289                v.invokevirtual("java/lang/Number", "longValue", "()J", false);
290            }
291            else if (type == Type.BYTE_TYPE) {
292                v.invokevirtual("java/lang/Number", "byteValue", "()B", false);
293            }
294            else if (type == Type.FLOAT_TYPE) {
295                v.invokevirtual("java/lang/Number", "floatValue", "()F", false);
296            }
297            else if (type == Type.DOUBLE_TYPE) {
298                v.invokevirtual("java/lang/Number", "doubleValue", "()D", false);
299            }
300        }
301    
302        protected void coerceTo(@NotNull Type toType, @NotNull InstructionAdapter v) {
303            coerce(this.type, toType, v);
304        }
305    
306        protected void coerceFrom(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
307            coerce(topOfStackType, this.type, v);
308        }
309    
310        public static void coerce(@NotNull Type fromType, @NotNull Type toType, @NotNull InstructionAdapter v) {
311            if (toType.equals(fromType)) return;
312    
313            if (toType.getSort() == Type.VOID) {
314                pop(v, fromType);
315            }
316            else if (fromType.getSort() == Type.VOID) {
317                if (toType.equals(UNIT_TYPE) || toType.equals(OBJECT_TYPE)) {
318                    putUnitInstance(v);
319                }
320                else if (toType.getSort() == Type.OBJECT || toType.getSort() == Type.ARRAY) {
321                    v.aconst(null);
322                }
323                else {
324                    pushDefaultPrimitiveValueOnStack(toType, v);
325                }
326            }
327            else if (toType.equals(UNIT_TYPE)) {
328                if (fromType.equals(getType(Object.class))) {
329                    v.checkcast(UNIT_TYPE);
330                }
331                else if (!fromType.equals(getType(Void.class))) {
332                    pop(v, fromType);
333                    putUnitInstance(v);
334                }
335            }
336            else if (toType.getSort() == Type.ARRAY) {
337                v.checkcast(toType);
338            }
339            else if (toType.getSort() == Type.OBJECT) {
340                if (fromType.getSort() == Type.OBJECT || fromType.getSort() == Type.ARRAY) {
341                    if (!toType.equals(OBJECT_TYPE)) {
342                        v.checkcast(toType);
343                    }
344                }
345                else {
346                    box(fromType, toType, v);
347                }
348            }
349            else if (fromType.getSort() == Type.OBJECT) {
350                if (fromType.equals(getType(Boolean.class)) || fromType.equals(getType(Character.class))) {
351                    unbox(unboxType(fromType), v);
352                    coerce(unboxType(fromType), toType, v);
353                }
354                else {
355                    if (toType.getSort() == Type.BOOLEAN || toType.getSort() == Type.CHAR) {
356                        coerce(fromType, boxType(toType), v);
357                    }
358                    else {
359                        coerce(fromType, getType(Number.class), v);
360                    }
361                    unbox(toType, v);
362                }
363            }
364            else {
365                v.cast(fromType, toType);
366            }
367        }
368    
369        public static void putUnitInstance(@NotNull InstructionAdapter v) {
370            unit().put(UNIT_TYPE, v);
371        }
372    
373        public static StackValue unit() {
374            return UNIT;
375        }
376    
377        public void putAsBoolean(InstructionAdapter v) {
378            Label ifTrue = new Label();
379            Label end = new Label();
380            condJump(ifTrue, false, v);
381            v.iconst(0);
382            v.goTo(end);
383            v.mark(ifTrue);
384            v.iconst(1);
385            v.mark(end);
386        }
387    
388        public static StackValue none() {
389            return None.INSTANCE;
390        }
391    
392        public static FieldForSharedVar fieldForSharedVar(@NotNull Type localType, @NotNull Type classType, @NotNull String fieldName, @NotNull StackValue receiver) {
393            Field receiverWithRefWrapper = field(sharedTypeForType(localType), classType, fieldName, false, receiver);
394            return new FieldForSharedVar(localType, classType, fieldName, receiverWithRefWrapper);
395        }
396    
397        @NotNull
398        public static FieldForSharedVar fieldForSharedVar(@NotNull FieldForSharedVar field, @NotNull StackValue newReceiver) {
399            Field oldReceiver = (Field) field.receiver;
400            Field newSharedVarReceiver = field(oldReceiver, newReceiver);
401            return new FieldForSharedVar(field.type, field.owner, field.name, newSharedVarReceiver);
402        }
403    
404        public static StackValue coercion(@NotNull StackValue value, @NotNull Type castType) {
405            if (value.type.equals(castType)) {
406                return value;
407            }
408            return new CoercionValue(value, castType);
409        }
410    
411        public static StackValue thisOrOuter(@NotNull ExpressionCodegen codegen, @NotNull ClassDescriptor descriptor, boolean isSuper, boolean isExplicit) {
412            // Coerce this/super for traits to support traits with required classes.
413            // Coerce explicit 'this' for the case when it is smart cast.
414            // Do not coerce for other classes due to the 'protected' access issues (JVMS 7, 4.9.2 Structural Constraints).
415            boolean coerceType = descriptor.getKind() == ClassKind.TRAIT || (isExplicit && !isSuper);
416            return new ThisOuter(codegen, descriptor, isSuper, coerceType);
417        }
418    
419        public static StackValue postIncrement(int index, int increment) {
420            return new PostIncrement(index, increment);
421        }
422    
423        public static StackValue preIncrementForLocalVar(int index, int increment) {
424            return new PreIncrementForLocalVar(index, increment);
425        }
426    
427        public static StackValue preIncrement(
428                @NotNull Type type,
429                @NotNull StackValue stackValue,
430                int delta,
431                @NotNull Callable method,
432                ResolvedCall resolvedCall,
433                @NotNull ExpressionCodegen codegen
434        ) {
435            return new PrefixIncrement(type, stackValue, delta, method, resolvedCall, codegen);
436        }
437    
438        public static StackValue receiver(
439                ResolvedCall<?> resolvedCall,
440                StackValue receiver,
441                ExpressionCodegen codegen,
442                @Nullable CallableMethod callableMethod
443        ) {
444            if (resolvedCall.getDispatchReceiver().exists() || resolvedCall.getExtensionReceiver().exists() || isLocalFunCall(callableMethod)) {
445                boolean hasExtensionReceiver = resolvedCall.getExtensionReceiver().exists();
446                StackValue dispatchReceiver = platformStaticCallIfPresent(
447                        genReceiver(hasExtensionReceiver ? none() : receiver, codegen, resolvedCall, callableMethod, false),
448                        resolvedCall.getResultingDescriptor()
449                );
450                StackValue extensionReceiver = genReceiver(receiver, codegen, resolvedCall, callableMethod, true);
451                return new CallReceiver(dispatchReceiver, extensionReceiver,
452                                        CallReceiver.calcType(resolvedCall, codegen.typeMapper, callableMethod));
453            }
454            return receiver;
455        }
456    
457        private static StackValue genReceiver(
458                @NotNull StackValue receiver,
459                @NotNull ExpressionCodegen codegen,
460                @NotNull ResolvedCall resolvedCall,
461                @Nullable CallableMethod callableMethod,
462                boolean isExtension
463        ) {
464            ReceiverValue receiverValue = isExtension ? resolvedCall.getExtensionReceiver() : resolvedCall.getDispatchReceiver();
465            if (receiver == none()) {
466                if (receiverValue.exists()) {
467                    return codegen.generateReceiverValue(receiverValue);
468                }
469                else if (isLocalFunCall(callableMethod) && !isExtension) {
470                    CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
471                    StackValue value = codegen.findLocalOrCapturedValue(descriptor.getOriginal());
472                    assert value != null : "Local fun should be found in locals or in captured params: " + resolvedCall;
473                    return value;
474                }
475            }
476            else if (receiverValue.exists()) {
477                return receiver;
478            }
479            return none();
480        }
481    
482        private static StackValue platformStaticCallIfPresent(@NotNull StackValue resultReceiver, @NotNull CallableDescriptor descriptor) {
483            if (AnnotationsPackage.isPlatformStaticInObjectOrClass(descriptor)) {
484                if (resultReceiver.canHaveSideEffects()) {
485                    return coercion(resultReceiver, Type.VOID_TYPE);
486                }
487                else {
488                    return none();
489                }
490            }
491            return resultReceiver;
492        }
493    
494        @Contract("null -> false")
495        private static boolean isLocalFunCall(@Nullable CallableMethod callableMethod) {
496            return callableMethod != null && callableMethod.getGenerateCalleeType() != null;
497        }
498    
499        public static StackValue receiverWithoutReceiverArgument(StackValue receiverWithParameter) {
500            if (receiverWithParameter instanceof CallReceiver) {
501                CallReceiver callReceiver = (CallReceiver) receiverWithParameter;
502                return new CallReceiver(callReceiver.dispatchReceiver, none(), callReceiver.type);
503            }
504            return receiverWithParameter;
505        }
506    
507        public static Field singleton(ClassDescriptor classDescriptor, JetTypeMapper typeMapper) {
508            FieldInfo info = FieldInfo.createForSingleton(classDescriptor, typeMapper);
509            return field(info.getFieldType(), Type.getObjectType(info.getOwnerInternalName()), info.getFieldName(), true, none());
510        }
511    
512        public static StackValue operation(Type type, Function1<InstructionAdapter, Unit> lambda) {
513            return new OperationStackValue(type, lambda);
514        }
515    
516        public static StackValue functionCall(Type type, Function1<InstructionAdapter, Unit> lambda) {
517            return new FunctionCallStackValue(type, lambda);
518        }
519    
520        public static boolean couldSkipReceiverOnStaticCall(StackValue value) {
521            return value instanceof Local || value instanceof Constant;
522        }
523    
524        private static class None extends StackValue {
525            public static final None INSTANCE = new None();
526    
527            private None() {
528                super(Type.VOID_TYPE, false);
529            }
530    
531            @Override
532            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
533                coerceTo(type, v);
534            }
535        }
536    
537        public static class Local extends StackValue {
538            public final int index;
539    
540            private Local(int index, Type type) {
541                super(type, false);
542                this.index = index;
543    
544                if (index < 0) {
545                    throw new IllegalStateException("local variable index must be non-negative");
546                }
547            }
548    
549            @Override
550            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
551                v.load(index, this.type);
552                coerceTo(type, v);
553                // TODO unbox
554            }
555    
556            @Override
557            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
558                coerceFrom(topOfStackType, v);
559                v.store(index, this.type);
560            }
561        }
562    
563        public static class OnStack extends StackValue {
564            public OnStack(Type type) {
565                super(type);
566            }
567    
568            @Override
569            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
570                coerceTo(type, v);
571            }
572    
573            @Override
574            public void moveToTopOfStack(@NotNull Type type, @NotNull InstructionAdapter v, int depth) {
575                if (depth == 0) {
576                    put(type, v);
577                }
578                else if (depth == 1) {
579                    int size = this.type.getSize();
580                    if (size == 1) {
581                        v.swap();
582                    } else if (size == 2) {
583                        v.dupX2();
584                        v.pop();
585                    } else {
586                        throw new UnsupportedOperationException("don't know how to move type " + type + " to top of stack");
587                    }
588    
589                    coerceTo(type, v);
590                }
591                else {
592                    throw new UnsupportedOperationException("unsupported move-to-top depth " + depth);
593                }
594            }
595        }
596    
597        public static class Constant extends StackValue {
598            @Nullable
599            private final Object value;
600    
601            public Constant(@Nullable Object value, Type type) {
602                super(type, false);
603                this.value = value;
604            }
605    
606            @Override
607            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
608                if (value instanceof Integer) {
609                    v.iconst((Integer) value);
610                }
611                else if (value instanceof Long) {
612                    v.lconst((Long) value);
613                }
614                else if (value instanceof Float) {
615                    v.fconst((Float) value);
616                }
617                else if (value instanceof Double) {
618                    v.dconst((Double) value);
619                }
620                else {
621                    v.aconst(value);
622                }
623    
624                coerceTo(type, v);
625            }
626    
627            @Override
628            public void condJump(@NotNull Label label, boolean jumpIfFalse, @NotNull InstructionAdapter v) {
629                if (value instanceof Boolean) {
630                    boolean boolValue = (Boolean) value;
631                    if (boolValue ^ jumpIfFalse) {
632                        v.goTo(label);
633                    }
634                }
635                else {
636                    throw new UnsupportedOperationException("don't know how to generate this condjump");
637                }
638            }
639        }
640    
641        private static class NumberCompare extends StackValue {
642            protected final IElementType opToken;
643            protected final Type operandType;
644            protected final StackValue left;
645            protected final StackValue right;
646    
647            public NumberCompare(IElementType opToken, Type operandType, StackValue left, StackValue right) {
648                super(Type.BOOLEAN_TYPE);
649                this.opToken = opToken;
650                this.operandType = operandType;
651                this.left = left;
652                this.right = right;
653            }
654    
655            @Override
656            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
657                putAsBoolean(v);
658                coerceTo(type, v);
659            }
660    
661            @Override
662            public void condJump(@NotNull Label label, boolean jumpIfFalse, @NotNull InstructionAdapter v) {
663                left.put(this.operandType, v);
664                right.put(this.operandType, v);
665                int opcode;
666                if (opToken == JetTokens.EQEQ) {
667                    opcode = jumpIfFalse ? IFNE : IFEQ;
668                }
669                else if (opToken == JetTokens.EXCLEQ) {
670                    opcode = jumpIfFalse ? IFEQ : IFNE;
671                }
672                else if (opToken == JetTokens.GT) {
673                    opcode = jumpIfFalse ? IFLE : IFGT;
674                }
675                else if (opToken == JetTokens.GTEQ) {
676                    opcode = jumpIfFalse ? IFLT : IFGE;
677                }
678                else if (opToken == JetTokens.LT) {
679                    opcode = jumpIfFalse ? IFGE : IFLT;
680                }
681                else if (opToken == JetTokens.LTEQ) {
682                    opcode = jumpIfFalse ? IFGT : IFLE;
683                }
684                else {
685                    throw new UnsupportedOperationException("Don't know how to generate this condJump: " + opToken);
686                }
687                if (operandType == Type.FLOAT_TYPE || operandType == Type.DOUBLE_TYPE) {
688                    if (opToken == JetTokens.GT || opToken == JetTokens.GTEQ) {
689                        v.cmpl(operandType);
690                    }
691                    else {
692                        v.cmpg(operandType);
693                    }
694                }
695                else if (operandType == Type.LONG_TYPE) {
696                    v.lcmp();
697                }
698                else {
699                    opcode += (IF_ICMPEQ - IFEQ);
700                }
701                v.visitJumpInsn(opcode, label);
702            }
703        }
704    
705        private static class ObjectCompare extends NumberCompare {
706            public ObjectCompare(IElementType opToken, Type operandType, StackValue left, StackValue right) {
707                super(opToken, operandType, left, right);
708            }
709    
710            @Override
711            public void condJump(@NotNull Label label, boolean jumpIfFalse, @NotNull InstructionAdapter v) {
712                left.put(this.operandType, v);
713                right.put(this.operandType, v);
714                int opcode;
715                if (opToken == JetTokens.EQEQEQ) {
716                    opcode = jumpIfFalse ? IF_ACMPNE : IF_ACMPEQ;
717                }
718                else if (opToken == JetTokens.EXCLEQEQEQ) {
719                    opcode = jumpIfFalse ? IF_ACMPEQ : IF_ACMPNE;
720                }
721                else {
722                    throw new UnsupportedOperationException("don't know how to generate this condjump");
723                }
724                v.visitJumpInsn(opcode, label);
725            }
726        }
727    
728        private static class Invert extends StackValue {
729            private final StackValue myOperand;
730    
731            private Invert(StackValue operand) {
732                super(Type.BOOLEAN_TYPE);
733                myOperand = operand;
734                if (myOperand.type != Type.BOOLEAN_TYPE) {
735                    throw new UnsupportedOperationException("operand of ! must be boolean");
736                }
737            }
738    
739            @Override
740            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
741                putAsBoolean(v);
742                coerceTo(type, v);
743            }
744    
745            @Override
746            public void condJump(@NotNull Label label, boolean jumpIfFalse, @NotNull InstructionAdapter v) {
747                myOperand.condJump(label, !jumpIfFalse, v);
748            }
749        }
750    
751        private static class ArrayElement extends StackValueWithSimpleReceiver {
752            private final Type type;
753    
754            public ArrayElement(Type type, StackValue array, StackValue index) {
755                super(type, false, false, new Receiver(Type.LONG_TYPE, array, index), true);
756                this.type = type;
757            }
758    
759            @Override
760            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
761                coerceFrom(topOfStackType, v);
762                v.astore(this.type);
763            }
764    
765            @Override
766            public int receiverSize() {
767                return 2;
768            }
769    
770            @Override
771            public void putSelector(
772                    @NotNull Type type, @NotNull InstructionAdapter v
773            ) {
774                v.aload(this.type);    // assumes array and index are on the stack
775                coerceTo(type, v);
776            }
777        }
778    
779        public static class CollectionElementReceiver extends StackValue {
780            private final Callable callable;
781            private final boolean isGetter;
782            private final ExpressionCodegen codegen;
783            private final JetExpression array;
784            private final Type arrayType;
785            private final JetArrayAccessExpression expression;
786            private final Type[] argumentTypes;
787            private final ArgumentGenerator argumentGenerator;
788            private final List<ResolvedValueArgument> valueArguments;
789            private final FrameMap frame;
790            private final StackValue receiver;
791            private final ResolvedCall<FunctionDescriptor> resolvedGetCall;
792            private final ResolvedCall<FunctionDescriptor> resolvedSetCall;
793    
794            public CollectionElementReceiver(
795                    Callable callable,
796                    StackValue receiver,
797                    ResolvedCall<FunctionDescriptor> resolvedGetCall,
798                    ResolvedCall<FunctionDescriptor> resolvedSetCall,
799                    boolean isGetter,
800                    ExpressionCodegen codegen,
801                    ArgumentGenerator argumentGenerator,
802                    List<ResolvedValueArgument> valueArguments,
803                    JetExpression array,
804                    Type arrayType,
805                    JetArrayAccessExpression expression,
806                    Type[] argumentTypes
807            ) {
808                super(OBJECT_TYPE);
809                this.callable = callable;
810    
811                this.isGetter = isGetter;
812                this.receiver = receiver;
813                this.resolvedGetCall = resolvedGetCall;
814                this.resolvedSetCall = resolvedSetCall;
815                this.argumentGenerator = argumentGenerator;
816                this.valueArguments = valueArguments;
817                this.codegen = codegen;
818                this.array = array;
819                this.arrayType = arrayType;
820                this.expression = expression;
821                this.argumentTypes = argumentTypes;
822                this.frame = codegen.myFrameMap;
823            }
824    
825            @Override
826            public void putSelector(
827                    @NotNull Type type, @NotNull InstructionAdapter v
828            ) {
829                ResolvedCall<?> call = isGetter ? resolvedGetCall : resolvedSetCall;
830                if (callable instanceof CallableMethod) {
831                    StackValue newReceiver = StackValue.receiver(call, receiver, codegen, (CallableMethod) callable);
832                    newReceiver.put(newReceiver.type, v);
833                    argumentGenerator.generate(valueArguments);
834                }
835                else {
836                    codegen.gen(array, arrayType); // intrinsic method
837    
838                    int index = call.getExtensionReceiver().exists() ? 1 : 0;
839    
840                    for (JetExpression jetExpression : expression.getIndexExpressions()) {
841                        codegen.gen(jetExpression, argumentTypes[index]);
842                        index++;
843                    }
844                }
845            }
846    
847            @Override
848            public void dup(@NotNull InstructionAdapter v, boolean withReceiver) {
849                dupReceiver(v);
850            }
851    
852            public void dupReceiver(@NotNull InstructionAdapter v) {
853                if (isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) {
854                    v.dup2();   // collection and index
855                    return;
856                }
857    
858                FrameMap.Mark mark = frame.mark();
859    
860                // indexes
861                List<ValueParameterDescriptor> valueParameters = resolvedGetCall.getResultingDescriptor().getValueParameters();
862                int firstParamIndex = -1;
863                for (int i = valueParameters.size() - 1; i >= 0; --i) {
864                    Type type = codegen.typeMapper.mapType(valueParameters.get(i).getType());
865                    firstParamIndex = frame.enterTemp(type);
866                    v.store(firstParamIndex, type);
867                }
868    
869                ReceiverValue receiverParameter = resolvedGetCall.getExtensionReceiver();
870                int receiverIndex = -1;
871                if (receiverParameter.exists()) {
872                    Type type = codegen.typeMapper.mapType(receiverParameter.getType());
873                    receiverIndex = frame.enterTemp(type);
874                    v.store(receiverIndex, type);
875                }
876    
877                ReceiverValue dispatchReceiver = resolvedGetCall.getDispatchReceiver();
878                int thisIndex = -1;
879                if (dispatchReceiver.exists()) {
880                    thisIndex = frame.enterTemp(OBJECT_TYPE);
881                    v.store(thisIndex, OBJECT_TYPE);
882                }
883    
884                // for setter
885    
886                int realReceiverIndex;
887                Type realReceiverType;
888                if (receiverIndex != -1) {
889                    realReceiverType = codegen.typeMapper.mapType(receiverParameter.getType());
890                    realReceiverIndex = receiverIndex;
891                }
892                else if (thisIndex != -1) {
893                    realReceiverType = OBJECT_TYPE;
894                    realReceiverIndex = thisIndex;
895                }
896                else {
897                    throw new UnsupportedOperationException();
898                }
899    
900                if (resolvedSetCall.getDispatchReceiver().exists()) {
901                    if (resolvedSetCall.getExtensionReceiver().exists()) {
902                        codegen.generateReceiverValue(resolvedSetCall.getDispatchReceiver()).put(OBJECT_TYPE, v);
903                    }
904                    v.load(realReceiverIndex, realReceiverType);
905                }
906                else {
907                    if (resolvedSetCall.getExtensionReceiver().exists()) {
908                        v.load(realReceiverIndex, realReceiverType);
909                    }
910                    else {
911                        throw new UnsupportedOperationException();
912                    }
913                }
914    
915                int index = firstParamIndex;
916                for (ValueParameterDescriptor valueParameter : valueParameters) {
917                    Type type = codegen.typeMapper.mapType(valueParameter.getType());
918                    v.load(index, type);
919                    index -= type.getSize();
920                }
921    
922                // restoring original
923                if (thisIndex != -1) {
924                    v.load(thisIndex, OBJECT_TYPE);
925                }
926    
927                if (receiverIndex != -1) {
928                    v.load(receiverIndex, realReceiverType);
929                }
930    
931                index = firstParamIndex;
932                for (ValueParameterDescriptor valueParameter : valueParameters) {
933                    Type type = codegen.typeMapper.mapType(valueParameter.getType());
934                    v.load(index, type);
935                    index -= type.getSize();
936                }
937    
938                mark.dropTo();
939            }
940    
941            private boolean isStandardStack(ResolvedCall<?> call, int valueParamsSize) {
942                if (call == null) {
943                    return true;
944                }
945    
946                List<ValueParameterDescriptor> valueParameters = call.getResultingDescriptor().getValueParameters();
947                if (valueParameters.size() != valueParamsSize) {
948                    return false;
949                }
950    
951                for (ValueParameterDescriptor valueParameter : valueParameters) {
952                    if (codegen.typeMapper.mapType(valueParameter.getType()).getSize() != 1) {
953                        return false;
954                    }
955                }
956    
957                if (call.getDispatchReceiver().exists()) {
958                    if (call.getExtensionReceiver().exists()) {
959                        return false;
960                    }
961                }
962                else {
963                    if (codegen.typeMapper.mapType(call.getResultingDescriptor().getExtensionReceiverParameter().getType())
964                                .getSize() != 1) {
965                        return false;
966                    }
967                }
968    
969                return true;
970            }
971        }
972    
973        public static class CollectionElement extends StackValueWithSimpleReceiver {
974            private final Callable getter;
975            private final Callable setter;
976            private final ExpressionCodegen codegen;
977            private final GenerationState state;
978            private final ResolvedCall<FunctionDescriptor> resolvedGetCall;
979            private final ResolvedCall<FunctionDescriptor> resolvedSetCall;
980            private final FunctionDescriptor setterDescriptor;
981            private final FunctionDescriptor getterDescriptor;
982    
983            public CollectionElement(
984                    StackValue collectionElementReceiver,
985                    Type type,
986                    ResolvedCall<FunctionDescriptor> resolvedGetCall,
987                    ResolvedCall<FunctionDescriptor> resolvedSetCall,
988                    ExpressionCodegen codegen,
989                    GenerationState state
990            ) {
991                super(type, false, false, collectionElementReceiver, true);
992                this.resolvedGetCall = resolvedGetCall;
993                this.resolvedSetCall = resolvedSetCall;
994                this.state = state;
995                this.setterDescriptor = resolvedSetCall == null ? null : resolvedSetCall.getResultingDescriptor();
996                this.getterDescriptor = resolvedGetCall == null ? null : resolvedGetCall.getResultingDescriptor();
997                this.setter = resolvedSetCall == null ? null : codegen.resolveToCallable(setterDescriptor, false);
998                this.getter = resolvedGetCall == null ? null : codegen.resolveToCallable(getterDescriptor, false);
999                this.codegen = codegen;
1000            }
1001    
1002            @Override
1003            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1004                if (getter == null) {
1005                    throw new UnsupportedOperationException("no getter specified");
1006                }
1007                if (getter instanceof CallableMethod) {
1008                    ((CallableMethod) getter).invokeWithNotNullAssertion(v, state, resolvedGetCall);
1009                }
1010                else {
1011                    StackValue result = ((IntrinsicMethod) getter).generate(codegen, this.type, null, Collections.<JetExpression>emptyList(), StackValue.none());
1012                    result.put(result.type, v);
1013                }
1014                coerceTo(type, v);
1015            }
1016    
1017            @Override
1018            public int receiverSize() {
1019                if (isStandardStack(resolvedGetCall, 1) && isStandardStack(resolvedSetCall, 2)) {
1020                    return 2;
1021                }
1022                else {
1023                    return -1;
1024                }
1025            }
1026    
1027            private boolean isStandardStack(ResolvedCall<?> call, int valueParamsSize) {
1028                if (call == null) {
1029                    return true;
1030                }
1031    
1032                List<ValueParameterDescriptor> valueParameters = call.getResultingDescriptor().getValueParameters();
1033                if (valueParameters.size() != valueParamsSize) {
1034                    return false;
1035                }
1036    
1037                for (ValueParameterDescriptor valueParameter : valueParameters) {
1038                    if (codegen.typeMapper.mapType(valueParameter.getType()).getSize() != 1) {
1039                        return false;
1040                    }
1041                }
1042    
1043                if (call.getDispatchReceiver().exists()) {
1044                    if (call.getExtensionReceiver().exists()) {
1045                        return false;
1046                    }
1047                }
1048                else {
1049                    if (codegen.typeMapper.mapType(call.getResultingDescriptor().getExtensionReceiverParameter().getType())
1050                                .getSize() != 1) {
1051                        return false;
1052                    }
1053                }
1054    
1055                return true;
1056            }
1057    
1058            @Override
1059            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1060                if (setter == null) {
1061                    throw new UnsupportedOperationException("no setter specified");
1062                }
1063                if (setter instanceof CallableMethod) {
1064                    CallableMethod method = (CallableMethod) setter;
1065                    Method asmMethod = method.getAsmMethod();
1066                    Type[] argumentTypes = asmMethod.getArgumentTypes();
1067                    coerce(topOfStackType, argumentTypes[argumentTypes.length - 1], v);
1068                    method.invokeWithNotNullAssertion(v, state, resolvedSetCall);
1069                    Type returnType = asmMethod.getReturnType();
1070                    if (returnType != Type.VOID_TYPE) {
1071                        pop(v, returnType);
1072                    }
1073                }
1074                else {
1075                    //noinspection ConstantConditions
1076                    StackValue result = ((IntrinsicMethod) setter).generate(codegen, null, null, Collections.<JetExpression>emptyList(), StackValue.none());
1077                    result.put(result.type, v);
1078                }
1079            }
1080        }
1081    
1082    
1083        public static class Field extends StackValueWithSimpleReceiver {
1084            public final Type owner;
1085            public final String name;
1086    
1087            public Field(Type type, Type owner, String name, boolean isStatic, StackValue receiver) {
1088                super(type, isStatic, isStatic, receiver, receiver.canHaveSideEffects());
1089                this.owner = owner;
1090                this.name = name;
1091            }
1092    
1093            @Override
1094            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1095                v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD, owner.getInternalName(), name, this.type.getDescriptor());
1096                coerceTo(type, v);
1097            }
1098    
1099            @Override
1100            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1101                coerceFrom(topOfStackType, v);
1102                v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, owner.getInternalName(), name, this.type.getDescriptor());
1103            }
1104        }
1105    
1106        static class Property extends StackValueWithSimpleReceiver {
1107            private final CallableMethod getter;
1108            private final CallableMethod setter;
1109            private final Type backingFieldOwner;
1110    
1111            private final PropertyDescriptor descriptor;
1112            private final GenerationState state;
1113    
1114            private final String fieldName;
1115    
1116            public Property(
1117                    @NotNull PropertyDescriptor descriptor, @NotNull Type backingFieldOwner,
1118                    @Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStaticBackingField,
1119                    @Nullable String fieldName, @NotNull Type type, @NotNull GenerationState state,
1120                    @NotNull StackValue receiver
1121            ) {
1122                super(type, isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver, true);
1123                this.backingFieldOwner = backingFieldOwner;
1124                this.getter = getter;
1125                this.setter = setter;
1126                this.descriptor = descriptor;
1127                this.state = state;
1128                this.fieldName = fieldName;
1129            }
1130    
1131            @Override
1132            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1133                if (getter == null) {
1134                    assert fieldName != null : "Property should have either a getter or a field name: " + descriptor;
1135                    v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD, backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
1136                    genNotNullAssertionForField(v, state, descriptor);
1137                    coerceTo(type, v);
1138                }
1139                else {
1140                    getter.invokeWithoutAssertions(v);
1141                    coerce(getter.getAsmMethod().getReturnType(), type, v);
1142                }
1143            }
1144    
1145            @Override
1146            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1147                coerceFrom(topOfStackType, v);
1148                if (setter == null) {
1149                    assert fieldName != null : "Property should have either a setter or a field name: " + descriptor;
1150                    v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
1151                }
1152                else {
1153                    setter.invokeWithoutAssertions(v);
1154                }
1155            }
1156    
1157            private static boolean isStatic(boolean isStaticBackingField, @Nullable CallableMethod callable) {
1158                if (isStaticBackingField && callable == null) {
1159                    return true;
1160                }
1161    
1162                if (callable != null && callable.isStaticCall()) {
1163                    List<JvmMethodParameterSignature> parameters = callable.getValueParameters();
1164                    for (JvmMethodParameterSignature parameter : parameters) {
1165                        JvmMethodParameterKind kind = parameter.getKind();
1166                        if (kind == JvmMethodParameterKind.VALUE) {
1167                            break;
1168                        }
1169                        if (kind == JvmMethodParameterKind.RECEIVER || kind == JvmMethodParameterKind.THIS) {
1170                            return false;
1171                        }
1172                    }
1173                    return true;
1174                }
1175    
1176                return false;
1177            }
1178        }
1179    
1180        private static class Expression extends StackValue {
1181            private final JetExpression expression;
1182            private final ExpressionCodegen generator;
1183    
1184            public Expression(Type type, JetExpression expression, ExpressionCodegen generator) {
1185                super(type);
1186                this.expression = expression;
1187                this.generator = generator;
1188            }
1189    
1190            @Override
1191            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1192                generator.gen(expression, type);
1193            }
1194        }
1195    
1196        public static class Shared extends StackValueWithSimpleReceiver {
1197            private final int index;
1198    
1199            public Shared(int index, Type type) {
1200                super(type, false, false, local(index, OBJECT_TYPE), false);
1201                this.index = index;
1202            }
1203    
1204            public int getIndex() {
1205                return index;
1206            }
1207    
1208            @Override
1209            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1210                Type refType = refType(this.type);
1211                Type sharedType = sharedTypeForType(this.type);
1212                v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
1213                coerceFrom(refType, v);
1214                coerceTo(type, v);
1215            }
1216    
1217            @Override
1218            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1219                coerceFrom(topOfStackType, v);
1220                Type refType = refType(this.type);
1221                Type sharedType = sharedTypeForType(this.type);
1222                v.visitFieldInsn(PUTFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
1223            }
1224        }
1225    
1226        @NotNull
1227        public static Type sharedTypeForType(@NotNull Type type) {
1228            switch (type.getSort()) {
1229                case Type.OBJECT:
1230                case Type.ARRAY:
1231                    return OBJECT_REF_TYPE;
1232                case Type.BYTE:
1233                    return Type.getObjectType("kotlin/jvm/internal/Ref$ByteRef");
1234                case Type.SHORT:
1235                    return Type.getObjectType("kotlin/jvm/internal/Ref$ShortRef");
1236                case Type.CHAR:
1237                    return Type.getObjectType("kotlin/jvm/internal/Ref$CharRef");
1238                case Type.INT:
1239                    return Type.getObjectType("kotlin/jvm/internal/Ref$IntRef");
1240                case Type.LONG:
1241                    return Type.getObjectType("kotlin/jvm/internal/Ref$LongRef");
1242                case Type.BOOLEAN:
1243                    return Type.getObjectType("kotlin/jvm/internal/Ref$BooleanRef");
1244                case Type.FLOAT:
1245                    return Type.getObjectType("kotlin/jvm/internal/Ref$FloatRef");
1246                case Type.DOUBLE:
1247                    return Type.getObjectType("kotlin/jvm/internal/Ref$DoubleRef");
1248                default:
1249                    throw new UnsupportedOperationException();
1250            }
1251        }
1252    
1253        public static Type refType(Type type) {
1254            if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
1255                return OBJECT_TYPE;
1256            }
1257    
1258            return type;
1259        }
1260    
1261        public static class FieldForSharedVar extends StackValueWithSimpleReceiver {
1262            final Type owner;
1263            final String name;
1264    
1265            public FieldForSharedVar(Type type, Type owner, String name, StackValue.Field receiver) {
1266                super(type, false, false, receiver, receiver.canHaveSideEffects());
1267                this.owner = owner;
1268                this.name = name;
1269            }
1270    
1271            @Override
1272            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1273                Type sharedType = sharedTypeForType(this.type);
1274                Type refType = refType(this.type);
1275                v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
1276                coerceFrom(refType, v);
1277                coerceTo(type, v);
1278            }
1279    
1280            @Override
1281            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1282                coerceFrom(topOfStackType, v);
1283                v.visitFieldInsn(PUTFIELD, sharedTypeForType(type).getInternalName(), "element", refType(type).getDescriptor());
1284            }
1285        }
1286    
1287        private static class ThisOuter extends StackValue {
1288            private final ExpressionCodegen codegen;
1289            private final ClassDescriptor descriptor;
1290            private final boolean isSuper;
1291            private final boolean coerceType;
1292    
1293            public ThisOuter(ExpressionCodegen codegen, ClassDescriptor descriptor, boolean isSuper, boolean coerceType) {
1294                super(OBJECT_TYPE, false);
1295                this.codegen = codegen;
1296                this.descriptor = descriptor;
1297                this.isSuper = isSuper;
1298                this.coerceType = coerceType;
1299            }
1300    
1301            @Override
1302            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1303                StackValue stackValue = codegen.generateThisOrOuter(descriptor, isSuper);
1304                stackValue.put(coerceType ? type : stackValue.type, v);
1305            }
1306        }
1307    
1308        private static class PostIncrement extends StackValue {
1309            private final int index;
1310            private final int increment;
1311    
1312            public PostIncrement(int index, int increment) {
1313                super(Type.INT_TYPE);
1314                this.index = index;
1315                this.increment = increment;
1316            }
1317    
1318            @Override
1319            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1320                if (!type.equals(Type.VOID_TYPE)) {
1321                    v.load(index, Type.INT_TYPE);
1322                    coerceTo(type, v);
1323                }
1324                v.iinc(index, increment);
1325            }
1326        }
1327    
1328        private static class PreIncrementForLocalVar extends StackValue {
1329            private final int index;
1330            private final int increment;
1331    
1332            public PreIncrementForLocalVar(int index, int increment) {
1333                super(Type.INT_TYPE);
1334                this.index = index;
1335                this.increment = increment;
1336            }
1337    
1338            @Override
1339            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1340                v.iinc(index, increment);
1341                if (!type.equals(Type.VOID_TYPE)) {
1342                    v.load(index, Type.INT_TYPE);
1343                    coerceTo(type, v);
1344                }
1345            }
1346        }
1347    
1348        private static class PrefixIncrement extends StackValue {
1349            private final int delta;
1350            private final Callable callable;
1351            private final ResolvedCall resolvedCall;
1352            private final ExpressionCodegen codegen;
1353            private StackValue value;
1354    
1355            public PrefixIncrement(
1356                    @NotNull Type type,
1357                    @NotNull StackValue value,
1358                    int delta,
1359                    @NotNull Callable callable,
1360                    ResolvedCall resolvedCall,
1361                    @NotNull ExpressionCodegen codegen
1362            ) {
1363                super(type);
1364                this.value = value;
1365                this.delta = delta;
1366                this.callable = callable;
1367                this.resolvedCall = resolvedCall;
1368                this.codegen = codegen;
1369            }
1370    
1371            @Override
1372            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1373                value = StackValue.complexReceiver(value, true, false, true);
1374                value.put(this.type, v);
1375    
1376                if (callable instanceof CallableMethod) {
1377                    value.store(codegen.invokeFunction(resolvedCall, StackValue.onStack(this.type)), v, true);
1378                }
1379                else {
1380                    genIncrement(this.type, delta, v);
1381                    value.store(StackValue.onStack(this.type), v, true);
1382                }
1383    
1384                value.put(this.type, v, true);
1385                coerceTo(type, v);
1386            }
1387        }
1388    
1389        public static class CallReceiver extends StackValue {
1390            private final StackValue dispatchReceiver;
1391            private final StackValue extensionReceiver;
1392    
1393            public CallReceiver(
1394                    @NotNull StackValue dispatchReceiver,
1395                    @NotNull StackValue extensionReceiver,
1396                    @NotNull Type type
1397            ) {
1398                super(type, dispatchReceiver.canHaveSideEffects() || extensionReceiver.canHaveSideEffects());
1399                this.dispatchReceiver = dispatchReceiver;
1400                this.extensionReceiver = extensionReceiver;
1401            }
1402    
1403            public static Type calcType(
1404                    @NotNull ResolvedCall<?> resolvedCall,
1405                    @NotNull JetTypeMapper typeMapper,
1406                    @Nullable CallableMethod callableMethod
1407            ) {
1408                CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
1409    
1410                ReceiverParameterDescriptor dispatchReceiver = descriptor.getDispatchReceiverParameter();
1411                ReceiverParameterDescriptor extensionReceiver = descriptor.getExtensionReceiverParameter();
1412    
1413                if (extensionReceiver != null) {
1414                    return callableMethod != null ? callableMethod.getReceiverClass() : typeMapper.mapType(extensionReceiver.getType());
1415                }
1416                else if (dispatchReceiver != null) {
1417                    if (AnnotationsPackage.isPlatformStaticInObjectOrClass(descriptor)) {
1418                        return Type.VOID_TYPE;
1419                    }
1420                    else {
1421                        return callableMethod != null ? callableMethod.getThisType() : typeMapper.mapType(dispatchReceiver.getType());
1422                    }
1423                }
1424                else if (isLocalFunCall(callableMethod)) {
1425                    return callableMethod.getGenerateCalleeType();
1426                }
1427    
1428                return Type.VOID_TYPE;
1429            }
1430    
1431    
1432            @Override
1433            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1434                StackValue currentExtensionReceiver = extensionReceiver;
1435                boolean hasExtensionReceiver = extensionReceiver != none();
1436                if (extensionReceiver instanceof StackValue.SafeCall) {
1437                    currentExtensionReceiver.put(currentExtensionReceiver.type, v);
1438                    currentExtensionReceiver = StackValue.onStack(currentExtensionReceiver.type);
1439                }
1440    
1441                dispatchReceiver.put(hasExtensionReceiver ? dispatchReceiver.type : type, v);
1442    
1443                currentExtensionReceiver
1444                        .moveToTopOfStack(hasExtensionReceiver ? type : currentExtensionReceiver.type, v, dispatchReceiver.type.getSize());
1445            }
1446        }
1447    
1448        public abstract static class StackValueWithSimpleReceiver extends StackValue {
1449    
1450            public final boolean isStaticPut;
1451    
1452            public final boolean isStaticStore;
1453            @NotNull
1454            public final StackValue receiver;
1455    
1456            public StackValueWithSimpleReceiver(
1457                    @NotNull Type type,
1458                    boolean isStaticPut,
1459                    boolean isStaticStore,
1460                    @NotNull StackValue receiver,
1461                    boolean canHaveSideEffects
1462            ) {
1463                super(type, canHaveSideEffects);
1464                this.receiver = receiver;
1465                this.isStaticPut = isStaticPut;
1466                this.isStaticStore = isStaticStore;
1467            }
1468    
1469            @Override
1470            public void putReceiver(@NotNull InstructionAdapter v, boolean isRead) {
1471                boolean hasReceiver = isNonStaticAccess(isRead);
1472                if (hasReceiver || receiver.canHaveSideEffects()) {
1473                    receiver.put(hasReceiver ? receiver.type : Type.VOID_TYPE, v);
1474                }
1475            }
1476    
1477            @Override
1478            public boolean isNonStaticAccess(boolean isRead) {
1479                return isRead ? !isStaticPut : !isStaticStore;
1480            }
1481    
1482            public int receiverSize() {
1483                return receiver.type.getSize();
1484            }
1485    
1486            @Override
1487            public void dup(@NotNull InstructionAdapter v, boolean withWriteReceiver) {
1488                if (!withWriteReceiver) {
1489                    super.dup(v, false);
1490                }
1491                else {
1492                    int receiverSize = isNonStaticAccess(false) ? receiverSize() : 0;
1493                    switch (receiverSize) {
1494                        case 0:
1495                            AsmUtil.dup(v, type);
1496                            break;
1497    
1498                        case 1:
1499                            if (type.getSize() == 2) {
1500                                v.dup2X1();
1501                            }
1502                            else {
1503                                v.dupX1();
1504                            }
1505                            break;
1506    
1507                        case 2:
1508                            if (type.getSize() == 2) {
1509                                v.dup2X2();
1510                            }
1511                            else {
1512                                v.dupX2();
1513                            }
1514                            break;
1515    
1516                        case -1:
1517                            throw new UnsupportedOperationException();
1518                    }
1519                }
1520            }
1521    
1522            @Override
1523            public void store(
1524                    @NotNull StackValue rightSide, @NotNull InstructionAdapter v, boolean skipReceiver
1525            ) {
1526                if (!skipReceiver) {
1527                    putReceiver(v, false);
1528                }
1529                rightSide.put(rightSide.type, v);
1530                storeSelector(rightSide.type, v);
1531            }
1532        }
1533    
1534        private static class ComplexReceiver extends StackValue {
1535    
1536            private final StackValueWithSimpleReceiver originalValueWithReceiver;
1537            private final boolean[] isReadOperations;
1538    
1539            public ComplexReceiver(StackValueWithSimpleReceiver value, boolean[] isReadOperations) {
1540                super(value.type, value.receiver.canHaveSideEffects());
1541                this.originalValueWithReceiver = value;
1542                this.isReadOperations = isReadOperations;
1543            }
1544    
1545            @Override
1546            public void putSelector(
1547                    @NotNull Type type, @NotNull InstructionAdapter v
1548            ) {
1549                boolean wasPut = false;
1550                StackValue receiver = originalValueWithReceiver.receiver;
1551                for (boolean operation : isReadOperations) {
1552                    if (originalValueWithReceiver.isNonStaticAccess(operation)) {
1553                        if (!wasPut) {
1554                            receiver.put(receiver.type, v);
1555                            wasPut = true;
1556                        }
1557                        else {
1558                            receiver.dup(v, false);
1559                        }
1560                    }
1561                }
1562    
1563                if (!wasPut && receiver.canHaveSideEffects()) {
1564                    receiver.put(Type.VOID_TYPE, v);
1565                }
1566            }
1567        }
1568    
1569        public static class Receiver extends StackValue {
1570    
1571            private final StackValue[] instructions;
1572    
1573            protected Receiver(@NotNull Type type, StackValue... receiverInstructions) {
1574                super(type);
1575                instructions = receiverInstructions;
1576            }
1577    
1578            @Override
1579            public void putSelector(
1580                    @NotNull Type type, @NotNull InstructionAdapter v
1581            ) {
1582                for (StackValue instruction : instructions) {
1583                    instruction.put(instruction.type, v);
1584                }
1585            }
1586        }
1587    
1588        public static class DelegatedForComplexReceiver extends StackValueWithSimpleReceiver {
1589    
1590            public final StackValueWithSimpleReceiver originalValue;
1591    
1592            public DelegatedForComplexReceiver(
1593                    @NotNull Type type,
1594                    @NotNull StackValueWithSimpleReceiver originalValue,
1595                    @NotNull ComplexReceiver receiver
1596            ) {
1597                super(type, bothReceiverStatic(originalValue), bothReceiverStatic(originalValue), receiver, originalValue.canHaveSideEffects());
1598                this.originalValue = originalValue;
1599            }
1600    
1601            private static boolean bothReceiverStatic(StackValueWithSimpleReceiver originalValue) {
1602                return !(originalValue.isNonStaticAccess(true) || originalValue.isNonStaticAccess(false));
1603            }
1604    
1605            @Override
1606            public void putSelector(
1607                    @NotNull Type type, @NotNull InstructionAdapter v
1608            ) {
1609                originalValue.putSelector(type, v);
1610            }
1611    
1612            @Override
1613            public void storeSelector(
1614                    @NotNull Type topOfStackType, @NotNull InstructionAdapter v
1615            ) {
1616                originalValue.storeSelector(topOfStackType, v);
1617            }
1618    
1619            @Override
1620            public void dup(@NotNull InstructionAdapter v, boolean withWriteReceiver) {
1621                originalValue.dup(v, withWriteReceiver);
1622            }
1623        }
1624    
1625        public static StackValue complexWriteReadReceiver(StackValue stackValue) {
1626            return complexReceiver(stackValue, false, true);
1627        }
1628    
1629        private static StackValue complexReceiver(StackValue stackValue, boolean... isReadOperations) {
1630            if (stackValue instanceof StackValueWithSimpleReceiver) {
1631                return new DelegatedForComplexReceiver(stackValue.type, (StackValueWithSimpleReceiver) stackValue,
1632                                     new ComplexReceiver((StackValueWithSimpleReceiver) stackValue, isReadOperations));
1633            }
1634            else {
1635                return stackValue;
1636            }
1637        }
1638    
1639        static class SafeCall extends StackValue {
1640    
1641            @NotNull private final Type type;
1642            private final StackValue receiver;
1643            @Nullable private final Label ifNull;
1644    
1645            public SafeCall(@NotNull Type type, @NotNull StackValue value, @Nullable Label ifNull) {
1646                super(type);
1647                this.type = type;
1648                this.receiver = value;
1649                this.ifNull = ifNull;
1650            }
1651    
1652            @Override
1653            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1654                receiver.put(this.type, v);
1655                if (ifNull != null) {
1656                    //not a primitive
1657                    v.dup();
1658                    v.ifnull(ifNull);
1659                }
1660                coerceTo(type, v);
1661            }
1662        }
1663    
1664        static class SafeFallback extends StackValueWithSimpleReceiver {
1665    
1666            @Nullable private final Label ifNull;
1667    
1668            public SafeFallback(@NotNull Type type, @Nullable Label ifNull, StackValue receiver) {
1669                super(type, false, false, receiver, true);
1670                this.ifNull = ifNull;
1671            }
1672    
1673            @Override
1674            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1675                Label end = new Label();
1676    
1677                v.goTo(end);
1678                v.mark(ifNull);
1679                v.pop();
1680                if (!this.type.equals(Type.VOID_TYPE)) {
1681                    v.aconst(null);
1682                }
1683                v.mark(end);
1684    
1685                coerceTo(type, v);
1686            }
1687    
1688            @Override
1689            public void store(
1690                    @NotNull StackValue rightSide, @NotNull InstructionAdapter v, boolean skipReceiver
1691            ) {
1692                receiver.store(rightSide, v, skipReceiver);
1693    
1694                Label end = new Label();
1695                v.goTo(end);
1696                v.mark(ifNull);
1697                v.pop();
1698                v.mark(end);
1699            }
1700        }
1701    }
1702