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