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