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.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                Type unboxedType = unboxPrimitiveTypeOrNull(fromType);
398                if (unboxedType != null) {
399                    unbox(unboxedType, v);
400                    coerce(unboxedType, toType, v);
401                }
402                else {
403                    if (toType.getSort() == Type.BOOLEAN || toType.getSort() == Type.CHAR) {
404                        coerce(fromType, boxType(toType), v);
405                    }
406                    else {
407                        coerce(fromType, getType(Number.class), v);
408                    }
409                    unbox(toType, v);
410                }
411            }
412            else {
413                v.cast(fromType, toType);
414            }
415        }
416    
417        public static void putUnitInstance(@NotNull InstructionAdapter v) {
418            unit().put(UNIT_TYPE, v);
419        }
420    
421        public static StackValue unit() {
422            return UNIT;
423        }
424    
425        public static StackValue none() {
426            return None.INSTANCE;
427        }
428    
429        public static Field receiverWithRefWrapper(
430                @NotNull Type localType,
431                @NotNull Type classType,
432                @NotNull String fieldName,
433                @NotNull StackValue receiver,
434                @Nullable DeclarationDescriptor descriptor
435        ) {
436            return field(sharedTypeForType(localType), classType, fieldName, false, receiver, descriptor);
437        }
438    
439        public static FieldForSharedVar fieldForSharedVar(
440                @NotNull Type localType,
441                @NotNull Type classType,
442                @NotNull String fieldName,
443                @NotNull Field refWrapper
444        ) {
445            return new FieldForSharedVar(localType, classType, fieldName, refWrapper);
446        }
447    
448        @NotNull
449        public static FieldForSharedVar fieldForSharedVar(@NotNull FieldForSharedVar field, @NotNull StackValue newReceiver) {
450            Field oldReceiver = (Field) field.receiver;
451            Field newSharedVarReceiver = field(oldReceiver, newReceiver);
452            return new FieldForSharedVar(field.type, field.owner, field.name, newSharedVarReceiver);
453        }
454    
455        public static StackValue coercion(@NotNull StackValue value, @NotNull Type castType) {
456            if (value.type.equals(castType)) {
457                return value;
458            }
459            return new CoercionValue(value, castType);
460        }
461    
462        @NotNull
463        public static StackValue thisOrOuter(
464                @NotNull ExpressionCodegen codegen,
465                @NotNull ClassDescriptor descriptor,
466                boolean isSuper,
467                boolean castReceiver
468        ) {
469            // Coerce 'this' for the case when it is smart cast.
470            // Do not coerce for other cases due to the 'protected' access issues (JVMS 7, 4.9.2 Structural Constraints).
471            boolean coerceType = descriptor.getKind() == ClassKind.INTERFACE || (castReceiver && !isSuper);
472            return new ThisOuter(codegen, descriptor, isSuper, coerceType);
473        }
474    
475        public static StackValue postIncrement(int index, int increment) {
476            return new PostIncrement(index, increment);
477        }
478    
479        public static StackValue preIncrementForLocalVar(int index, int increment) {
480            return new PreIncrementForLocalVar(index, increment);
481        }
482    
483        public static StackValue preIncrement(
484                @NotNull Type type,
485                @NotNull StackValue stackValue,
486                int delta,
487                ResolvedCall resolvedCall,
488                @NotNull ExpressionCodegen codegen
489        ) {
490            if (stackValue instanceof StackValue.Local && Type.INT_TYPE == stackValue.type) {
491                return preIncrementForLocalVar(((StackValue.Local) stackValue).index, delta);
492            }
493            return new PrefixIncrement(type, stackValue, resolvedCall, codegen);
494        }
495    
496        public static StackValue receiver(
497                ResolvedCall<?> resolvedCall,
498                StackValue receiver,
499                ExpressionCodegen codegen,
500                @Nullable Callable callableMethod
501        ) {
502            ReceiverValue callDispatchReceiver = resolvedCall.getDispatchReceiver();
503            CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
504            if (descriptor instanceof SyntheticFieldDescriptor) {
505                callDispatchReceiver = ((SyntheticFieldDescriptor) descriptor).getDispatchReceiverForBackend();
506            }
507    
508            ReceiverValue callExtensionReceiver = resolvedCall.getExtensionReceiver();
509            if (callDispatchReceiver != null || callExtensionReceiver != null
510                || isLocalFunCall(callableMethod) || isCallToMemberObjectImportedByName(resolvedCall)) {
511                ReceiverParameterDescriptor dispatchReceiverParameter = descriptor.getDispatchReceiverParameter();
512                ReceiverParameterDescriptor extensionReceiverParameter = descriptor.getExtensionReceiverParameter();
513    
514                if (descriptor.getOriginal() instanceof SamAdapterExtensionFunctionDescriptor) {
515                    callDispatchReceiver = callExtensionReceiver;
516                    callExtensionReceiver = null;
517                    dispatchReceiverParameter = extensionReceiverParameter;
518                    extensionReceiverParameter = null;
519                }
520                else if (descriptor instanceof SyntheticFieldDescriptor) {
521                    dispatchReceiverParameter = ((SyntheticFieldDescriptor) descriptor).getDispatchReceiverParameterForBackend();
522                }
523    
524                boolean hasExtensionReceiver = callExtensionReceiver != null;
525                StackValue dispatchReceiver = platformStaticCallIfPresent(
526                        genReceiver(hasExtensionReceiver ? none() : receiver, codegen, resolvedCall, callableMethod, callDispatchReceiver, false),
527                        descriptor
528                );
529                StackValue extensionReceiver = genReceiver(receiver, codegen, resolvedCall, callableMethod, callExtensionReceiver, true);
530                Type type = CallReceiver.calcType(resolvedCall, dispatchReceiverParameter, extensionReceiverParameter, codegen.typeMapper, callableMethod, codegen.getState());
531                assert type != null : "Could not map receiver type for " + resolvedCall;
532                return new CallReceiver(dispatchReceiver, extensionReceiver, type);
533            }
534            return receiver;
535        }
536    
537        private static StackValue genReceiver(
538                @NotNull StackValue receiver,
539                @NotNull ExpressionCodegen codegen,
540                @NotNull ResolvedCall resolvedCall,
541                @Nullable Callable callableMethod,
542                @Nullable ReceiverValue receiverValue,
543                boolean isExtension
544        ) {
545            if (receiver == none()) {
546                if (receiverValue != null) {
547                    return codegen.generateReceiverValue(receiverValue, false);
548                }
549                else if (isLocalFunCall(callableMethod) && !isExtension) {
550                    StackValue value = codegen.findLocalOrCapturedValue(resolvedCall.getResultingDescriptor().getOriginal());
551                    assert value != null : "Local fun should be found in locals or in captured params: " + resolvedCall;
552                    return value;
553                }
554                else if (isCallToMemberObjectImportedByName(resolvedCall)) {
555                    return singleton(((ImportedFromObjectCallableDescriptor) resolvedCall.getResultingDescriptor()).getContainingObject(), codegen.typeMapper);
556                }
557            }
558            else if (receiverValue != null) {
559                return receiver;
560            }
561            return none();
562        }
563    
564        private static boolean isCallToMemberObjectImportedByName(@NotNull ResolvedCall resolvedCall) {
565            return resolvedCall.getResultingDescriptor() instanceof ImportedFromObjectCallableDescriptor;
566        }
567    
568        private static StackValue platformStaticCallIfPresent(@NotNull StackValue resultReceiver, @NotNull CallableDescriptor descriptor) {
569            if (AnnotationUtilKt.isPlatformStaticInObjectOrClass(descriptor)) {
570                if (resultReceiver.canHaveSideEffects()) {
571                    return coercion(resultReceiver, Type.VOID_TYPE);
572                }
573                else {
574                    return none();
575                }
576            }
577            return resultReceiver;
578        }
579    
580        @Contract("null -> false")
581        private static boolean isLocalFunCall(@Nullable Callable callableMethod) {
582            return callableMethod != null && callableMethod.getGenerateCalleeType() != null;
583        }
584    
585        public static StackValue receiverWithoutReceiverArgument(StackValue receiverWithParameter) {
586            if (receiverWithParameter instanceof CallReceiver) {
587                CallReceiver callReceiver = (CallReceiver) receiverWithParameter;
588                return new CallReceiver(callReceiver.dispatchReceiver, none(), callReceiver.type);
589            }
590            return receiverWithParameter;
591        }
592    
593        @NotNull
594        public static Field enumEntry(@NotNull ClassDescriptor descriptor, @NotNull KotlinTypeMapper typeMapper) {
595            DeclarationDescriptor enumClass = descriptor.getContainingDeclaration();
596            assert DescriptorUtils.isEnumClass(enumClass) : "Enum entry should be declared in enum class: " + descriptor;
597            Type type = typeMapper.mapType((ClassDescriptor) enumClass);
598            return field(type, type, descriptor.getName().asString(), true, none(), descriptor);
599        }
600    
601        @NotNull
602        public static Field singleton(@NotNull ClassDescriptor classDescriptor, @NotNull KotlinTypeMapper typeMapper) {
603            return field(FieldInfo.createForSingleton(classDescriptor, typeMapper), none());
604        }
605    
606        public static Field singletonViaInstance(ClassDescriptor classDescriptor, KotlinTypeMapper typeMapper) {
607            return field(FieldInfo.createSingletonViaInstance(classDescriptor, typeMapper), none());
608        }
609    
610        public static StackValue operation(Type type, Function1<InstructionAdapter, Unit> lambda) {
611            return new OperationStackValue(type, lambda);
612        }
613    
614        public static StackValue functionCall(Type type, Function1<InstructionAdapter, Unit> lambda) {
615            return new FunctionCallStackValue(type, lambda);
616        }
617    
618        public static boolean couldSkipReceiverOnStaticCall(StackValue value) {
619            return value instanceof Local || value instanceof Constant;
620        }
621    
622        private static class None extends StackValue {
623            public static final None INSTANCE = new None();
624    
625            private None() {
626                super(Type.VOID_TYPE, false);
627            }
628    
629            @Override
630            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
631                coerceTo(type, v);
632            }
633        }
634    
635        public static class Local extends StackValue {
636            public final int index;
637    
638            private Local(int index, Type type) {
639                super(type, false);
640                this.index = index;
641    
642                if (index < 0) {
643                    throw new IllegalStateException("local variable index must be non-negative");
644                }
645            }
646    
647            @Override
648            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
649                v.load(index, this.type);
650                coerceTo(type, v);
651                // TODO unbox
652            }
653    
654            @Override
655            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
656                coerceFrom(topOfStackType, v);
657                v.store(index, this.type);
658            }
659        }
660    
661        public static class OnStack extends StackValue {
662            public OnStack(Type type) {
663                super(type);
664            }
665    
666            @Override
667            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
668                coerceTo(type, v);
669            }
670    
671            @Override
672            public void moveToTopOfStack(@NotNull Type type, @NotNull InstructionAdapter v, int depth) {
673                if (depth == 0) {
674                    put(type, v);
675                }
676                else if (depth == 1) {
677                    int size = this.type.getSize();
678                    if (size == 1) {
679                        v.swap();
680                    }
681                    else if (size == 2) {
682                        v.dupX2();
683                        v.pop();
684                    }
685                    else {
686                        throw new UnsupportedOperationException("don't know how to move type " + type + " to top of stack");
687                    }
688    
689                    coerceTo(type, v);
690                }
691                else if (depth == 2) {
692                    int size = this.type.getSize();
693                    if (size == 1) {
694                        v.dup2X1();
695                        v.pop2();
696                    }
697                    else if (size == 2) {
698                        v.dup2X2();
699                        v.pop2();
700                    }
701                    else {
702                        throw new UnsupportedOperationException("don't know how to move type " + type + " to top of stack");
703                    }
704    
705                    coerceTo(type, v);
706                }
707                else {
708                    throw new UnsupportedOperationException("unsupported move-to-top depth " + depth);
709                }
710            }
711        }
712    
713        private static class Constant extends StackValue {
714            @Nullable
715            private final Object value;
716    
717            public Constant(@Nullable Object value, Type type) {
718                super(type, false);
719                assert !Type.BOOLEAN_TYPE.equals(type) : "Boolean constants should be created via 'StackValue.constant'";
720                this.value = value;
721            }
722    
723            @Override
724            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
725                if (value instanceof Integer || value instanceof Byte || value instanceof Short) {
726                    v.iconst(((Number) value).intValue());
727                }
728                else if (value instanceof Character) {
729                    v.iconst(((Character) value).charValue());
730                }
731                else if (value instanceof Long) {
732                    v.lconst((Long) value);
733                }
734                else if (value instanceof Float) {
735                    v.fconst((Float) value);
736                }
737                else if (value instanceof Double) {
738                    v.dconst((Double) value);
739                }
740                else {
741                    v.aconst(value);
742                }
743    
744                coerceTo(type, v);
745            }
746        }
747    
748        private static class ArrayElement extends StackValueWithSimpleReceiver {
749            private final Type type;
750    
751            public ArrayElement(Type type, StackValue array, StackValue index) {
752                super(type, false, false, new Receiver(Type.LONG_TYPE, array, index), true);
753                this.type = type;
754            }
755    
756            @Override
757            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
758                coerceFrom(topOfStackType, v);
759                v.astore(this.type);
760            }
761    
762            @Override
763            public int receiverSize() {
764                return 2;
765            }
766    
767            @Override
768            public void putSelector(
769                    @NotNull Type type, @NotNull InstructionAdapter v
770            ) {
771                v.aload(this.type);    // assumes array and index are on the stack
772                coerceTo(type, v);
773            }
774        }
775    
776        public static class CollectionElementReceiver extends StackValue {
777            private final Callable callable;
778            private final boolean isGetter;
779            private final ExpressionCodegen codegen;
780            private final List<ResolvedValueArgument> valueArguments;
781            private final FrameMap frame;
782            private final StackValue receiver;
783            private final ResolvedCall<FunctionDescriptor> resolvedGetCall;
784            private final ResolvedCall<FunctionDescriptor> resolvedSetCall;
785            private DefaultCallArgs defaultArgs;
786            private CallGenerator callGenerator;
787            boolean isComplexOperationWithDup;
788    
789            public CollectionElementReceiver(
790                    @NotNull Callable callable,
791                    @NotNull StackValue receiver,
792                    ResolvedCall<FunctionDescriptor> resolvedGetCall,
793                    ResolvedCall<FunctionDescriptor> resolvedSetCall,
794                    boolean isGetter,
795                    @NotNull ExpressionCodegen codegen,
796                    List<ResolvedValueArgument> valueArguments
797            ) {
798                super(OBJECT_TYPE);
799                this.callable = callable;
800    
801                this.isGetter = isGetter;
802                this.receiver = receiver;
803                this.resolvedGetCall = resolvedGetCall;
804                this.resolvedSetCall = resolvedSetCall;
805                this.valueArguments = valueArguments;
806                this.codegen = codegen;
807                this.frame = codegen.myFrameMap;
808            }
809    
810            @Override
811            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
812                ResolvedCall<?> call = isGetter ? resolvedGetCall : resolvedSetCall;
813                StackValue newReceiver = StackValue.receiver(call, receiver, codegen, callable);
814                ArgumentGenerator generator = createArgumentGenerator();
815                newReceiver.put(newReceiver.type, v);
816                callGenerator.putHiddenParams();
817    
818                defaultArgs = generator.generate(valueArguments, valueArguments);
819            }
820    
821            private ArgumentGenerator createArgumentGenerator() {
822                assert callGenerator == null :
823                        "'putSelector' and 'createArgumentGenerator' methods should be called once for CollectionElementReceiver: " + callable;
824                ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall;
825                assert resolvedCall != null : "Resolved call should be non-null: " + callable;
826                callGenerator =
827                        !isComplexOperationWithDup ? codegen.getOrCreateCallGenerator(resolvedCall) : codegen.defaultCallGenerator;
828                return new CallBasedArgumentGenerator(
829                        codegen,
830                        callGenerator,
831                        resolvedCall.getResultingDescriptor().getValueParameters(), callable.getValueParameterTypes()
832                );
833            }
834    
835            @Override
836            public void dup(@NotNull InstructionAdapter v, boolean withReceiver) {
837                dupReceiver(v);
838            }
839    
840            public void dupReceiver(@NotNull InstructionAdapter v) {
841                if (CollectionElement.isStandardStack(codegen.typeMapper, resolvedGetCall, 1) &&
842                    CollectionElement.isStandardStack(codegen.typeMapper, resolvedSetCall, 2)) {
843                    v.dup2();   // collection and index
844                    return;
845                }
846    
847                FrameMap.Mark mark = frame.mark();
848    
849                // indexes
850                List<ValueParameterDescriptor> valueParameters = resolvedGetCall.getResultingDescriptor().getValueParameters();
851                int firstParamIndex = -1;
852                for (int i = valueParameters.size() - 1; i >= 0; --i) {
853                    Type type = codegen.typeMapper.mapType(valueParameters.get(i).getType());
854                    firstParamIndex = frame.enterTemp(type);
855                    v.store(firstParamIndex, type);
856                }
857    
858                ReceiverValue receiverParameter = resolvedGetCall.getExtensionReceiver();
859                int receiverIndex = -1;
860                if (receiverParameter != null) {
861                    Type type = codegen.typeMapper.mapType(receiverParameter.getType());
862                    receiverIndex = frame.enterTemp(type);
863                    v.store(receiverIndex, type);
864                }
865    
866                ReceiverValue dispatchReceiver = resolvedGetCall.getDispatchReceiver();
867                int thisIndex = -1;
868                if (dispatchReceiver != null) {
869                    thisIndex = frame.enterTemp(OBJECT_TYPE);
870                    v.store(thisIndex, OBJECT_TYPE);
871                }
872    
873                // for setter
874    
875                int realReceiverIndex;
876                Type realReceiverType;
877                if (receiverIndex != -1) {
878                    realReceiverType = codegen.typeMapper.mapType(receiverParameter.getType());
879                    realReceiverIndex = receiverIndex;
880                }
881                else if (thisIndex != -1) {
882                    realReceiverType = OBJECT_TYPE;
883                    realReceiverIndex = thisIndex;
884                }
885                else {
886                    throw new UnsupportedOperationException();
887                }
888    
889                if (resolvedSetCall.getDispatchReceiver() != null) {
890                    if (resolvedSetCall.getExtensionReceiver() != null) {
891                        codegen.generateReceiverValue(resolvedSetCall.getDispatchReceiver(), false).put(OBJECT_TYPE, v);
892                    }
893                    v.load(realReceiverIndex, realReceiverType);
894                }
895                else {
896                    if (resolvedSetCall.getExtensionReceiver() != null) {
897                        v.load(realReceiverIndex, realReceiverType);
898                    }
899                    else {
900                        throw new UnsupportedOperationException();
901                    }
902                }
903    
904                int index = firstParamIndex;
905                for (ValueParameterDescriptor valueParameter : valueParameters) {
906                    Type type = codegen.typeMapper.mapType(valueParameter.getType());
907                    v.load(index, type);
908                    index -= type.getSize();
909                }
910    
911                // restoring original
912                if (thisIndex != -1) {
913                    v.load(thisIndex, OBJECT_TYPE);
914                }
915    
916                if (receiverIndex != -1) {
917                    v.load(receiverIndex, realReceiverType);
918                }
919    
920                index = firstParamIndex;
921                for (ValueParameterDescriptor valueParameter : valueParameters) {
922                    Type type = codegen.typeMapper.mapType(valueParameter.getType());
923                    v.load(index, type);
924                    index -= type.getSize();
925                }
926    
927                mark.dropTo();
928            }
929        }
930    
931        public static class CollectionElement extends StackValueWithSimpleReceiver {
932            private final Callable getter;
933            private final Callable setter;
934            private final ExpressionCodegen codegen;
935            private final ResolvedCall<FunctionDescriptor> resolvedGetCall;
936            private final ResolvedCall<FunctionDescriptor> resolvedSetCall;
937    
938            public CollectionElement(
939                    @NotNull CollectionElementReceiver collectionElementReceiver,
940                    @NotNull Type type,
941                    @Nullable ResolvedCall<FunctionDescriptor> resolvedGetCall,
942                    @Nullable ResolvedCall<FunctionDescriptor> resolvedSetCall,
943                    @NotNull ExpressionCodegen codegen
944            ) {
945                super(type, false, false, collectionElementReceiver, true);
946                this.resolvedGetCall = resolvedGetCall;
947                this.resolvedSetCall = resolvedSetCall;
948                this.setter = resolvedSetCall == null ? null :
949                              codegen.resolveToCallable(codegen.accessibleFunctionDescriptor(resolvedSetCall), false, resolvedSetCall);
950                this.getter = resolvedGetCall == null ? null :
951                              codegen.resolveToCallable(codegen.accessibleFunctionDescriptor(resolvedGetCall), false, resolvedGetCall);
952                this.codegen = codegen;
953            }
954    
955            @Override
956            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
957                if (getter == null) {
958                    throw new UnsupportedOperationException("no getter specified");
959                }
960                CallGenerator callGenerator = getCallGenerator();
961                callGenerator.genCall(getter, resolvedGetCall, genDefaultMaskIfPresent(callGenerator), codegen);
962                coerceTo(type, v);
963            }
964    
965            private boolean genDefaultMaskIfPresent(CallGenerator callGenerator) {
966                DefaultCallArgs defaultArgs = ((CollectionElementReceiver) receiver).defaultArgs;
967                return defaultArgs.generateOnStackIfNeeded(callGenerator, true);
968            }
969    
970            private CallGenerator getCallGenerator() {
971                CallGenerator generator = ((CollectionElementReceiver) receiver).callGenerator;
972                assert generator != null :
973                        "CollectionElementReceiver should be putted on stack before CollectionElement:" +
974                        " getCall = " + resolvedGetCall + ",  setCall = " + resolvedSetCall;
975                return generator;
976            }
977    
978            @Override
979            public int receiverSize() {
980                if (isStandardStack(codegen.typeMapper, resolvedGetCall, 1) && isStandardStack(codegen.typeMapper, resolvedSetCall, 2)) {
981                    return 2;
982                }
983                else {
984                    return -1;
985                }
986            }
987    
988            public static boolean isStandardStack(@NotNull KotlinTypeMapper typeMapper, @Nullable ResolvedCall<?> call, int valueParamsSize) {
989                if (call == null) {
990                    return true;
991                }
992    
993                List<ValueParameterDescriptor> valueParameters = call.getResultingDescriptor().getValueParameters();
994                if (valueParameters.size() != valueParamsSize) {
995                    return false;
996                }
997    
998                for (ValueParameterDescriptor valueParameter : valueParameters) {
999                    if (typeMapper.mapType(valueParameter.getType()).getSize() != 1) {
1000                        return false;
1001                    }
1002                }
1003    
1004                if (call.getDispatchReceiver() != null) {
1005                    if (call.getExtensionReceiver() != null) {
1006                        return false;
1007                    }
1008                }
1009                else {
1010                    //noinspection ConstantConditions
1011                    if (typeMapper.mapType(call.getResultingDescriptor().getExtensionReceiverParameter().getType()).getSize() != 1) {
1012                        return false;
1013                    }
1014                }
1015    
1016                return true;
1017            }
1018    
1019            @Override
1020            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1021                if (setter == null) {
1022                    throw new UnsupportedOperationException("no setter specified");
1023                }
1024    
1025                Type lastParameterType = ArraysKt.last(setter.getParameterTypes());
1026                coerce(topOfStackType, lastParameterType, v);
1027    
1028                getCallGenerator().afterParameterPut(lastParameterType, StackValue.onStack(lastParameterType),
1029                                                     CollectionsKt.getLastIndex(setter.getValueParameterTypes()));
1030    
1031                //Convention setter couldn't have default parameters, just getter can have it at last positions
1032                //We should remove default parameters of getter from stack*/
1033                //Note that it works only for non-inline case
1034                CollectionElementReceiver collectionElementReceiver = (CollectionElementReceiver) receiver;
1035                if (collectionElementReceiver.isGetter) {
1036                    List<ResolvedValueArgument> arguments = collectionElementReceiver.valueArguments;
1037                    List<Type> types = getter.getValueParameterTypes();
1038                    for (int i = arguments.size() - 1; i >= 0; i--) {
1039                        ResolvedValueArgument argument = arguments.get(i);
1040                        if (argument instanceof DefaultValueArgument) {
1041                            Type defaultType = types.get(i);
1042                            AsmUtil.swap(v, lastParameterType, defaultType);
1043                            AsmUtil.pop(v, defaultType);
1044                        }
1045                    }
1046                }
1047    
1048                getCallGenerator().genCall(setter, resolvedSetCall, false, codegen);
1049                Type returnType = setter.getReturnType();
1050                if (returnType != Type.VOID_TYPE) {
1051                    pop(v, returnType);
1052                }
1053            }
1054        }
1055    
1056    
1057        public static class Field extends StackValueWithSimpleReceiver {
1058            public final Type owner;
1059            public final String name;
1060            public final DeclarationDescriptor descriptor;
1061    
1062            public Field(
1063                    @NotNull Type type,
1064                    @NotNull Type owner,
1065                    @NotNull String name,
1066                    boolean isStatic,
1067                    @NotNull StackValue receiver,
1068                    @Nullable DeclarationDescriptor descriptor
1069            ) {
1070                super(type, isStatic, isStatic, receiver, receiver.canHaveSideEffects());
1071                this.owner = owner;
1072                this.name = name;
1073                this.descriptor = descriptor;
1074            }
1075    
1076            @Override
1077            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1078                v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD, owner.getInternalName(), name, this.type.getDescriptor());
1079                coerceTo(type, v);
1080            }
1081    
1082            @Override
1083            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1084                coerceFrom(topOfStackType, v);
1085                v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, owner.getInternalName(), name, this.type.getDescriptor());
1086            }
1087        }
1088    
1089        static class Property extends StackValueWithSimpleReceiver {
1090            private final CallableMethod getter;
1091            private final CallableMethod setter;
1092            private final Type backingFieldOwner;
1093    
1094            private final PropertyDescriptor descriptor;
1095            private final GenerationState state;
1096    
1097            private final String fieldName;
1098    
1099            public Property(
1100                    @NotNull PropertyDescriptor descriptor, @Nullable Type backingFieldOwner,
1101                    @Nullable CallableMethod getter, @Nullable CallableMethod setter, boolean isStaticBackingField,
1102                    @Nullable String fieldName, @NotNull Type type, @NotNull GenerationState state,
1103                    @NotNull StackValue receiver
1104            ) {
1105                super(type, isStatic(isStaticBackingField, getter), isStatic(isStaticBackingField, setter), receiver, true);
1106                this.backingFieldOwner = backingFieldOwner;
1107                this.getter = getter;
1108                this.setter = setter;
1109                this.descriptor = descriptor;
1110                this.state = state;
1111                this.fieldName = fieldName;
1112            }
1113    
1114            @Override
1115            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1116                if (getter == null) {
1117                    assert fieldName != null : "Property should have either a getter or a field name: " + descriptor;
1118                    assert backingFieldOwner != null : "Property should have either a getter or a backingFieldOwner: " + descriptor;
1119                    if (inlineJavaConstantIfNeeded(type, v)) return;
1120    
1121                    v.visitFieldInsn(isStaticPut ? GETSTATIC : GETFIELD,
1122                                     backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
1123                    genNotNullAssertionForLateInitIfNeeded(v);
1124                    coerceTo(type, v);
1125                }
1126                else {
1127                    getter.genInvokeInstruction(v);
1128                    coerce(getter.getReturnType(), type, v);
1129    
1130                    KotlinType returnType = descriptor.getReturnType();
1131                    if (returnType != null && KotlinBuiltIns.isNothing(returnType)) {
1132                        v.aconst(null);
1133                        v.athrow();
1134                    }
1135                }
1136            }
1137    
1138            private boolean inlineJavaConstantIfNeeded(@NotNull Type type, @NotNull InstructionAdapter v) {
1139                if (!JvmCodegenUtil.isInlinedJavaConstProperty(descriptor)) return false;
1140    
1141                assert AsmUtil.isPrimitive(this.type) || AsmTypes.JAVA_STRING_TYPE.equals(this.type) :
1142                        "Java const property should have primitive or string type: " + descriptor;
1143                assert isStaticPut : "Java const property should be static" + descriptor;
1144    
1145                JavaPropertyDescriptor javaPropertyDescriptor = (JavaPropertyDescriptor) descriptor;
1146                ConstantValue<?> constantValue = javaPropertyDescriptor.getCompileTimeInitializer();
1147                if (constantValue == null) return false;
1148    
1149                Object value = constantValue.getValue();
1150                if (this.type == Type.FLOAT_TYPE && value instanceof Double) {
1151                    value = ((Double) value).floatValue();
1152                }
1153    
1154                StackValue.constant(value, this.type).putSelector(type, v);
1155    
1156                return true;
1157            }
1158    
1159            private void genNotNullAssertionForLateInitIfNeeded(@NotNull InstructionAdapter v) {
1160                if (!descriptor.isLateInit()) return;
1161    
1162                v.dup();
1163                Label ok = new Label();
1164                v.ifnonnull(ok);
1165                v.visitLdcInsn(descriptor.getName().asString());
1166                v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "throwUninitializedPropertyAccessException", "(Ljava/lang/String;)V", false);
1167                v.mark(ok);
1168            }
1169    
1170            @Override
1171            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1172                if (setter == null) {
1173                    coerceFrom(topOfStackType, v);
1174                    assert fieldName != null : "Property should have either a setter or a field name: " + descriptor;
1175                    assert backingFieldOwner != null : "Property should have either a setter or a backingFieldOwner: " + descriptor;
1176                    v.visitFieldInsn(isStaticStore ? PUTSTATIC : PUTFIELD, backingFieldOwner.getInternalName(), fieldName, this.type.getDescriptor());
1177                }
1178                else {
1179                    coerce(topOfStackType, ArraysKt.last(setter.getParameterTypes()), v);
1180                    setter.genInvokeInstruction(v);
1181    
1182                    Type returnType = setter.getReturnType();
1183                    if (returnType != Type.VOID_TYPE) {
1184                        pop(v, returnType);
1185                    }
1186                }
1187            }
1188    
1189            private static boolean isStatic(boolean isStaticBackingField, @Nullable CallableMethod callable) {
1190                if (isStaticBackingField && callable == null) {
1191                    return true;
1192                }
1193    
1194                if (callable != null && callable.isStaticCall()) {
1195                    List<JvmMethodParameterSignature> parameters = callable.getValueParameters();
1196                    for (JvmMethodParameterSignature parameter : parameters) {
1197                        JvmMethodParameterKind kind = parameter.getKind();
1198                        if (kind == JvmMethodParameterKind.VALUE) {
1199                            break;
1200                        }
1201                        if (kind == JvmMethodParameterKind.RECEIVER || kind == JvmMethodParameterKind.THIS) {
1202                            return false;
1203                        }
1204                    }
1205                    return true;
1206                }
1207    
1208                return false;
1209            }
1210        }
1211    
1212        private static class Expression extends StackValue {
1213            private final KtExpression expression;
1214            private final ExpressionCodegen generator;
1215    
1216            public Expression(Type type, KtExpression expression, ExpressionCodegen generator) {
1217                super(type);
1218                this.expression = expression;
1219                this.generator = generator;
1220            }
1221    
1222            @Override
1223            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1224                generator.gen(expression, type);
1225            }
1226        }
1227    
1228        public static class Shared extends StackValueWithSimpleReceiver {
1229            private final int index;
1230    
1231            public Shared(int index, Type type) {
1232                super(type, false, false, local(index, OBJECT_TYPE), false);
1233                this.index = index;
1234            }
1235    
1236            public int getIndex() {
1237                return index;
1238            }
1239    
1240            @Override
1241            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1242                Type refType = refType(this.type);
1243                Type sharedType = sharedTypeForType(this.type);
1244                v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
1245                coerceFrom(refType, v);
1246                coerceTo(type, v);
1247            }
1248    
1249            @Override
1250            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1251                coerceFrom(topOfStackType, v);
1252                Type refType = refType(this.type);
1253                Type sharedType = sharedTypeForType(this.type);
1254                v.visitFieldInsn(PUTFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
1255            }
1256        }
1257    
1258        @NotNull
1259        public static Type sharedTypeForType(@NotNull Type type) {
1260            switch (type.getSort()) {
1261                case Type.OBJECT:
1262                case Type.ARRAY:
1263                    return OBJECT_REF_TYPE;
1264                default:
1265                    PrimitiveType primitiveType = AsmUtil.asmPrimitiveTypeToLangPrimitiveType(type);
1266                    if (primitiveType == null) throw new UnsupportedOperationException();
1267    
1268                    String typeName = primitiveType.getTypeName().getIdentifier();
1269                    return Type.getObjectType(REF_TYPE_PREFIX + typeName + "Ref");
1270            }
1271        }
1272    
1273        public static Type refType(Type type) {
1274            if (type.getSort() == Type.OBJECT || type.getSort() == Type.ARRAY) {
1275                return OBJECT_TYPE;
1276            }
1277    
1278            return type;
1279        }
1280    
1281        public static class FieldForSharedVar extends StackValueWithSimpleReceiver {
1282            final Type owner;
1283            final String name;
1284    
1285            public FieldForSharedVar(Type type, Type owner, String name, StackValue.Field receiver) {
1286                super(type, false, false, receiver, receiver.canHaveSideEffects());
1287                this.owner = owner;
1288                this.name = name;
1289            }
1290    
1291            @Override
1292            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1293                Type sharedType = sharedTypeForType(this.type);
1294                Type refType = refType(this.type);
1295                v.visitFieldInsn(GETFIELD, sharedType.getInternalName(), "element", refType.getDescriptor());
1296                coerceFrom(refType, v);
1297                coerceTo(type, v);
1298            }
1299    
1300            @Override
1301            public void storeSelector(@NotNull Type topOfStackType, @NotNull InstructionAdapter v) {
1302                coerceFrom(topOfStackType, v);
1303                v.visitFieldInsn(PUTFIELD, sharedTypeForType(type).getInternalName(), "element", refType(type).getDescriptor());
1304            }
1305        }
1306    
1307        private static class ThisOuter extends StackValue {
1308            private final ExpressionCodegen codegen;
1309            private final ClassDescriptor descriptor;
1310            private final boolean isSuper;
1311            private final boolean coerceType;
1312    
1313            public ThisOuter(ExpressionCodegen codegen, ClassDescriptor descriptor, boolean isSuper, boolean coerceType) {
1314                super(OBJECT_TYPE, false);
1315                this.codegen = codegen;
1316                this.descriptor = descriptor;
1317                this.isSuper = isSuper;
1318                this.coerceType = coerceType;
1319            }
1320    
1321            @Override
1322            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1323                StackValue stackValue = codegen.generateThisOrOuter(descriptor, isSuper);
1324                stackValue.put(coerceType ? type : stackValue.type, v);
1325            }
1326        }
1327    
1328        private static class PostIncrement extends StackValue {
1329            private final int index;
1330            private final int increment;
1331    
1332            public PostIncrement(int index, int increment) {
1333                super(Type.INT_TYPE);
1334                this.index = index;
1335                this.increment = increment;
1336            }
1337    
1338            @Override
1339            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1340                if (!type.equals(Type.VOID_TYPE)) {
1341                    v.load(index, Type.INT_TYPE);
1342                    coerceTo(type, v);
1343                }
1344                v.iinc(index, increment);
1345            }
1346        }
1347    
1348        private static class PreIncrementForLocalVar extends StackValue {
1349            private final int index;
1350            private final int increment;
1351    
1352            public PreIncrementForLocalVar(int index, int increment) {
1353                super(Type.INT_TYPE);
1354                this.index = index;
1355                this.increment = increment;
1356            }
1357    
1358            @Override
1359            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1360                v.iinc(index, increment);
1361                if (!type.equals(Type.VOID_TYPE)) {
1362                    v.load(index, Type.INT_TYPE);
1363                    coerceTo(type, v);
1364                }
1365            }
1366        }
1367    
1368        private static class PrefixIncrement extends StackValue {
1369            private final ResolvedCall resolvedCall;
1370            private final ExpressionCodegen codegen;
1371            private StackValue value;
1372    
1373            public PrefixIncrement(
1374                    @NotNull Type type,
1375                    @NotNull StackValue value,
1376                    ResolvedCall resolvedCall,
1377                    @NotNull ExpressionCodegen codegen
1378            ) {
1379                super(type);
1380                this.value = value;
1381                this.resolvedCall = resolvedCall;
1382                this.codegen = codegen;
1383            }
1384    
1385            @Override
1386            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1387                value = StackValue.complexReceiver(value, true, false, true);
1388                value.put(this.type, v);
1389    
1390                value.store(codegen.invokeFunction(resolvedCall, StackValue.onStack(this.type)), v, true);
1391    
1392                value.put(this.type, v, true);
1393                coerceTo(type, v);
1394            }
1395        }
1396    
1397        public static class CallReceiver extends StackValue {
1398            private final StackValue dispatchReceiver;
1399            private final StackValue extensionReceiver;
1400    
1401            public CallReceiver(
1402                    @NotNull StackValue dispatchReceiver,
1403                    @NotNull StackValue extensionReceiver,
1404                    @NotNull Type type
1405            ) {
1406                super(type, dispatchReceiver.canHaveSideEffects() || extensionReceiver.canHaveSideEffects());
1407                this.dispatchReceiver = dispatchReceiver;
1408                this.extensionReceiver = extensionReceiver;
1409            }
1410    
1411            @Nullable
1412            public static Type calcType(
1413                    @NotNull ResolvedCall<?> resolvedCall,
1414                    @Nullable ReceiverParameterDescriptor dispatchReceiver,
1415                    @Nullable ReceiverParameterDescriptor extensionReceiver,
1416                    @NotNull KotlinTypeMapper typeMapper,
1417                    @Nullable Callable callableMethod,
1418                    @NotNull GenerationState state
1419            ) {
1420                if (extensionReceiver != null) {
1421                    CallableDescriptor descriptor = resolvedCall.getCandidateDescriptor();
1422    
1423                    if (descriptor instanceof PropertyDescriptor &&
1424                        // hackaround: boxing changes behaviour of T.javaClass intrinsic
1425                        !(state.getIntrinsics().getIntrinsic((PropertyDescriptor) descriptor) instanceof JavaClassProperty)
1426                    ) {
1427                        ReceiverParameterDescriptor receiverCandidate = descriptor.getExtensionReceiverParameter();
1428                        assert receiverCandidate != null;
1429                        return typeMapper.mapType(receiverCandidate.getType());
1430                    }
1431    
1432                    return callableMethod != null ? callableMethod.getExtensionReceiverType() : typeMapper.mapType(extensionReceiver.getType());
1433                }
1434                else if (dispatchReceiver != null) {
1435                    CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
1436    
1437                    if (AnnotationUtilKt.isPlatformStaticInObjectOrClass(descriptor)) {
1438                        return Type.VOID_TYPE;
1439                    }
1440    
1441                    if (callableMethod != null) {
1442                        return callableMethod.getDispatchReceiverType();
1443                    }
1444    
1445                    // Extract the receiver from the resolved call, workarounding the fact that ResolvedCall#dispatchReceiver doesn't have
1446                    // all the needed information, for example there's no way to find out whether or not a smart cast was applied to the receiver.
1447                    DeclarationDescriptor container = descriptor.getContainingDeclaration();
1448                    if (container instanceof ClassDescriptor) {
1449                        return typeMapper.mapClass((ClassDescriptor) container);
1450                    }
1451    
1452                    return typeMapper.mapType(dispatchReceiver);
1453                }
1454                else if (isLocalFunCall(callableMethod)) {
1455                    return callableMethod.getGenerateCalleeType();
1456                }
1457    
1458                return Type.VOID_TYPE;
1459            }
1460    
1461            @Override
1462            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1463                StackValue currentExtensionReceiver = extensionReceiver;
1464                boolean hasExtensionReceiver = extensionReceiver != none();
1465                if (extensionReceiver instanceof StackValue.SafeCall) {
1466                    currentExtensionReceiver.put(currentExtensionReceiver.type, v);
1467                    currentExtensionReceiver = StackValue.onStack(currentExtensionReceiver.type);
1468                }
1469    
1470                dispatchReceiver.put(hasExtensionReceiver ? dispatchReceiver.type : type, v);
1471    
1472                currentExtensionReceiver
1473                        .moveToTopOfStack(hasExtensionReceiver ? type : currentExtensionReceiver.type, v, dispatchReceiver.type.getSize());
1474            }
1475    
1476            @Override
1477            public void dup(@NotNull InstructionAdapter v, boolean withReceiver) {
1478                AsmUtil.dup(v, extensionReceiver.type, dispatchReceiver.type);
1479            }
1480        }
1481    
1482        public abstract static class StackValueWithSimpleReceiver extends StackValue {
1483    
1484            public final boolean isStaticPut;
1485    
1486            public final boolean isStaticStore;
1487            @NotNull
1488            public final StackValue receiver;
1489    
1490            public StackValueWithSimpleReceiver(
1491                    @NotNull Type type,
1492                    boolean isStaticPut,
1493                    boolean isStaticStore,
1494                    @NotNull StackValue receiver,
1495                    boolean canHaveSideEffects
1496            ) {
1497                super(type, canHaveSideEffects);
1498                this.receiver = receiver;
1499                this.isStaticPut = isStaticPut;
1500                this.isStaticStore = isStaticStore;
1501            }
1502    
1503            @Override
1504            public void putReceiver(@NotNull InstructionAdapter v, boolean isRead) {
1505                boolean hasReceiver = isNonStaticAccess(isRead);
1506                if (hasReceiver || receiver.canHaveSideEffects()) {
1507                    receiver.put(hasReceiver ? receiver.type : Type.VOID_TYPE, v);
1508                }
1509            }
1510    
1511            @Override
1512            public boolean isNonStaticAccess(boolean isRead) {
1513                return isRead ? !isStaticPut : !isStaticStore;
1514            }
1515    
1516            public int receiverSize() {
1517                return receiver.type.getSize();
1518            }
1519    
1520            @Override
1521            public void dup(@NotNull InstructionAdapter v, boolean withWriteReceiver) {
1522                if (!withWriteReceiver) {
1523                    super.dup(v, false);
1524                }
1525                else {
1526                    int receiverSize = isNonStaticAccess(false) ? receiverSize() : 0;
1527                    switch (receiverSize) {
1528                        case 0:
1529                            AsmUtil.dup(v, type);
1530                            break;
1531    
1532                        case 1:
1533                            if (type.getSize() == 2) {
1534                                v.dup2X1();
1535                            }
1536                            else {
1537                                v.dupX1();
1538                            }
1539                            break;
1540    
1541                        case 2:
1542                            if (type.getSize() == 2) {
1543                                v.dup2X2();
1544                            }
1545                            else {
1546                                v.dupX2();
1547                            }
1548                            break;
1549    
1550                        case -1:
1551                            throw new UnsupportedOperationException();
1552                    }
1553                }
1554            }
1555    
1556            @Override
1557            public void store(
1558                    @NotNull StackValue rightSide, @NotNull InstructionAdapter v, boolean skipReceiver
1559            ) {
1560                if (!skipReceiver) {
1561                    putReceiver(v, false);
1562                }
1563                rightSide.put(rightSide.type, v);
1564                storeSelector(rightSide.type, v);
1565            }
1566        }
1567    
1568        private static class ComplexReceiver extends StackValue {
1569    
1570            private final StackValueWithSimpleReceiver originalValueWithReceiver;
1571            private final boolean[] isReadOperations;
1572    
1573            public ComplexReceiver(StackValueWithSimpleReceiver value, boolean[] isReadOperations) {
1574                super(value.type, value.receiver.canHaveSideEffects());
1575                this.originalValueWithReceiver = value;
1576                this.isReadOperations = isReadOperations;
1577                if (value instanceof CollectionElement) {
1578                    if (value.receiver instanceof CollectionElementReceiver) {
1579                        ((CollectionElementReceiver) value.receiver).isComplexOperationWithDup = true;
1580                    }
1581                }
1582            }
1583    
1584            @Override
1585            public void putSelector(
1586                    @NotNull Type type, @NotNull InstructionAdapter v
1587            ) {
1588                boolean wasPut = false;
1589                StackValue receiver = originalValueWithReceiver.receiver;
1590                for (boolean operation : isReadOperations) {
1591                    if (originalValueWithReceiver.isNonStaticAccess(operation)) {
1592                        if (!wasPut) {
1593                            receiver.put(receiver.type, v);
1594                            wasPut = true;
1595                        }
1596                        else {
1597                            receiver.dup(v, false);
1598                        }
1599                    }
1600                }
1601    
1602                if (!wasPut && receiver.canHaveSideEffects()) {
1603                    receiver.put(Type.VOID_TYPE, v);
1604                }
1605            }
1606        }
1607    
1608        public static class Receiver extends StackValue {
1609    
1610            private final StackValue[] instructions;
1611    
1612            protected Receiver(@NotNull Type type, StackValue... receiverInstructions) {
1613                super(type);
1614                instructions = receiverInstructions;
1615            }
1616    
1617            @Override
1618            public void putSelector(
1619                    @NotNull Type type, @NotNull InstructionAdapter v
1620            ) {
1621                for (StackValue instruction : instructions) {
1622                    instruction.put(instruction.type, v);
1623                }
1624            }
1625        }
1626    
1627        public static class DelegatedForComplexReceiver extends StackValueWithSimpleReceiver {
1628    
1629            public final StackValueWithSimpleReceiver originalValue;
1630    
1631            public DelegatedForComplexReceiver(
1632                    @NotNull Type type,
1633                    @NotNull StackValueWithSimpleReceiver originalValue,
1634                    @NotNull ComplexReceiver receiver
1635            ) {
1636                super(type, bothReceiverStatic(originalValue), bothReceiverStatic(originalValue), receiver, originalValue.canHaveSideEffects());
1637                this.originalValue = originalValue;
1638            }
1639    
1640            private static boolean bothReceiverStatic(StackValueWithSimpleReceiver originalValue) {
1641                return !(originalValue.isNonStaticAccess(true) || originalValue.isNonStaticAccess(false));
1642            }
1643    
1644            @Override
1645            public void putSelector(
1646                    @NotNull Type type, @NotNull InstructionAdapter v
1647            ) {
1648                originalValue.putSelector(type, v);
1649            }
1650    
1651            @Override
1652            public void storeSelector(
1653                    @NotNull Type topOfStackType, @NotNull InstructionAdapter v
1654            ) {
1655                originalValue.storeSelector(topOfStackType, v);
1656            }
1657    
1658            @Override
1659            public void dup(@NotNull InstructionAdapter v, boolean withWriteReceiver) {
1660                originalValue.dup(v, withWriteReceiver);
1661            }
1662        }
1663    
1664        public static StackValue complexWriteReadReceiver(StackValue stackValue) {
1665            return complexReceiver(stackValue, false, true);
1666        }
1667    
1668        private static StackValue complexReceiver(StackValue stackValue, boolean... isReadOperations) {
1669            if (stackValue instanceof StackValueWithSimpleReceiver) {
1670                return new DelegatedForComplexReceiver(stackValue.type, (StackValueWithSimpleReceiver) stackValue,
1671                                     new ComplexReceiver((StackValueWithSimpleReceiver) stackValue, isReadOperations));
1672            }
1673            else {
1674                return stackValue;
1675            }
1676        }
1677    
1678        static class SafeCall extends StackValue {
1679    
1680            @NotNull private final Type type;
1681            private final StackValue receiver;
1682            @Nullable private final Label ifNull;
1683    
1684            public SafeCall(@NotNull Type type, @NotNull StackValue value, @Nullable Label ifNull) {
1685                super(type);
1686                this.type = type;
1687                this.receiver = value;
1688                this.ifNull = ifNull;
1689            }
1690    
1691            @Override
1692            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1693                receiver.put(this.type, v);
1694                if (ifNull != null) {
1695                    //not a primitive
1696                    v.dup();
1697                    v.ifnull(ifNull);
1698                }
1699                coerceTo(type, v);
1700            }
1701        }
1702    
1703        static class SafeFallback extends StackValueWithSimpleReceiver {
1704    
1705            @Nullable private final Label ifNull;
1706    
1707            public SafeFallback(@NotNull Type type, @Nullable Label ifNull, StackValue receiver) {
1708                super(type, false, false, receiver, true);
1709                this.ifNull = ifNull;
1710            }
1711    
1712            @Override
1713            public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
1714                Label end = new Label();
1715    
1716                v.goTo(end);
1717                v.mark(ifNull);
1718                v.pop();
1719                if (!this.type.equals(Type.VOID_TYPE)) {
1720                    v.aconst(null);
1721                }
1722                v.mark(end);
1723    
1724                coerceTo(type, v);
1725            }
1726    
1727            @Override
1728            public void store(
1729                    @NotNull StackValue rightSide, @NotNull InstructionAdapter v, boolean skipReceiver
1730            ) {
1731                receiver.store(rightSide, v, skipReceiver);
1732    
1733                Label end = new Label();
1734                v.goTo(end);
1735                v.mark(ifNull);
1736                v.pop();
1737                v.mark(end);
1738            }
1739        }
1740    }
1741