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