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