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