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