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