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