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