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