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