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.google.common.collect.Lists;
020    import com.google.common.collect.Maps;
021    import com.intellij.openapi.progress.ProcessCanceledException;
022    import com.intellij.openapi.util.Ref;
023    import com.intellij.psi.PsiElement;
024    import com.intellij.psi.tree.IElementType;
025    import com.intellij.util.ArrayUtil;
026    import com.intellij.util.Function;
027    import com.intellij.util.containers.Stack;
028    import kotlin.Pair;
029    import kotlin.Unit;
030    import kotlin.collections.CollectionsKt;
031    import kotlin.jvm.functions.Function1;
032    import org.jetbrains.annotations.NotNull;
033    import org.jetbrains.annotations.Nullable;
034    import org.jetbrains.kotlin.backend.common.CodegenUtil;
035    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
036    import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
037    import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
038    import org.jetbrains.kotlin.codegen.context.*;
039    import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
040    import org.jetbrains.kotlin.codegen.inline.*;
041    import org.jetbrains.kotlin.codegen.intrinsics.*;
042    import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt;
043    import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
044    import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
045    import org.jetbrains.kotlin.codegen.state.GenerationState;
046    import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
047    import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
048    import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
049    import org.jetbrains.kotlin.descriptors.*;
050    import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
051    import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
052    import org.jetbrains.kotlin.diagnostics.Errors;
053    import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
054    import org.jetbrains.kotlin.lexer.KtTokens;
055    import org.jetbrains.kotlin.load.java.JvmAbi;
056    import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
057    import org.jetbrains.kotlin.name.Name;
058    import org.jetbrains.kotlin.psi.*;
059    import org.jetbrains.kotlin.resolve.BindingContext;
060    import org.jetbrains.kotlin.resolve.BindingContextUtils;
061    import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
062    import org.jetbrains.kotlin.resolve.DescriptorUtils;
063    import org.jetbrains.kotlin.resolve.bindingContextUtil.BindingContextUtilsKt;
064    import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilKt;
065    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
066    import org.jetbrains.kotlin.resolve.calls.model.*;
067    import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
068    import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
069    import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
070    import org.jetbrains.kotlin.resolve.constants.ConstantValue;
071    import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
072    import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluatorKt;
073    import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
074    import org.jetbrains.kotlin.resolve.inline.InlineUtil;
075    import org.jetbrains.kotlin.resolve.jvm.JvmBindingContextSlices;
076    import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo;
077    import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
078    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
079    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
080    import org.jetbrains.kotlin.resolve.scopes.receivers.*;
081    import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
082    import org.jetbrains.kotlin.types.KotlinType;
083    import org.jetbrains.kotlin.types.TypeProjection;
084    import org.jetbrains.kotlin.types.TypeUtils;
085    import org.jetbrains.kotlin.types.checker.KotlinTypeChecker;
086    import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt;
087    import org.jetbrains.org.objectweb.asm.Label;
088    import org.jetbrains.org.objectweb.asm.MethodVisitor;
089    import org.jetbrains.org.objectweb.asm.Opcodes;
090    import org.jetbrains.org.objectweb.asm.Type;
091    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
092    import org.jetbrains.org.objectweb.asm.commons.Method;
093    
094    import java.util.*;
095    
096    import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt;
097    import static org.jetbrains.kotlin.codegen.AsmUtil.*;
098    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
099    import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
100    import static org.jetbrains.kotlin.resolve.BindingContext.*;
101    import static org.jetbrains.kotlin.resolve.BindingContextUtils.*;
102    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
103    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject;
104    import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
105    import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression;
106    import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral;
107    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
108    
109    public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> implements LocalLookup {
110        private final GenerationState state;
111        final KotlinTypeMapper typeMapper;
112        private final BindingContext bindingContext;
113    
114        public final InstructionAdapter v;
115        public final FrameMap myFrameMap;
116        private final MethodContext context;
117        private final Type returnType;
118    
119        private final CodegenStatementVisitor statementVisitor = new CodegenStatementVisitor(this);
120        private final MemberCodegen<?> parentCodegen;
121        private final TailRecursionCodegen tailRecursionCodegen;
122        public final CallGenerator defaultCallGenerator = new CallGenerator.DefaultCallGenerator(this);
123    
124        private final Stack<BlockStackElement> blockStackElements = new Stack<BlockStackElement>();
125    
126        /*
127         * When we create a temporary variable to hold some value not to compute it many times
128         * we put it into this map to emit access to that variable instead of evaluating the whole expression
129         */
130        public final Map<KtElement, StackValue> tempVariables = Maps.newHashMap();
131    
132        private int myLastLineNumber = -1;
133        private boolean shouldMarkLineNumbers = true;
134        private int finallyDepth = 0;
135    
136        public ExpressionCodegen(
137                @NotNull MethodVisitor mv,
138                @NotNull FrameMap frameMap,
139                @NotNull Type returnType,
140                @NotNull MethodContext context,
141                @NotNull GenerationState state,
142                @NotNull MemberCodegen<?> parentCodegen
143        ) {
144            this.state = state;
145            this.typeMapper = state.getTypeMapper();
146            this.bindingContext = state.getBindingContext();
147            this.v = new InstructionAdapter(mv);
148            this.myFrameMap = frameMap;
149            this.context = context;
150            this.returnType = returnType;
151            this.parentCodegen = parentCodegen;
152            this.tailRecursionCodegen = new TailRecursionCodegen(context, this, this.v, state);
153        }
154    
155        static class BlockStackElement {
156        }
157    
158        static class LoopBlockStackElement extends BlockStackElement {
159            final Label continueLabel;
160            final Label breakLabel;
161            public final KtSimpleNameExpression targetLabel;
162    
163            LoopBlockStackElement(Label breakLabel, Label continueLabel, KtSimpleNameExpression targetLabel) {
164                this.breakLabel = breakLabel;
165                this.continueLabel = continueLabel;
166                this.targetLabel = targetLabel;
167            }
168        }
169    
170        static class FinallyBlockStackElement extends BlockStackElement {
171            List<Label> gaps = new ArrayList<Label>();
172    
173            final KtTryExpression expression;
174    
175            FinallyBlockStackElement(KtTryExpression expression) {
176                this.expression = expression;
177            }
178    
179            private void addGapLabel(Label label){
180                gaps.add(label);
181            }
182        }
183    
184        @NotNull
185        public GenerationState getState() {
186            return state;
187        }
188    
189        @NotNull
190        public BindingContext getBindingContext() {
191            return bindingContext;
192        }
193    
194        @NotNull
195        public MemberCodegen<?> getParentCodegen() {
196            return parentCodegen;
197        }
198    
199        @NotNull
200        public ObjectLiteralResult generateObjectLiteral(@NotNull KtObjectLiteralExpression literal) {
201            KtObjectDeclaration objectDeclaration = literal.getObjectDeclaration();
202    
203            ClassDescriptor classDescriptor = bindingContext.get(CLASS, objectDeclaration);
204            assert classDescriptor != null;
205    
206            Type asmType = asmTypeForAnonymousClass(bindingContext, objectDeclaration);
207            ClassBuilder classBuilder = state.getFactory().newVisitor(
208                    JvmDeclarationOriginKt.OtherOrigin(objectDeclaration, classDescriptor),
209                    asmType,
210                    literal.getContainingFile()
211            );
212    
213            ClassContext objectContext = context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION);
214    
215            MemberCodegen literalCodegen = new ImplementationBodyCodegen(
216                    objectDeclaration, objectContext, classBuilder, state, getParentCodegen(),
217                    /* isLocal = */ true);
218            literalCodegen.generate();
219    
220            addReifiedParametersFromSignature(literalCodegen, classDescriptor);
221            propagateChildReifiedTypeParametersUsages(literalCodegen.getReifiedTypeParametersUsages());
222    
223            return new ObjectLiteralResult(
224                    literalCodegen.getReifiedTypeParametersUsages().wereUsedReifiedParameters(),
225                    classDescriptor
226            );
227        }
228    
229        private static void addReifiedParametersFromSignature(@NotNull MemberCodegen member, @NotNull ClassDescriptor descriptor) {
230            for (KotlinType type : descriptor.getTypeConstructor().getSupertypes()) {
231                for (TypeProjection supertypeArgument : type.getArguments()) {
232                    TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(supertypeArgument.getType());
233                    if (parameterDescriptor != null && parameterDescriptor.isReified()) {
234                        member.getReifiedTypeParametersUsages().addUsedReifiedParameter(parameterDescriptor.getName().asString());
235                    }
236                }
237            }
238        }
239    
240        private static class ObjectLiteralResult {
241            private final boolean wereReifiedMarkers;
242            private final ClassDescriptor classDescriptor;
243    
244            public ObjectLiteralResult(boolean wereReifiedMarkers, @NotNull ClassDescriptor classDescriptor) {
245                this.wereReifiedMarkers = wereReifiedMarkers;
246                this.classDescriptor = classDescriptor;
247            }
248        }
249    
250        @NotNull
251        private StackValue castToRequiredTypeOfInterfaceIfNeeded(
252                StackValue inner,
253                @NotNull ClassDescriptor provided,
254                @NotNull ClassDescriptor required
255        ) {
256            if (!isJvmInterface(provided) && isJvmInterface(required)) {
257                return StackValue.coercion(inner, asmType(required.getDefaultType()));
258            }
259    
260            return inner;
261        }
262    
263        public StackValue genQualified(StackValue receiver, KtElement selector) {
264            return genQualified(receiver, selector, this);
265        }
266    
267        private StackValue genQualified(StackValue receiver, KtElement selector, KtVisitor<StackValue, StackValue> visitor) {
268            if (tempVariables.containsKey(selector)) {
269                throw new IllegalStateException("Inconsistent state: expression saved to a temporary variable is a selector");
270            }
271            if (!(selector instanceof KtBlockExpression)) {
272                markStartLineNumber(selector);
273            }
274            try {
275                if (selector instanceof KtExpression) {
276                    StackValue samValue = genSamInterfaceValue((KtExpression) selector, visitor);
277                    if (samValue != null) {
278                        return samValue;
279                    }
280                }
281    
282                StackValue stackValue = selector.accept(visitor, receiver);
283    
284                RuntimeAssertionInfo runtimeAssertionInfo = null;
285                if (selector instanceof KtExpression) {
286                    runtimeAssertionInfo = bindingContext.get(JvmBindingContextSlices.RUNTIME_ASSERTION_INFO, (KtExpression) selector);
287                }
288    
289                if (BuiltinSpecialBridgesKt.isValueArgumentForCallToMethodWithTypeCheckBarrier(selector, bindingContext)) return stackValue;
290    
291                return genNotNullAssertions(state, stackValue, runtimeAssertionInfo);
292            }
293            catch (ProcessCanceledException e) {
294                throw e;
295            }
296            catch (CompilationException e) {
297                throw e;
298            }
299            catch (Throwable error) {
300                String message = error.getMessage();
301                throw new CompilationException(message != null ? message : "null", error, selector);
302            }
303        }
304    
305        public StackValue gen(KtElement expr) {
306            StackValue tempVar = tempVariables.get(expr);
307            return tempVar != null ? tempVar : genQualified(StackValue.none(), expr);
308        }
309    
310        public void gen(KtElement expr, Type type) {
311            StackValue value = Type.VOID_TYPE.equals(type) ? genStatement(expr) : gen(expr);
312            // for repl store the result of the last line into special field
313            if (value.type != Type.VOID_TYPE && state.getReplSpecific().getShouldGenerateScriptResultValue()) {
314                ScriptContext context = getScriptContext();
315                if (expr == context.getLastStatement()) {
316                    StackValue.Field resultValue = StackValue.field(context.getResultFieldInfo(), StackValue.LOCAL_0);
317                    resultValue.store(value, v);
318                    state.getReplSpecific().setHasResult(true);
319                    return;
320                }
321            }
322    
323            value.put(type, v);
324        }
325    
326        @NotNull
327        private ScriptContext getScriptContext() {
328            CodegenContext context = getContext();
329            while (!(context instanceof ScriptContext)) {
330                context = context.getParentContext();
331            }
332            return (ScriptContext) context;
333        }
334    
335        public StackValue genLazy(KtElement expr, Type type) {
336            StackValue value = gen(expr);
337            return StackValue.coercion(value, type);
338        }
339    
340        private StackValue genStatement(KtElement statement) {
341            return genQualified(StackValue.none(), statement, statementVisitor);
342        }
343    
344        @Override
345        public StackValue visitClass(@NotNull KtClass klass, StackValue data) {
346            return visitClassOrObject(klass);
347        }
348    
349        private StackValue visitClassOrObject(KtClassOrObject declaration) {
350            ClassDescriptor descriptor = bindingContext.get(CLASS, declaration);
351            assert descriptor != null;
352    
353            Type asmType = asmTypeForAnonymousClass(bindingContext, declaration);
354            ClassBuilder classBuilder = state.getFactory().newVisitor(JvmDeclarationOriginKt.OtherOrigin(declaration, descriptor), asmType, declaration.getContainingFile());
355    
356            ClassContext objectContext = context.intoAnonymousClass(descriptor, this, OwnerKind.IMPLEMENTATION);
357            new ImplementationBodyCodegen(declaration, objectContext, classBuilder, state, getParentCodegen(), /* isLocal = */ true).generate();
358    
359            if (declaration instanceof KtClass && ((KtClass) declaration).isInterface()) {
360                Type traitImplType = state.getTypeMapper().mapDefaultImpls(descriptor);
361                ClassBuilder traitImplBuilder = state.getFactory().newVisitor(JvmDeclarationOriginKt.TraitImpl(declaration, descriptor), traitImplType, declaration.getContainingFile());
362                ClassContext traitImplContext = context.intoAnonymousClass(descriptor, this, OwnerKind.DEFAULT_IMPLS);
363                new InterfaceImplBodyCodegen(declaration, traitImplContext, traitImplBuilder, state, parentCodegen).generate();
364            }
365    
366            return StackValue.none();
367        }
368    
369        @Override
370        public StackValue visitObjectDeclaration(@NotNull KtObjectDeclaration declaration, StackValue data) {
371            return visitClassOrObject(declaration);
372        }
373    
374        @Override
375        public StackValue visitExpression(@NotNull KtExpression expression, StackValue receiver) {
376            throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented");
377        }
378    
379        @Override
380        public StackValue visitSuperExpression(@NotNull KtSuperExpression expression, StackValue data) {
381            return StackValue.thisOrOuter(this, getSuperCallLabelTarget(context, expression), true, false);
382        }
383    
384        @NotNull
385        public static ClassDescriptor getSuperCallLabelTarget(
386                @NotNull CodegenContext<?> context,
387                @NotNull KtSuperExpression expression
388        ) {
389            KotlinType thisTypeForSuperCall = context.getState().getBindingContext().get(BindingContext.THIS_TYPE_FOR_SUPER_EXPRESSION, expression);
390            assert thisTypeForSuperCall != null : "This type for superCall ''" + expression.getText() + "'' should be not null!";
391            ClassifierDescriptor descriptor = thisTypeForSuperCall.getConstructor().getDeclarationDescriptor();
392            assert descriptor instanceof ClassDescriptor :
393                    "'This' reference target for ''" + expression.getText() + "''should be class descriptor, but was " + descriptor;
394            return (ClassDescriptor) descriptor;
395        }
396    
397        @NotNull
398        private Type asmType(@NotNull KotlinType type) {
399            return typeMapper.mapType(type);
400        }
401    
402        @NotNull
403        public Type expressionType(@Nullable KtExpression expression) {
404            KotlinType type = expressionJetType(expression);
405            return type == null ? Type.VOID_TYPE : asmType(type);
406        }
407    
408        @Nullable
409        public KotlinType expressionJetType(@Nullable KtExpression expression) {
410            return expression != null ? bindingContext.getType(expression) : null;
411        }
412    
413        @Override
414        public StackValue visitParenthesizedExpression(@NotNull KtParenthesizedExpression expression, StackValue receiver) {
415            return genQualified(receiver, expression.getExpression());
416        }
417    
418        @Override
419        public StackValue visitAnnotatedExpression(@NotNull KtAnnotatedExpression expression, StackValue receiver) {
420            return genQualified(receiver, expression.getBaseExpression());
421        }
422    
423        private static boolean isEmptyExpression(@Nullable KtElement expr) {
424            if (expr == null) {
425                return true;
426            }
427            if (expr instanceof KtBlockExpression) {
428                KtBlockExpression blockExpression = (KtBlockExpression) expr;
429                List<KtExpression> statements = blockExpression.getStatements();
430                if (statements.size() == 0 || statements.size() == 1 && isEmptyExpression(statements.get(0))) {
431                    return true;
432                }
433            }
434            return false;
435        }
436    
437        @Override
438        public StackValue visitIfExpression(@NotNull KtIfExpression expression, StackValue receiver) {
439            return generateIfExpression(expression, false);
440        }
441    
442        /* package */ StackValue generateIfExpression(@NotNull final KtIfExpression expression, final boolean isStatement) {
443            final Type asmType = isStatement ? Type.VOID_TYPE : expressionType(expression);
444            final StackValue condition = gen(expression.getCondition());
445    
446            final KtExpression thenExpression = expression.getThen();
447            final KtExpression elseExpression = expression.getElse();
448    
449            if (isEmptyExpression(thenExpression)) {
450                if (isEmptyExpression(elseExpression)) {
451                    return StackValue.coercion(condition, asmType);
452                }
453                return generateSingleBranchIf(condition, expression, elseExpression, false, isStatement);
454            }
455            else {
456                if (isEmptyExpression(elseExpression)) {
457                    return generateSingleBranchIf(condition, expression, thenExpression, true, isStatement);
458                }
459            }
460    
461            return StackValue.operation(asmType, new Function1<InstructionAdapter, Unit>() {
462                @Override
463                public Unit invoke(InstructionAdapter v) {
464                    Label elseLabel = new Label();
465                    BranchedValue.Companion.condJump(condition, elseLabel, true, v);
466    
467                    Label end = new Label();
468    
469                    gen(thenExpression, asmType);
470    
471                    v.goTo(end);
472                    v.mark(elseLabel);
473    
474                    gen(elseExpression, asmType);
475    
476                    markLineNumber(expression, isStatement);
477                    v.mark(end);
478                    return Unit.INSTANCE;
479                }
480            });
481        }
482    
483        @Override
484        public StackValue visitWhileExpression(@NotNull KtWhileExpression expression, StackValue receiver) {
485            Label condition = new Label();
486            v.mark(condition);
487    
488            Label end = new Label();
489            blockStackElements.push(new LoopBlockStackElement(end, condition, targetLabel(expression)));
490    
491            StackValue conditionValue = gen(expression.getCondition());
492            BranchedValue.Companion.loopJump(conditionValue, end, true, v);
493    
494            generateLoopBody(expression.getBody());
495    
496            markStartLineNumber(expression);
497            v.goTo(condition);
498    
499            v.mark(end);
500    
501            blockStackElements.pop();
502    
503            return StackValue.onStack(Type.VOID_TYPE);
504        }
505    
506    
507        @Override
508        public StackValue visitDoWhileExpression(@NotNull KtDoWhileExpression expression, StackValue receiver) {
509            Label beginLoopLabel = new Label();
510            v.mark(beginLoopLabel);
511    
512            Label breakLabel = new Label();
513            Label continueLabel = new Label();
514    
515            blockStackElements.push(new LoopBlockStackElement(breakLabel, continueLabel, targetLabel(expression)));
516    
517            PseudoInsnsKt.fakeAlwaysFalseIfeq(v, continueLabel);
518    
519            KtExpression body = expression.getBody();
520            KtExpression condition = expression.getCondition();
521            StackValue conditionValue;
522    
523            StackValueWithLeaveTask leaveTask = null;
524            if (body instanceof KtBlockExpression) {
525                // If body's a block, it can contain variable declarations which may be used in the condition of a do-while loop.
526                // We handle this case separately because otherwise such variable will be out of the frame map after the block ends
527                List<KtExpression> doWhileStatements = ((KtBlockExpression) body).getStatements();
528    
529                List<KtExpression> statements = new ArrayList<KtExpression>(doWhileStatements.size() + 1);
530                statements.addAll(doWhileStatements);
531                statements.add(condition);
532    
533                //Need to split leave task and condition cause otherwise BranchedValue optimizations wouldn't work
534                leaveTask = generateBlock(statements, false, continueLabel, null);
535                conditionValue = leaveTask.getStackValue();
536            }
537            else {
538                if (body != null) {
539                    gen(body, Type.VOID_TYPE);
540                }
541                v.mark(continueLabel);
542                conditionValue = gen(condition);
543            }
544    
545            BranchedValue.Companion.loopJump(conditionValue, beginLoopLabel, false, v);
546            if (leaveTask != null) {
547                leaveTask.getLeaveTasks().invoke(conditionValue);
548            }
549            v.mark(breakLabel);
550    
551            blockStackElements.pop();
552            return StackValue.none();
553        }
554    
555        @Override
556        public StackValue visitForExpression(@NotNull KtForExpression forExpression, StackValue receiver) {
557            ResolvedCall<? extends CallableDescriptor> loopRangeCall = RangeCodegenUtil.getLoopRangeResolvedCall(forExpression, bindingContext);
558            if (loopRangeCall != null) {
559                AbstractForLoopGenerator optimizedForLoopGenerator = createOptimizedForLoopGeneratorOrNull(forExpression, loopRangeCall);
560                if (optimizedForLoopGenerator != null) {
561                    generateForLoop(optimizedForLoopGenerator);
562                    return StackValue.none();
563                }
564            }
565    
566            KtExpression loopRange = forExpression.getLoopRange();
567            assert loopRange != null;
568            KotlinType loopRangeType = bindingContext.getType(loopRange);
569            assert loopRangeType != null;
570            Type asmLoopRangeType = asmType(loopRangeType);
571            if (asmLoopRangeType.getSort() == Type.ARRAY) {
572                generateForLoop(new ForInArrayLoopGenerator(forExpression));
573                return StackValue.none();
574            }
575    
576            if (RangeCodegenUtil.isRange(loopRangeType)) {
577                generateForLoop(new ForInRangeInstanceLoopGenerator(forExpression));
578                return StackValue.none();
579            }
580    
581            if (RangeCodegenUtil.isProgression(loopRangeType)) {
582                generateForLoop(new ForInProgressionExpressionLoopGenerator(forExpression));
583                return StackValue.none();
584            }
585    
586            generateForLoop(new IteratorForLoopGenerator(forExpression));
587            return StackValue.none();
588        }
589    
590        @Nullable
591        private AbstractForLoopGenerator createOptimizedForLoopGeneratorOrNull(
592                @NotNull KtForExpression forExpression,
593                @NotNull ResolvedCall<? extends CallableDescriptor> loopRangeCall
594        ) {
595            CallableDescriptor loopRangeCallee = loopRangeCall.getResultingDescriptor();
596            if (RangeCodegenUtil.isPrimitiveNumberRangeTo(loopRangeCallee)) {
597                return new ForInRangeLiteralLoopGenerator(forExpression, loopRangeCall);
598            }
599            else if (RangeCodegenUtil.isPrimitiveNumberDownTo(loopRangeCallee)) {
600                return new ForInDownToProgressionLoopGenerator(forExpression, loopRangeCall);
601            }
602            else if (RangeCodegenUtil.isArrayOrPrimitiveArrayIndices(loopRangeCallee)) {
603                return new ForInArrayIndicesRangeLoopGenerator(forExpression, loopRangeCall);
604            }
605            else if (RangeCodegenUtil.isCollectionIndices(loopRangeCallee)) {
606                return new ForInCollectionIndicesRangeLoopGenerator(forExpression, loopRangeCall);
607            }
608    
609            return null;
610        }
611    
612        @NotNull
613        private static KotlinType getExpectedReceiverType(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
614            ReceiverParameterDescriptor extensionReceiver = resolvedCall.getResultingDescriptor().getExtensionReceiverParameter();
615            assert extensionReceiver != null : "Extension receiver should be non-null";
616            return extensionReceiver.getType();
617        }
618    
619        @Nullable
620        private static KtExpression getSingleArgumentExpression(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
621            List<ResolvedValueArgument> resolvedValueArguments = resolvedCall.getValueArgumentsByIndex();
622            if (resolvedValueArguments == null) return null;
623            if (resolvedValueArguments.size() != 1) return null;
624            List<ValueArgument> valueArguments = resolvedValueArguments.get(0).getArguments();
625            if (valueArguments.size() != 1) return null;
626            return valueArguments.get(0).getArgumentExpression();
627        }
628    
629        private OwnerKind contextKind() {
630            return context.getContextKind();
631        }
632    
633        private void generateForLoop(AbstractForLoopGenerator generator) {
634            Label loopExit = new Label();
635            Label loopEntry = new Label();
636            Label continueLabel = new Label();
637    
638            generator.beforeLoop();
639            generator.checkEmptyLoop(loopExit);
640    
641            v.mark(loopEntry);
642            generator.checkPreCondition(loopExit);
643    
644            // Some forms of for-loop can be optimized as post-condition loops.
645            PseudoInsnsKt.fakeAlwaysFalseIfeq(v, continueLabel);
646    
647            generator.beforeBody();
648            blockStackElements.push(new LoopBlockStackElement(loopExit, continueLabel, targetLabel(generator.forExpression)));
649            generator.body();
650            blockStackElements.pop();
651            v.mark(continueLabel);
652            generator.afterBody(loopExit);
653    
654            v.goTo(loopEntry);
655    
656            v.mark(loopExit);
657            generator.afterLoop();
658        }
659    
660        private abstract class AbstractForLoopGenerator {
661    
662            // for (e : E in c) {...}
663            protected final KtForExpression forExpression;
664            private final Label loopParameterStartLabel = new Label();
665            private final Label bodyEnd = new Label();
666            private final List<Runnable> leaveVariableTasks = Lists.newArrayList();
667    
668            protected final KotlinType elementType;
669            protected final Type asmElementType;
670    
671            protected int loopParameterVar;
672            protected Type loopParameterType;
673    
674            private AbstractForLoopGenerator(@NotNull KtForExpression forExpression) {
675                this.forExpression = forExpression;
676                this.elementType = getElementType(forExpression);
677                this.asmElementType = asmType(elementType);
678            }
679    
680            @NotNull
681            private KotlinType getElementType(KtForExpression forExpression) {
682                KtExpression loopRange = forExpression.getLoopRange();
683                assert loopRange != null;
684                ResolvedCall<FunctionDescriptor> nextCall = getNotNull(bindingContext,
685                                                                       LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange,
686                                                                       "No next() function " + DiagnosticUtils.atLocation(loopRange));
687                //noinspection ConstantConditions
688                return nextCall.getResultingDescriptor().getReturnType();
689            }
690    
691            public void beforeLoop() {
692                KtParameter loopParameter = forExpression.getLoopParameter();
693                if (loopParameter != null) {
694                    // E e = tmp<iterator>.next()
695                    final VariableDescriptor parameterDescriptor = bindingContext.get(VALUE_PARAMETER, loopParameter);
696                    loopParameterType = asmType(parameterDescriptor.getType());
697                    loopParameterVar = myFrameMap.enter(parameterDescriptor, loopParameterType);
698                    scheduleLeaveVariable(new Runnable() {
699                        @Override
700                        public void run() {
701                            myFrameMap.leave(parameterDescriptor);
702                            v.visitLocalVariable(parameterDescriptor.getName().asString(),
703                                                 loopParameterType.getDescriptor(), null,
704                                                 loopParameterStartLabel, bodyEnd,
705                                                 loopParameterVar);
706                        }
707                    });
708                }
709                else {
710                    KtDestructuringDeclaration multiParameter = forExpression.getDestructuringParameter();
711                    assert multiParameter != null;
712    
713                    // E tmp<e> = tmp<iterator>.next()
714                    loopParameterType = asmElementType;
715                    loopParameterVar = createLoopTempVariable(asmElementType);
716                }
717            }
718    
719            public abstract void checkEmptyLoop(@NotNull Label loopExit);
720    
721            public abstract void checkPreCondition(@NotNull Label loopExit);
722    
723            public void beforeBody() {
724                assignToLoopParameter();
725                v.mark(loopParameterStartLabel);
726    
727                if (forExpression.getLoopParameter() == null) {
728                    KtDestructuringDeclaration multiParameter = forExpression.getDestructuringParameter();
729                    assert multiParameter != null;
730    
731                    generateMultiVariables(multiParameter.getEntries());
732                }
733            }
734    
735            private void generateMultiVariables(List<KtDestructuringDeclarationEntry> entries) {
736                for (KtDestructuringDeclarationEntry variableDeclaration : entries) {
737                    final VariableDescriptor componentDescriptor = bindingContext.get(VARIABLE, variableDeclaration);
738    
739                    @SuppressWarnings("ConstantConditions") final Type componentAsmType = asmType(componentDescriptor.getReturnType());
740                    final int componentVarIndex = myFrameMap.enter(componentDescriptor, componentAsmType);
741                    final Label variableStartLabel = new Label();
742                    scheduleLeaveVariable(new Runnable() {
743                        @Override
744                        public void run() {
745                            myFrameMap.leave(componentDescriptor);
746                            v.visitLocalVariable(componentDescriptor.getName().asString(),
747                                                 componentAsmType.getDescriptor(), null,
748                                                 variableStartLabel, bodyEnd,
749                                                 componentVarIndex);
750                        }
751                    });
752    
753                    ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(COMPONENT_RESOLVED_CALL, variableDeclaration);
754                    assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText();
755                    Call call = makeFakeCall(new TransientReceiver(elementType));
756    
757                    StackValue value = invokeFunction(call, resolvedCall, StackValue.local(loopParameterVar, asmElementType));
758                    StackValue.local(componentVarIndex, componentAsmType).store(value, v);
759                    v.visitLabel(variableStartLabel);
760                }
761            }
762    
763            protected abstract void assignToLoopParameter();
764    
765            protected abstract void increment(@NotNull Label loopExit);
766    
767            public void body() {
768                generateLoopBody(forExpression.getBody());
769            }
770    
771            private void scheduleLeaveVariable(Runnable runnable) {
772                leaveVariableTasks.add(runnable);
773            }
774    
775            protected int createLoopTempVariable(final Type type) {
776                int varIndex = myFrameMap.enterTemp(type);
777                scheduleLeaveVariable(new Runnable() {
778                    @Override
779                    public void run() {
780                        myFrameMap.leaveTemp(type);
781                    }
782                });
783                return varIndex;
784            }
785    
786            public void afterBody(@NotNull Label loopExit) {
787                markStartLineNumber(forExpression);
788    
789                increment(loopExit);
790    
791                v.mark(bodyEnd);
792            }
793    
794            public void afterLoop() {
795                for (Runnable task : Lists.reverse(leaveVariableTasks)) {
796                    task.run();
797                }
798            }
799    
800            // This method consumes range/progression from stack
801            // The result is stored to local variable
802            protected void generateRangeOrProgressionProperty(
803                    @NotNull Type loopRangeType,
804                    @NotNull String getterName,
805                    @NotNull Type getterReturnType,
806                    @NotNull Type varType,
807                    int varToStore
808            ) {
809                v.invokevirtual(loopRangeType.getInternalName(), getterName, "()" + getterReturnType.getDescriptor(), false);
810                StackValue.local(varToStore, varType).store(StackValue.onStack(getterReturnType), v);
811            }
812        }
813    
814        private void generateLoopBody(@Nullable KtExpression body) {
815            if (body != null) {
816                gen(body, Type.VOID_TYPE);
817            }
818        }
819    
820        private class IteratorForLoopGenerator extends AbstractForLoopGenerator {
821    
822            private int iteratorVarIndex;
823            private final ResolvedCall<FunctionDescriptor> iteratorCall;
824            private final ResolvedCall<FunctionDescriptor> nextCall;
825            private final Type asmTypeForIterator;
826    
827            private IteratorForLoopGenerator(@NotNull KtForExpression forExpression) {
828                super(forExpression);
829    
830                KtExpression loopRange = forExpression.getLoopRange();
831                assert loopRange != null;
832                this.iteratorCall = getNotNull(bindingContext,
833                                               LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange,
834                                               "No .iterator() function " + DiagnosticUtils.atLocation(loopRange));
835    
836                KotlinType iteratorType = iteratorCall.getResultingDescriptor().getReturnType();
837                assert iteratorType != null;
838                this.asmTypeForIterator = asmType(iteratorType);
839    
840                this.nextCall = getNotNull(bindingContext,
841                                           LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange,
842                                           "No next() function " + DiagnosticUtils.atLocation(loopRange));
843            }
844    
845            @Override
846            public void beforeLoop() {
847                super.beforeLoop();
848    
849                // Iterator<E> tmp<iterator> = c.iterator()
850    
851                iteratorVarIndex = createLoopTempVariable(asmTypeForIterator);
852    
853                StackValue.local(iteratorVarIndex, asmTypeForIterator).store(invokeFunction(iteratorCall, StackValue.none()), v);
854            }
855    
856            @Override
857            public void checkEmptyLoop(@NotNull Label loopExit) {
858            }
859    
860            @Override
861            public void checkPreCondition(@NotNull Label loopExit) {
862                // tmp<iterator>.hasNext()
863    
864                KtExpression loopRange = forExpression.getLoopRange();
865                @SuppressWarnings("ConstantConditions") ResolvedCall<FunctionDescriptor> hasNextCall = getNotNull(bindingContext,
866                                                                          LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, loopRange,
867                                                                          "No hasNext() function " + DiagnosticUtils.atLocation(loopRange));
868                @SuppressWarnings("ConstantConditions") Call fakeCall = makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType()));
869                StackValue result = invokeFunction(fakeCall, hasNextCall, StackValue.local(iteratorVarIndex, asmTypeForIterator));
870                result.put(result.type, v);
871    
872                FunctionDescriptor hasNext = hasNextCall.getResultingDescriptor();
873                KotlinType type = hasNext.getReturnType();
874                assert type != null && KotlinTypeChecker.DEFAULT.isSubtypeOf(type, DescriptorUtilsKt.getBuiltIns(hasNext).getBooleanType());
875    
876                Type asmType = asmType(type);
877                StackValue.coerce(asmType, Type.BOOLEAN_TYPE, v);
878                v.ifeq(loopExit);
879            }
880    
881            @Override
882            protected void assignToLoopParameter() {
883                @SuppressWarnings("ConstantConditions") Call fakeCall =
884                        makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType()));
885                StackValue value = invokeFunction(fakeCall, nextCall, StackValue.local(iteratorVarIndex, asmTypeForIterator));
886                //noinspection ConstantConditions
887                StackValue.local(loopParameterVar, loopParameterType).store(value, v);
888            }
889    
890            @Override
891            protected void increment(@NotNull Label loopExit) {
892            }
893        }
894    
895        private class ForInArrayLoopGenerator extends AbstractForLoopGenerator {
896            private int indexVar;
897            private int arrayVar;
898            private final KotlinType loopRangeType;
899    
900            private ForInArrayLoopGenerator(@NotNull KtForExpression forExpression) {
901                super(forExpression);
902                loopRangeType = bindingContext.getType(forExpression.getLoopRange());
903            }
904    
905            @Override
906            public void beforeLoop() {
907                super.beforeLoop();
908    
909                indexVar = createLoopTempVariable(Type.INT_TYPE);
910    
911                KtExpression loopRange = forExpression.getLoopRange();
912                StackValue value = gen(loopRange);
913                Type asmLoopRangeType = asmType(loopRangeType);
914                if (value instanceof StackValue.Local && value.type.equals(asmLoopRangeType)) {
915                    arrayVar = ((StackValue.Local) value).index; // no need to copy local variable into another variable
916                }
917                else {
918                    arrayVar = createLoopTempVariable(OBJECT_TYPE);
919                    value.put(asmLoopRangeType, v);
920                    v.store(arrayVar, OBJECT_TYPE);
921                }
922    
923                v.iconst(0);
924                v.store(indexVar, Type.INT_TYPE);
925            }
926    
927            @Override
928            public void checkEmptyLoop(@NotNull Label loopExit) {
929            }
930    
931            @Override
932            public void checkPreCondition(@NotNull Label loopExit) {
933                v.load(indexVar, Type.INT_TYPE);
934                v.load(arrayVar, OBJECT_TYPE);
935                v.arraylength();
936                v.ificmpge(loopExit);
937            }
938    
939            @Override
940            protected void assignToLoopParameter() {
941                Type arrayElParamType;
942                if (KotlinBuiltIns.isArray(loopRangeType)) {
943                    arrayElParamType = boxType(asmElementType);
944                }
945                else {
946                    arrayElParamType = asmElementType;
947                }
948    
949                v.load(arrayVar, OBJECT_TYPE);
950                v.load(indexVar, Type.INT_TYPE);
951                v.aload(arrayElParamType);
952                StackValue.onStack(arrayElParamType).put(asmElementType, v);
953                v.store(loopParameterVar, asmElementType);
954            }
955    
956            @Override
957            protected void increment(@NotNull Label loopExit) {
958                v.iinc(indexVar, 1);
959            }
960        }
961    
962        private abstract class AbstractForInProgressionOrRangeLoopGenerator extends AbstractForLoopGenerator {
963            protected int endVar;
964    
965            private StackValue loopParameter;
966    
967            private AbstractForInProgressionOrRangeLoopGenerator(@NotNull KtForExpression forExpression) {
968                super(forExpression);
969    
970                switch (asmElementType.getSort()) {
971                    case Type.INT:
972                    case Type.BYTE:
973                    case Type.SHORT:
974                    case Type.CHAR:
975                    case Type.LONG:
976                        break;
977    
978                    default:
979                        throw new IllegalStateException("Unexpected range element type: " + asmElementType);
980                }
981            }
982    
983            @Override
984            public void beforeLoop() {
985                super.beforeLoop();
986    
987                endVar = createLoopTempVariable(asmElementType);
988            }
989    
990            protected void checkPostCondition(@NotNull Label loopExit) {
991                assert endVar != -1 :
992                        "endVar must be allocated, endVar = " + endVar;
993                loopParameter().put(asmElementType, v);
994                v.load(endVar, asmElementType);
995                if (asmElementType.getSort() == Type.LONG) {
996                    v.lcmp();
997                    v.ifeq(loopExit);
998                }
999                else {
1000                    v.ificmpeq(loopExit);
1001                }
1002            }
1003    
1004            @Override
1005            public void checkPreCondition(@NotNull Label loopExit) {
1006            }
1007    
1008            @NotNull
1009            protected StackValue loopParameter() {
1010                if (loopParameter == null) {
1011                    loopParameter = StackValue.local(loopParameterVar, loopParameterType);
1012                }
1013                return loopParameter;
1014            }
1015        }
1016    
1017        private abstract class AbstractForInRangeLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator {
1018            private final int step;
1019    
1020            private AbstractForInRangeLoopGenerator(@NotNull KtForExpression forExpression, int step) {
1021                super(forExpression);
1022                this.step = step;
1023                assert step == 1 || step == -1 : "'step' should be either 1 or -1: " + step;
1024            }
1025    
1026            private AbstractForInRangeLoopGenerator(@NotNull KtForExpression forExpression) {
1027                this(forExpression, 1);
1028            }
1029    
1030            @Override
1031            public void beforeLoop() {
1032                super.beforeLoop();
1033    
1034                storeRangeStartAndEnd();
1035            }
1036    
1037            protected abstract void storeRangeStartAndEnd();
1038    
1039            @Override
1040            public void checkEmptyLoop(@NotNull Label loopExit) {
1041                loopParameter().put(asmElementType, v);
1042                v.load(endVar, asmElementType);
1043                if (asmElementType.getSort() == Type.LONG) {
1044                    v.lcmp();
1045                    if (step > 0) {
1046                        v.ifgt(loopExit);
1047                    }
1048                    else {
1049                        v.iflt(loopExit);
1050                    }
1051                }
1052                else {
1053                    if (step > 0) {
1054                        v.ificmpgt(loopExit);
1055                    }
1056                    else {
1057                        v.ificmplt(loopExit);
1058                    }
1059                }
1060            }
1061    
1062            @Override
1063            protected void assignToLoopParameter() {
1064            }
1065    
1066            @Override
1067            protected void increment(@NotNull Label loopExit) {
1068                checkPostCondition(loopExit);
1069    
1070                if (loopParameterType == Type.INT_TYPE) {
1071                    v.iinc(loopParameterVar, step);
1072                }
1073                else {
1074                    StackValue loopParameter = loopParameter();
1075                    loopParameter.put(asmElementType, v);
1076                    genIncrement(asmElementType, step, v);
1077                    loopParameter.store(StackValue.onStack(asmElementType), v);
1078                }
1079            }
1080        }
1081    
1082        private class ForInRangeLiteralLoopGenerator extends AbstractForInRangeLoopGenerator {
1083            private final ReceiverValue from;
1084            private final KtExpression to;
1085    
1086            private ForInRangeLiteralLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
1087                super(forExpression);
1088                this.from = loopRangeCall.getDispatchReceiver();
1089                this.to = getSingleArgumentExpression(loopRangeCall);
1090            }
1091    
1092            @Override
1093            protected void storeRangeStartAndEnd() {
1094                loopParameter().store(generateReceiverValue(from, false), v);
1095                StackValue.local(endVar, asmElementType).store(gen(to), v);
1096            }
1097        }
1098    
1099        private class ForInDownToProgressionLoopGenerator extends AbstractForInRangeLoopGenerator {
1100            private final ReceiverValue from;
1101            private final KtExpression to;
1102    
1103            private ForInDownToProgressionLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
1104                super(forExpression, -1);
1105                this.from = loopRangeCall.getExtensionReceiver();
1106                this.to = getSingleArgumentExpression(loopRangeCall);
1107            }
1108    
1109            @Override
1110            protected void storeRangeStartAndEnd() {
1111                loopParameter().store(generateReceiverValue(from, false), v);
1112                StackValue.local(endVar, asmElementType).store(gen(to), v);
1113            }
1114        }
1115    
1116        private class ForInRangeInstanceLoopGenerator extends AbstractForInRangeLoopGenerator {
1117            private ForInRangeInstanceLoopGenerator(@NotNull KtForExpression forExpression) {
1118                super(forExpression);
1119            }
1120    
1121            @Override
1122            protected void storeRangeStartAndEnd() {
1123                KotlinType loopRangeType = bindingContext.getType(forExpression.getLoopRange());
1124                assert loopRangeType != null;
1125                Type asmLoopRangeType = asmType(loopRangeType);
1126                gen(forExpression.getLoopRange(), asmLoopRangeType);
1127                v.dup();
1128    
1129                // ranges inherit first and last from corresponding progressions
1130                generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType, loopParameterVar);
1131                generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar);
1132            }
1133        }
1134    
1135        private abstract class ForInOptimizedIndicesLoopGenerator extends AbstractForInRangeLoopGenerator {
1136            protected final ReceiverValue receiverValue;
1137            protected final KotlinType expectedReceiverType;
1138    
1139            private ForInOptimizedIndicesLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
1140                super(forExpression);
1141                this.receiverValue = loopRangeCall.getExtensionReceiver();
1142                this.expectedReceiverType = getExpectedReceiverType(loopRangeCall);
1143            }
1144    
1145            @Override
1146            protected void storeRangeStartAndEnd() {
1147                loopParameter().store(StackValue.constant(0, asmElementType), v);
1148    
1149                StackValue receiver = generateReceiverValue(receiverValue, false);
1150                Type receiverType = asmType(expectedReceiverType);
1151                receiver.put(receiverType, v);
1152                getReceiverSizeAsInt();
1153                v.iconst(1);
1154                v.sub(Type.INT_TYPE);
1155                StackValue.local(endVar, asmElementType).store(StackValue.onStack(Type.INT_TYPE), v);
1156            }
1157    
1158            /**
1159             * <code>(receiver -> size:I)</code>
1160             */
1161            protected abstract void getReceiverSizeAsInt();
1162        }
1163    
1164        private class ForInCollectionIndicesRangeLoopGenerator extends ForInOptimizedIndicesLoopGenerator {
1165            private ForInCollectionIndicesRangeLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
1166                super(forExpression, loopRangeCall);
1167            }
1168    
1169            @Override
1170            protected void getReceiverSizeAsInt() {
1171                v.invokeinterface("java/util/Collection", "size", "()I");
1172            }
1173        }
1174    
1175        private class ForInArrayIndicesRangeLoopGenerator extends ForInOptimizedIndicesLoopGenerator {
1176            private ForInArrayIndicesRangeLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
1177                super(forExpression, loopRangeCall);
1178            }
1179    
1180            @Override
1181            protected void getReceiverSizeAsInt() {
1182                v.arraylength();
1183            }
1184        }
1185    
1186        private class ForInProgressionExpressionLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator {
1187            private int incrementVar;
1188            private Type incrementType;
1189    
1190            private ForInProgressionExpressionLoopGenerator(@NotNull KtForExpression forExpression) {
1191                super(forExpression);
1192            }
1193    
1194            @Override
1195            public void beforeLoop() {
1196                super.beforeLoop();
1197    
1198                incrementVar = createLoopTempVariable(asmElementType);
1199    
1200                KotlinType loopRangeType = bindingContext.getType(forExpression.getLoopRange());
1201                assert loopRangeType != null;
1202                Type asmLoopRangeType = asmType(loopRangeType);
1203    
1204                Collection<PropertyDescriptor> incrementProp =
1205                        loopRangeType.getMemberScope().getContributedVariables(Name.identifier("step"), NoLookupLocation.FROM_BACKEND);
1206                assert incrementProp.size() == 1 : loopRangeType + " " + incrementProp.size();
1207                incrementType = asmType(incrementProp.iterator().next().getType());
1208    
1209                gen(forExpression.getLoopRange(), asmLoopRangeType);
1210                v.dup();
1211                v.dup();
1212    
1213                generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType, loopParameterVar);
1214                generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar);
1215                generateRangeOrProgressionProperty(asmLoopRangeType, "getStep", incrementType, incrementType, incrementVar);
1216            }
1217    
1218            @Override
1219            public void checkEmptyLoop(@NotNull Label loopExit) {
1220                loopParameter().put(asmElementType, v);
1221                v.load(endVar, asmElementType);
1222                v.load(incrementVar, incrementType);
1223    
1224                Label negativeIncrement = new Label();
1225                Label afterIf = new Label();
1226    
1227                if (asmElementType.getSort() == Type.LONG) {
1228                    v.lconst(0L);
1229                    v.lcmp();
1230                    v.ifle(negativeIncrement); // if increment < 0, jump
1231    
1232                    // increment > 0
1233                    v.lcmp();
1234                    v.ifgt(loopExit);
1235                    v.goTo(afterIf);
1236    
1237                    // increment < 0
1238                    v.mark(negativeIncrement);
1239                    v.lcmp();
1240                    v.iflt(loopExit);
1241                    v.mark(afterIf);
1242                }
1243                else {
1244                    v.ifle(negativeIncrement); // if increment < 0, jump
1245    
1246                    // increment > 0
1247                    v.ificmpgt(loopExit);
1248                    v.goTo(afterIf);
1249    
1250                    // increment < 0
1251                    v.mark(negativeIncrement);
1252                    v.ificmplt(loopExit);
1253                    v.mark(afterIf);
1254                }
1255            }
1256    
1257            @Override
1258            protected void assignToLoopParameter() {
1259            }
1260    
1261            @Override
1262            protected void increment(@NotNull Label loopExit) {
1263                checkPostCondition(loopExit);
1264    
1265                StackValue loopParameter = loopParameter();
1266                loopParameter.put(asmElementType, v);
1267                v.load(incrementVar, asmElementType);
1268                v.add(asmElementType);
1269    
1270                if (asmElementType == Type.BYTE_TYPE || asmElementType == Type.SHORT_TYPE || asmElementType == Type.CHAR_TYPE) {
1271                    StackValue.coerce(Type.INT_TYPE, asmElementType, v);
1272                }
1273    
1274                loopParameter.store(StackValue.onStack(asmElementType), v);
1275            }
1276        }
1277    
1278    
1279        @Override
1280        public StackValue visitBreakExpression(@NotNull KtBreakExpression expression, StackValue receiver) {
1281            return generateBreakOrContinueExpression(expression, true, new Label());
1282        }
1283    
1284        @Override
1285        public StackValue visitContinueExpression(@NotNull KtContinueExpression expression, StackValue receiver) {
1286            return generateBreakOrContinueExpression(expression, false, new Label());
1287        }
1288    
1289        @NotNull
1290        private StackValue generateBreakOrContinueExpression(
1291                @NotNull KtExpressionWithLabel expression,
1292                boolean isBreak,
1293                final @NotNull Label afterBreakContinueLabel
1294        ) {
1295            assert expression instanceof KtContinueExpression || expression instanceof KtBreakExpression;
1296    
1297            if (blockStackElements.isEmpty()) {
1298                throw new UnsupportedOperationException("Target label for break/continue not found");
1299            }
1300    
1301            BlockStackElement stackElement = blockStackElements.peek();
1302    
1303            if (stackElement instanceof FinallyBlockStackElement) {
1304                FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement;
1305                //noinspection ConstantConditions
1306                genFinallyBlockOrGoto(finallyBlockStackElement, null, afterBreakContinueLabel);
1307            }
1308            else if (stackElement instanceof LoopBlockStackElement) {
1309                LoopBlockStackElement loopBlockStackElement = (LoopBlockStackElement) stackElement;
1310                KtSimpleNameExpression labelElement = expression.getTargetLabel();
1311                //noinspection ConstantConditions
1312                if (labelElement == null ||
1313                    loopBlockStackElement.targetLabel != null &&
1314                    labelElement.getReferencedName().equals(loopBlockStackElement.targetLabel.getReferencedName())) {
1315                    final Label label = isBreak ? loopBlockStackElement.breakLabel : loopBlockStackElement.continueLabel;
1316                    return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
1317                                                    @Override
1318                                                    public Unit invoke(InstructionAdapter adapter) {
1319                                                        PseudoInsnsKt.fixStackAndJump(v, label);
1320                                                        v.mark(afterBreakContinueLabel);
1321                                                        return Unit.INSTANCE;
1322                                                    }
1323                                                }
1324                    );
1325                }
1326            }
1327            else {
1328                throw new UnsupportedOperationException("Wrong BlockStackElement in processing stack");
1329            }
1330    
1331            blockStackElements.pop();
1332            StackValue result = generateBreakOrContinueExpression(expression, isBreak, afterBreakContinueLabel);
1333            blockStackElements.push(stackElement);
1334            return result;
1335        }
1336    
1337        private StackValue generateSingleBranchIf(
1338                final StackValue condition,
1339                final KtIfExpression ifExpression,
1340                final KtExpression expression,
1341                final boolean inverse,
1342                final boolean isStatement
1343        ) {
1344            Type targetType = isStatement ? Type.VOID_TYPE : expressionType(ifExpression);
1345            return StackValue.operation(targetType, new Function1<InstructionAdapter, Unit>() {
1346                @Override
1347                public Unit invoke(InstructionAdapter v) {
1348                    Label elseLabel = new Label();
1349                    BranchedValue.Companion.condJump(condition, elseLabel, inverse, v);
1350    
1351                    if (isStatement) {
1352                        gen(expression, Type.VOID_TYPE);
1353                        v.mark(elseLabel);
1354                    }
1355                    else {
1356                        Type targetType = expressionType(ifExpression);
1357                        gen(expression, targetType);
1358                        Label end = new Label();
1359                        v.goTo(end);
1360    
1361                        v.mark(elseLabel);
1362                        StackValue.putUnitInstance(v);
1363    
1364                        markStartLineNumber(ifExpression);
1365                        v.mark(end);
1366                    }
1367                    return null;
1368                }
1369            });
1370        }
1371    
1372        @Override
1373        public StackValue visitConstantExpression(@NotNull KtConstantExpression expression, StackValue receiver) {
1374            ConstantValue<?> compileTimeValue = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext);
1375            assert compileTimeValue != null;
1376            return StackValue.constant(compileTimeValue.getValue(), expressionType(expression));
1377        }
1378    
1379        @Nullable
1380        public static ConstantValue<?> getPrimitiveOrStringCompileTimeConstant(@NotNull KtExpression expression, @NotNull BindingContext bindingContext) {
1381            ConstantValue<?> constant = getCompileTimeConstant(expression, bindingContext, false);
1382            if (constant == null || ConstantExpressionEvaluatorKt.isStandaloneOnlyConstant(constant)) {
1383                return null;
1384            }
1385            return constant;
1386        }
1387    
1388        @Nullable
1389        public static ConstantValue<?> getCompileTimeConstant(@NotNull KtExpression expression, @NotNull BindingContext bindingContext) {
1390            return getCompileTimeConstant(expression, bindingContext, false);
1391        }
1392    
1393        @Nullable
1394        public static ConstantValue<?> getCompileTimeConstant(
1395                @NotNull KtExpression expression,
1396                @NotNull final BindingContext bindingContext,
1397                boolean takeUpConstValsAsConst
1398        ) {
1399            CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, bindingContext);
1400            if (compileTimeValue == null || compileTimeValue.getUsesNonConstValAsConstant()) {
1401                return null;
1402            }
1403    
1404            if (!takeUpConstValsAsConst && compileTimeValue.getUsesVariableAsConstant()) {
1405                final Ref<Boolean> containsNonInlinedVals = new Ref<Boolean>(false);
1406                KtVisitor constantChecker = new KtVisitor() {
1407                    @Override
1408                    public Object visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression, Object data) {
1409                        ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext);
1410                        if (resolvedCall != null) {
1411                            CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
1412                            if (callableDescriptor instanceof PropertyDescriptor &&
1413                                !JvmCodegenUtil.isInlinedJavaConstProperty((VariableDescriptor) callableDescriptor)) {
1414                                    containsNonInlinedVals.set(true);
1415                            }
1416                        }
1417                        return null;
1418                    }
1419    
1420                    @Override
1421                    public Object visitKtElement(@NotNull KtElement element, Object data) {
1422                        if (!containsNonInlinedVals.get()) {
1423                            element.acceptChildren(this);
1424                        }
1425                        return null;
1426                    }
1427                };
1428    
1429                expression.accept(constantChecker);
1430    
1431                if (containsNonInlinedVals.get()) {
1432                    return null;
1433                }
1434            }
1435    
1436            KotlinType expectedType = bindingContext.getType(expression);
1437            return compileTimeValue.toConstantValue(expectedType);
1438        }
1439    
1440        @Override
1441        public StackValue visitStringTemplateExpression(@NotNull KtStringTemplateExpression expression, StackValue receiver) {
1442            StringBuilder constantValue = new StringBuilder("");
1443            final KtStringTemplateEntry[] entries = expression.getEntries();
1444    
1445            if (entries.length == 1 && entries[0] instanceof KtStringTemplateEntryWithExpression) {
1446                KtExpression expr = entries[0].getExpression();
1447                return genToString(gen(expr), expressionType(expr));
1448            }
1449    
1450            for (KtStringTemplateEntry entry : entries) {
1451                if (entry instanceof KtLiteralStringTemplateEntry) {
1452                    constantValue.append(entry.getText());
1453                }
1454                else if (entry instanceof KtEscapeStringTemplateEntry) {
1455                    constantValue.append(((KtEscapeStringTemplateEntry) entry).getUnescapedValue());
1456                }
1457                else {
1458                    constantValue = null;
1459                    break;
1460                }
1461            }
1462            if (constantValue != null) {
1463                Type type = expressionType(expression);
1464                return StackValue.constant(constantValue.toString(), type);
1465            }
1466            else {
1467                return StackValue.operation(JAVA_STRING_TYPE, new Function1<InstructionAdapter, Unit>() {
1468                    @Override
1469                    public Unit invoke(InstructionAdapter v) {
1470                        genStringBuilderConstructor(v);
1471                        for (KtStringTemplateEntry entry : entries) {
1472                            if (entry instanceof KtStringTemplateEntryWithExpression) {
1473                                invokeAppend(entry.getExpression());
1474                            }
1475                            else {
1476                                String text = entry instanceof KtEscapeStringTemplateEntry
1477                                              ? ((KtEscapeStringTemplateEntry) entry).getUnescapedValue()
1478                                              : entry.getText();
1479                                v.aconst(text);
1480                                genInvokeAppendMethod(v, JAVA_STRING_TYPE);
1481                            }
1482                        }
1483                        v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
1484                        return Unit.INSTANCE;
1485                    }
1486                });
1487            }
1488        }
1489    
1490        @Override
1491        public StackValue visitBlockExpression(@NotNull KtBlockExpression expression, StackValue receiver) {
1492            return generateBlock(expression, false);
1493        }
1494    
1495        @Override
1496        public StackValue visitNamedFunction(@NotNull KtNamedFunction function, StackValue data) {
1497            return visitNamedFunction(function, data, false);
1498        }
1499    
1500        public StackValue visitNamedFunction(@NotNull KtNamedFunction function, StackValue data, boolean isStatement) {
1501            assert data == StackValue.none();
1502    
1503            if (KtPsiUtil.isScriptDeclaration(function)) {
1504                return StackValue.none();
1505            }
1506    
1507            StackValue closure = genClosure(function, null);
1508            if (isStatement) {
1509                DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, function);
1510                int index = lookupLocalIndex(descriptor);
1511                closure.put(OBJECT_TYPE, v);
1512                v.store(index, OBJECT_TYPE);
1513                return StackValue.none();
1514            }
1515            else {
1516                return closure;
1517            }
1518        }
1519    
1520        @Override
1521        public StackValue visitLambdaExpression(@NotNull KtLambdaExpression expression, StackValue receiver) {
1522            if (Boolean.TRUE.equals(bindingContext.get(BLOCK, expression))) {
1523                return gen(expression.getFunctionLiteral().getBodyExpression());
1524            }
1525            else {
1526                return genClosure(expression.getFunctionLiteral(), null);
1527            }
1528        }
1529    
1530        @NotNull
1531        private StackValue genClosure(KtDeclarationWithBody declaration, @Nullable SamType samType) {
1532            FunctionDescriptor descriptor = bindingContext.get(FUNCTION, declaration);
1533            assert descriptor != null : "Function is not resolved to descriptor: " + declaration.getText();
1534    
1535            return genClosure(
1536                    declaration, descriptor, new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration), samType, null
1537            );
1538        }
1539    
1540        @NotNull
1541        private StackValue genClosure(
1542                @NotNull KtElement declaration,
1543                @NotNull FunctionDescriptor descriptor,
1544                @NotNull FunctionGenerationStrategy strategy,
1545                @Nullable SamType samType,
1546                @Nullable FunctionDescriptor functionReferenceTarget
1547        ) {
1548            ClassBuilder cv = state.getFactory().newVisitor(
1549                    JvmDeclarationOriginKt.OtherOrigin(declaration, descriptor),
1550                    asmTypeForAnonymousClass(bindingContext, descriptor),
1551                    declaration.getContainingFile()
1552            );
1553    
1554            ClosureCodegen closureCodegen = new ClosureCodegen(
1555                    state, declaration, samType, context.intoClosure(descriptor, this, typeMapper),
1556                    functionReferenceTarget, strategy, parentCodegen, cv
1557            );
1558    
1559            closureCodegen.generate();
1560    
1561            if (closureCodegen.getReifiedTypeParametersUsages().wereUsedReifiedParameters()) {
1562                ReifiedTypeInliner.putNeedClassReificationMarker(v);
1563                propagateChildReifiedTypeParametersUsages(closureCodegen.getReifiedTypeParametersUsages());
1564            }
1565    
1566            return closureCodegen.putInstanceOnStack(this);
1567        }
1568    
1569        @Override
1570        public StackValue visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression, StackValue receiver) {
1571            final ObjectLiteralResult objectLiteralResult = generateObjectLiteral(expression);
1572            final ClassDescriptor classDescriptor = objectLiteralResult.classDescriptor;
1573            final Type type = typeMapper.mapType(classDescriptor);
1574    
1575            return StackValue.operation(type, new Function1<InstructionAdapter, Unit>() {
1576                @Override
1577                public Unit invoke(InstructionAdapter v) {
1578                    if (objectLiteralResult.wereReifiedMarkers) {
1579                        ReifiedTypeInliner.putNeedClassReificationMarker(v);
1580                    }
1581                    v.anew(type);
1582                    v.dup();
1583    
1584                    pushClosureOnStack(classDescriptor, true, defaultCallGenerator);
1585    
1586                    ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
1587                    assert primaryConstructor != null : "There should be primary constructor for object literal";
1588                    ResolvedCall<ConstructorDescriptor> superCall = getDelegationConstructorCall(bindingContext, primaryConstructor);
1589                    if (superCall != null) {
1590                        // For an anonymous object, we should also generate all non-default arguments that it captures for its super call
1591                        ConstructorDescriptor superConstructor = superCall.getResultingDescriptor();
1592                        ConstructorDescriptor constructorToCall = SamCodegenUtil.resolveSamAdapter(superConstructor);
1593                        List<ValueParameterDescriptor> superValueParameters = superConstructor.getValueParameters();
1594                        int params = superValueParameters.size();
1595                        List<Type> superMappedTypes = typeMapper.mapToCallableMethod(constructorToCall, false).getValueParameterTypes();
1596                        assert superMappedTypes.size() >= params : String
1597                                .format("Incorrect number of mapped parameters vs arguments: %d < %d for %s",
1598                                        superMappedTypes.size(), params, classDescriptor);
1599    
1600                        List<ResolvedValueArgument> valueArguments = new ArrayList<ResolvedValueArgument>(params);
1601                        List<ValueParameterDescriptor> valueParameters = new ArrayList<ValueParameterDescriptor>(params);
1602                        List<Type> mappedTypes = new ArrayList<Type>(params);
1603                        for (ValueParameterDescriptor parameter : superValueParameters) {
1604                            ResolvedValueArgument argument = superCall.getValueArguments().get(parameter);
1605                            if (!(argument instanceof DefaultValueArgument)) {
1606                                valueArguments.add(argument);
1607                                valueParameters.add(parameter);
1608                                mappedTypes.add(superMappedTypes.get(parameter.getIndex()));
1609                            }
1610                        }
1611                        ArgumentGenerator argumentGenerator =
1612                                new CallBasedArgumentGenerator(ExpressionCodegen.this, defaultCallGenerator, valueParameters, mappedTypes);
1613    
1614                        argumentGenerator.generate(valueArguments, valueArguments);
1615                    }
1616    
1617                    Collection<ConstructorDescriptor> constructors = classDescriptor.getConstructors();
1618                    assert constructors.size() == 1 : "Unexpected number of constructors for class: " + classDescriptor + " " + constructors;
1619                    ConstructorDescriptor constructorDescriptor = CollectionsKt.single(constructors);
1620    
1621                    Method constructor = typeMapper.mapAsmMethod(SamCodegenUtil.resolveSamAdapter(constructorDescriptor));
1622                    v.invokespecial(type.getInternalName(), "<init>", constructor.getDescriptor(), false);
1623                    return Unit.INSTANCE;
1624                }
1625            });
1626        }
1627    
1628        public void pushClosureOnStack(@NotNull ClassDescriptor classDescriptor, boolean putThis, @NotNull CallGenerator callGenerator) {
1629            CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor);
1630            if (closure == null) return;
1631    
1632            int paramIndex = 0;
1633    
1634            if (putThis) {
1635                ClassDescriptor captureThis = closure.getCaptureThis();
1636                if (captureThis != null) {
1637                    StackValue thisOrOuter = generateThisOrOuter(captureThis, false);
1638                    assert !isPrimitive(thisOrOuter.type) : "This or outer should be non primitive: " + thisOrOuter.type;
1639                    callGenerator.putCapturedValueOnStack(thisOrOuter, thisOrOuter.type, paramIndex++);
1640                }
1641            }
1642    
1643            KotlinType captureReceiver = closure.getCaptureReceiverType();
1644            if (captureReceiver != null) {
1645                Type asmType = typeMapper.mapType(captureReceiver);
1646                StackValue.Local capturedReceiver = StackValue.local(AsmUtil.getReceiverIndex(context, context.getContextDescriptor()), asmType);
1647                callGenerator.putCapturedValueOnStack(capturedReceiver, capturedReceiver.type, paramIndex++);
1648            }
1649    
1650            for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closure.getCaptureVariables().entrySet()) {
1651                Type sharedVarType = typeMapper.getSharedVarType(entry.getKey());
1652                if (sharedVarType == null) {
1653                    sharedVarType = typeMapper.mapType((VariableDescriptor) entry.getKey());
1654                }
1655                StackValue capturedVar = lookupOuterValue(entry.getValue());
1656                callGenerator.putCapturedValueOnStack(capturedVar, sharedVarType, paramIndex++);
1657            }
1658    
1659    
1660            ClassDescriptor superClass = DescriptorUtilsKt.getSuperClassNotAny(classDescriptor);
1661            if (superClass != null) {
1662                pushClosureOnStack(
1663                        superClass,
1664                        putThis && closure.getCaptureThis() == null,
1665                        callGenerator
1666                );
1667            }
1668        }
1669    
1670        /* package */ StackValue generateBlock(@NotNull KtBlockExpression expression, boolean isStatement) {
1671            if (expression.getParent() instanceof KtNamedFunction) {
1672                // For functions end of block should be end of function label
1673                return generateBlock(expression.getStatements(), isStatement, null, context.getMethodEndLabel());
1674            }
1675            return generateBlock(expression.getStatements(), isStatement, null, null);
1676        }
1677    
1678        @NotNull
1679        public StackValue lookupOuterValue(EnclosedValueDescriptor d) {
1680            DeclarationDescriptor descriptor = d.getDescriptor();
1681            for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
1682                if (aCase.isCase(descriptor)) {
1683                    return aCase.outerValue(d, this);
1684                }
1685            }
1686            throw new IllegalStateException("Can't get outer value in " + this + " for " + d);
1687        }
1688    
1689        private StackValueWithLeaveTask generateBlock(
1690                List<KtExpression> statements,
1691                boolean isStatement,
1692                Label labelBeforeLastExpression,
1693                @Nullable final Label labelBlockEnd
1694        ) {
1695            final Label blockEnd = labelBlockEnd != null ? labelBlockEnd : new Label();
1696    
1697            final List<Function<StackValue, Void>> leaveTasks = Lists.newArrayList();
1698    
1699            StackValue answer = StackValue.none();
1700    
1701            for (Iterator<KtExpression> iterator = statements.iterator(); iterator.hasNext(); ) {
1702                KtExpression possiblyLabeledStatement = iterator.next();
1703    
1704                KtElement statement = KtPsiUtil.safeDeparenthesize(possiblyLabeledStatement);
1705    
1706                if (statement instanceof KtNamedDeclaration) {
1707                    KtNamedDeclaration declaration = (KtNamedDeclaration) statement;
1708                    if (KtPsiUtil.isScriptDeclaration(declaration)) {
1709                        continue;
1710                    }
1711                }
1712    
1713                putDescriptorIntoFrameMap(statement);
1714    
1715                boolean isExpression = !iterator.hasNext() && !isStatement;
1716                if (isExpression && labelBeforeLastExpression != null) {
1717                    v.mark(labelBeforeLastExpression);
1718                }
1719    
1720                StackValue result = isExpression ? gen(possiblyLabeledStatement) : genStatement(possiblyLabeledStatement);
1721    
1722                if (!iterator.hasNext()) {
1723                    answer = result;
1724                }
1725                else {
1726                    result.put(Type.VOID_TYPE, v);
1727                }
1728    
1729                addLeaveTaskToRemoveDescriptorFromFrameMap(statement, blockEnd, leaveTasks);
1730            }
1731    
1732            return new StackValueWithLeaveTask(answer, new Function1<StackValue, Unit>() {
1733                @Override
1734                public Unit invoke(StackValue value) {
1735                    if (labelBlockEnd == null) {
1736                        v.mark(blockEnd);
1737                    }
1738                    for (Function<StackValue, Void> task : Lists.reverse(leaveTasks)) {
1739                        task.fun(value);
1740                    }
1741                    return Unit.INSTANCE;
1742                }
1743            });
1744        }
1745    
1746        @NotNull
1747        private Type getVariableType(@NotNull VariableDescriptor variableDescriptor) {
1748            Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
1749            return sharedVarType != null ? sharedVarType : asmType(variableDescriptor.getType());
1750        }
1751    
1752        private static boolean isSharedVarType(@NotNull Type type) {
1753            return type.getSort() == Type.OBJECT && type.getInternalName().startsWith(REF_TYPE_PREFIX);
1754        }
1755    
1756    
1757        private void putDescriptorIntoFrameMap(@NotNull KtElement statement) {
1758            if (statement instanceof KtDestructuringDeclaration) {
1759                KtDestructuringDeclaration multiDeclaration = (KtDestructuringDeclaration) statement;
1760                for (KtDestructuringDeclarationEntry entry : multiDeclaration.getEntries()) {
1761                    putLocalVariableIntoFrameMap(entry);
1762                }
1763            }
1764    
1765            if (statement instanceof KtVariableDeclaration) {
1766                putLocalVariableIntoFrameMap((KtVariableDeclaration) statement);
1767            }
1768    
1769            if (statement instanceof KtNamedFunction) {
1770                DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, statement);
1771                assert descriptor instanceof FunctionDescriptor : "Couldn't find function declaration in binding context " + statement.getText();
1772                Type type = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
1773                myFrameMap.enter(descriptor, type);
1774            }
1775        }
1776    
1777        private void putLocalVariableIntoFrameMap(@NotNull KtVariableDeclaration statement) {
1778            VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, statement);
1779            assert variableDescriptor != null : "Couldn't find variable declaration in binding context " + statement.getText();
1780    
1781            Type type = getVariableType(variableDescriptor);
1782            int index = myFrameMap.enter(variableDescriptor, type);
1783    
1784            if (isSharedVarType(type)) {
1785                markLineNumber(statement, false);
1786                v.anew(type);
1787                v.dup();
1788                v.invokespecial(type.getInternalName(), "<init>", "()V", false);
1789                v.store(index, OBJECT_TYPE);
1790            }
1791        }
1792    
1793        private void addLeaveTaskToRemoveDescriptorFromFrameMap(
1794                @NotNull KtElement statement,
1795                @NotNull Label blockEnd,
1796                @NotNull List<Function<StackValue, Void>> leaveTasks
1797        ) {
1798            if (statement instanceof KtDestructuringDeclaration) {
1799                KtDestructuringDeclaration multiDeclaration = (KtDestructuringDeclaration) statement;
1800                for (KtDestructuringDeclarationEntry entry : multiDeclaration.getEntries()) {
1801                    addLeaveTaskToRemoveLocalVariableFromFrameMap(entry, blockEnd, leaveTasks);
1802                }
1803            }
1804    
1805            if (statement instanceof KtVariableDeclaration) {
1806                addLeaveTaskToRemoveLocalVariableFromFrameMap((KtVariableDeclaration) statement, blockEnd, leaveTasks);
1807            }
1808    
1809            if (statement instanceof KtNamedFunction) {
1810                addLeaveTaskToRemoveNamedFunctionFromFrameMap((KtNamedFunction) statement, blockEnd, leaveTasks);
1811            }
1812        }
1813    
1814        private void addLeaveTaskToRemoveLocalVariableFromFrameMap(
1815                @NotNull KtVariableDeclaration statement,
1816                final Label blockEnd,
1817                @NotNull List<Function<StackValue, Void>> leaveTasks
1818        ) {
1819            final VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, statement);
1820            assert variableDescriptor != null;
1821    
1822            final Type type = getVariableType(variableDescriptor);
1823    
1824            final Label scopeStart = new Label();
1825            v.mark(scopeStart);
1826    
1827            leaveTasks.add(new Function<StackValue, Void>() {
1828                @Override
1829                public Void fun(StackValue answer) {
1830                    int index = myFrameMap.leave(variableDescriptor);
1831    
1832                    if (isSharedVarType(type)) {
1833                        v.aconst(null);
1834                        v.store(index, OBJECT_TYPE);
1835                    }
1836                    v.visitLocalVariable(variableDescriptor.getName().asString(), type.getDescriptor(), null, scopeStart, blockEnd, index);
1837                    return null;
1838                }
1839            });
1840        }
1841    
1842        private void addLeaveTaskToRemoveNamedFunctionFromFrameMap(
1843                @NotNull final KtNamedFunction statement,
1844                final Label blockEnd,
1845                @NotNull List<Function<StackValue, Void>> leaveTasks
1846        ) {
1847            final FunctionDescriptor functionDescriptor = (FunctionDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, statement);
1848            assert functionDescriptor != null;
1849    
1850            final Type type = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
1851    
1852            final Label scopeStart = new Label();
1853            v.mark(scopeStart);
1854    
1855            leaveTasks.add(new Function<StackValue, Void>() {
1856                @Override
1857                public Void fun(StackValue answer) {
1858                    int index = myFrameMap.leave(functionDescriptor);
1859    
1860                    assert !functionDescriptor.getName().isSpecial() : "Local variable should be generated only for function with name: " + statement.getText();
1861                    v.visitLocalVariable(functionDescriptor.getName().asString() + "$", type.getDescriptor(), null, scopeStart, blockEnd, index);
1862                    return null;
1863                }
1864            });
1865        }
1866    
1867        public boolean isShouldMarkLineNumbers() {
1868            return shouldMarkLineNumbers;
1869        }
1870    
1871        public void setShouldMarkLineNumbers(boolean shouldMarkLineNumbers) {
1872            this.shouldMarkLineNumbers = shouldMarkLineNumbers;
1873        }
1874    
1875        public void markStartLineNumber(@NotNull KtElement element) {
1876            markLineNumber(element, false);
1877        }
1878    
1879        public void markLineNumber(@NotNull KtElement statement, boolean markEndOffset) {
1880            if (!shouldMarkLineNumbers) return;
1881    
1882            Integer lineNumber = CodegenUtil.getLineNumberForElement(statement, markEndOffset);
1883            if (lineNumber == null || lineNumber == myLastLineNumber) {
1884                return;
1885            }
1886            myLastLineNumber = lineNumber;
1887    
1888            Label label = new Label();
1889            v.visitLabel(label);
1890            v.visitLineNumber(lineNumber, label);
1891        }
1892    
1893        //we should generate additional linenumber info after inline call only if it used as argument
1894        public void markLineNumberAfterInlineIfNeeded() {
1895            if (!shouldMarkLineNumbers) {
1896                //if it used as general argument
1897                if (myLastLineNumber > -1) {
1898                    Label label = new Label();
1899                    v.visitLabel(label);
1900                    v.visitLineNumber(myLastLineNumber, label);
1901                }
1902            } else {
1903                //if it used as argument of infix call (in this case lineNumber for simple inlineCall also would be reset)
1904                myLastLineNumber = -1;
1905            }
1906        }
1907    
1908        public int getLastLineNumber() {
1909            return myLastLineNumber;
1910        }
1911    
1912        private void doFinallyOnReturn(@NotNull Label afterReturnLabel) {
1913            if(!blockStackElements.isEmpty()) {
1914                BlockStackElement stackElement = blockStackElements.peek();
1915                if (stackElement instanceof FinallyBlockStackElement) {
1916                    FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement;
1917                    genFinallyBlockOrGoto(finallyBlockStackElement, null, afterReturnLabel);
1918                }
1919                else if (stackElement instanceof LoopBlockStackElement) {
1920    
1921                } else {
1922                    throw new UnsupportedOperationException("Wrong BlockStackElement in processing stack");
1923                }
1924    
1925                blockStackElements.pop();
1926                doFinallyOnReturn(afterReturnLabel);
1927                blockStackElements.push(stackElement);
1928            }
1929        }
1930    
1931        public boolean hasFinallyBlocks() {
1932            for (BlockStackElement element : blockStackElements) {
1933                if (element instanceof FinallyBlockStackElement) {
1934                    return true;
1935                }
1936            }
1937            return false;
1938        }
1939    
1940        private void genFinallyBlockOrGoto(
1941                @Nullable FinallyBlockStackElement finallyBlockStackElement,
1942                @Nullable Label tryCatchBlockEnd,
1943                @Nullable Label afterJumpLabel
1944        ) {
1945            if (finallyBlockStackElement != null) {
1946                finallyDepth++;
1947                assert finallyBlockStackElement.gaps.size() % 2 == 0 : "Finally block gaps are inconsistent";
1948    
1949                BlockStackElement topOfStack = blockStackElements.pop();
1950                assert topOfStack == finallyBlockStackElement : "Top element of stack doesn't equals processing finally block";
1951    
1952                KtTryExpression jetTryExpression = finallyBlockStackElement.expression;
1953                Label finallyStart = new Label();
1954                v.mark(finallyStart);
1955                finallyBlockStackElement.addGapLabel(finallyStart);
1956                if (InlineCodegenUtil.isFinallyMarkerRequired(context)) {
1957                    InlineCodegenUtil.generateFinallyMarker(v, finallyDepth, true);
1958                }
1959                //noinspection ConstantConditions
1960                gen(jetTryExpression.getFinallyBlock().getFinalExpression(), Type.VOID_TYPE);
1961    
1962                if (InlineCodegenUtil.isFinallyMarkerRequired(context)) {
1963                    InlineCodegenUtil.generateFinallyMarker(v, finallyDepth, false);
1964                }
1965            }
1966    
1967            if (tryCatchBlockEnd != null) {
1968                v.goTo(tryCatchBlockEnd);
1969            }
1970    
1971            if (finallyBlockStackElement != null) {
1972                finallyDepth--;
1973                Label finallyEnd = afterJumpLabel != null ? afterJumpLabel : new Label();
1974                if (afterJumpLabel == null) {
1975                    v.mark(finallyEnd);
1976                }
1977                finallyBlockStackElement.addGapLabel(finallyEnd);
1978    
1979                blockStackElements.push(finallyBlockStackElement);
1980            }
1981        }
1982    
1983        @Override
1984        public StackValue visitReturnExpression(@NotNull final KtReturnExpression expression, StackValue receiver) {
1985            return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
1986                @Override
1987                public Unit invoke(InstructionAdapter adapter) {
1988                    KtExpression returnedExpression = expression.getReturnedExpression();
1989                    CallableMemberDescriptor descriptor = getContext().getContextDescriptor();
1990                    NonLocalReturnInfo nonLocalReturn = getNonLocalReturnInfo(descriptor, expression);
1991                    boolean isNonLocalReturn = nonLocalReturn != null;
1992                    if (isNonLocalReturn && !state.isInlineEnabled()) {
1993                        state.getDiagnostics().report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE.on(expression));
1994                        genThrow(v, "java/lang/UnsupportedOperationException",
1995                                 "Non-local returns are not allowed with inlining disabled");
1996                        return Unit.INSTANCE;
1997                    }
1998    
1999                    Type returnType = isNonLocalReturn ? nonLocalReturn.returnType : ExpressionCodegen.this.returnType;
2000                    if (returnedExpression != null) {
2001                        gen(returnedExpression, returnType);
2002                    }
2003    
2004                    Label afterReturnLabel = new Label();
2005                    generateFinallyBlocksIfNeeded(returnType, afterReturnLabel);
2006    
2007                    if (isNonLocalReturn) {
2008                        InlineCodegenUtil.generateGlobalReturnFlag(v, nonLocalReturn.labelName);
2009                    }
2010                    v.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
2011                    v.mark(afterReturnLabel);
2012                    return Unit.INSTANCE;
2013                }
2014            });
2015        }
2016    
2017        public void generateFinallyBlocksIfNeeded(Type returnType, @NotNull Label afterReturnLabel) {
2018            if (hasFinallyBlocks()) {
2019                if (!Type.VOID_TYPE.equals(returnType)) {
2020                    int returnValIndex = myFrameMap.enterTemp(returnType);
2021                    StackValue.Local localForReturnValue = StackValue.local(returnValIndex, returnType);
2022                    localForReturnValue.store(StackValue.onStack(returnType), v);
2023                    doFinallyOnReturn(afterReturnLabel);
2024                    localForReturnValue.put(returnType, v);
2025                    myFrameMap.leaveTemp(returnType);
2026                }
2027                else {
2028                    doFinallyOnReturn(afterReturnLabel);
2029                }
2030            }
2031        }
2032    
2033        @Nullable
2034        private NonLocalReturnInfo getNonLocalReturnInfo(@NotNull CallableMemberDescriptor descriptor, @NotNull KtReturnExpression expression) {
2035            //call inside lambda
2036            if (isFunctionLiteral(descriptor) || isFunctionExpression(descriptor)) {
2037                if (expression.getLabelName() == null) {
2038                    if (isFunctionLiteral(descriptor)) {
2039                        //non labeled return couldn't be local in lambda
2040                        FunctionDescriptor containingFunction =
2041                                BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst();
2042                        //FIRST_FUN_LABEL to prevent clashing with existing labels
2043                        return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.FIRST_FUN_LABEL);
2044                    } else {
2045                        //local
2046                        return null;
2047                    }
2048                }
2049    
2050                PsiElement element = bindingContext.get(LABEL_TARGET, expression.getTargetLabel());
2051                if (element != DescriptorToSourceUtils.getSourceFromDescriptor(context.getContextDescriptor())) {
2052                    DeclarationDescriptor elementDescriptor = typeMapper.getBindingContext().get(DECLARATION_TO_DESCRIPTOR, element);
2053                    assert element != null : "Expression should be not null " + expression.getText();
2054                    assert elementDescriptor != null : "Descriptor should be not null: " + element.getText();
2055                    return new NonLocalReturnInfo(typeMapper.mapReturnType((CallableDescriptor) elementDescriptor), expression.getLabelName());
2056                }
2057            }
2058            return null;
2059        }
2060    
2061        public void returnExpression(KtExpression expr) {
2062            boolean isBlockedNamedFunction = expr instanceof KtBlockExpression && expr.getParent() instanceof KtNamedFunction;
2063    
2064            // If generating body for named block-bodied function, generate it as sequence of statements
2065            gen(expr, isBlockedNamedFunction ? Type.VOID_TYPE : returnType);
2066    
2067            // If it does not end with return we should return something
2068            // because if we don't there can be VerifyError (specific cases with Nothing-typed expressions)
2069            if (!endsWithReturn(expr)) {
2070                markLineNumber(expr, true);
2071    
2072                if (isLambdaVoidBody(expr, returnType)) {
2073                    markLineNumber((KtFunctionLiteral) expr.getParent(), true);
2074                }
2075    
2076                if (isBlockedNamedFunction && !Type.VOID_TYPE.equals(expressionType(expr))) {
2077                    StackValue.none().put(returnType, v);
2078                }
2079    
2080                v.areturn(returnType);
2081            }
2082        }
2083    
2084        private static boolean endsWithReturn(KtElement bodyExpression) {
2085            if (bodyExpression instanceof KtBlockExpression) {
2086                List<KtExpression> statements = ((KtBlockExpression) bodyExpression).getStatements();
2087                return statements.size() > 0 && statements.get(statements.size() - 1) instanceof KtReturnExpression;
2088            }
2089    
2090            return bodyExpression instanceof KtReturnExpression;
2091        }
2092    
2093        private static boolean isLambdaVoidBody(KtElement bodyExpression, Type returnType) {
2094            if (bodyExpression instanceof KtBlockExpression) {
2095                PsiElement parent = bodyExpression.getParent();
2096                if (parent instanceof KtFunctionLiteral) {
2097                    return Type.VOID_TYPE.equals(returnType);
2098                }
2099            }
2100    
2101            return false;
2102        }
2103    
2104        @Override
2105        public StackValue visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression, @NotNull StackValue receiver) {
2106            ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext);
2107    
2108            DeclarationDescriptor descriptor;
2109            if (resolvedCall == null) {
2110                descriptor = bindingContext.get(REFERENCE_TARGET, expression);
2111            }
2112            else {
2113                if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
2114                    VariableAsFunctionResolvedCall call = (VariableAsFunctionResolvedCall) resolvedCall;
2115                    resolvedCall = call.getVariableCall();
2116                }
2117    
2118                descriptor = resolvedCall.getResultingDescriptor();
2119    
2120                //Check early if KCallableNameProperty is applicable to prevent closure generation
2121                StackValue intrinsicResult = applyIntrinsic(descriptor, KCallableNameProperty.class, resolvedCall, receiver);
2122                if (intrinsicResult != null) return intrinsicResult;
2123    
2124                receiver = StackValue.receiver(resolvedCall, receiver, this, null);
2125                if (descriptor instanceof FakeCallableDescriptorForObject) {
2126                    descriptor = ((FakeCallableDescriptorForObject) descriptor).getReferencedDescriptor();
2127                }
2128            }
2129    
2130            assert descriptor != null : "Couldn't find descriptor for '" + expression.getText() + "'";
2131            descriptor = descriptor.getOriginal();
2132    
2133            boolean isSyntheticField = descriptor instanceof SyntheticFieldDescriptor;
2134            if (isSyntheticField) {
2135                descriptor = ((SyntheticFieldDescriptor) descriptor).getPropertyDescriptor();
2136            }
2137    
2138            StackValue intrinsicResult = applyIntrinsic(descriptor, IntrinsicPropertyGetter.class, resolvedCall, receiver);
2139            if (intrinsicResult != null) return intrinsicResult;
2140    
2141            if (descriptor instanceof PropertyDescriptor) {
2142                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
2143    
2144                Collection<ExpressionCodegenExtension> codegenExtensions = ExpressionCodegenExtension.Companion.getInstances(state.getProject());
2145                if (!codegenExtensions.isEmpty() && resolvedCall != null) {
2146                    ExpressionCodegenExtension.Context context = new ExpressionCodegenExtension.Context(typeMapper, v);
2147                    KotlinType returnType = propertyDescriptor.getReturnType();
2148                    for (ExpressionCodegenExtension extension : codegenExtensions) {
2149                        if (returnType != null) {
2150                            StackValue value = extension.applyProperty(receiver, resolvedCall, context);
2151                            if (value != null) return value;
2152                        }
2153                    }
2154                }
2155    
2156                boolean directToField = isSyntheticField && contextKind() != OwnerKind.DEFAULT_IMPLS;
2157                ClassDescriptor superCallTarget = resolvedCall == null ? null : getSuperCallTarget(resolvedCall.getCall());
2158    
2159                if (directToField) {
2160                    receiver = StackValue.receiverWithoutReceiverArgument(receiver);
2161                }
2162    
2163                return intermediateValueForProperty(propertyDescriptor, directToField, directToField, superCallTarget, false, receiver);
2164            }
2165    
2166            if (descriptor instanceof ClassDescriptor) {
2167                ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
2168                if (isObject(classDescriptor)) {
2169                    return StackValue.singleton(classDescriptor, typeMapper);
2170                }
2171                if (isEnumEntry(classDescriptor)) {
2172                    return StackValue.enumEntry(classDescriptor, typeMapper);
2173                }
2174                ClassDescriptor companionObjectDescriptor = classDescriptor.getCompanionObjectDescriptor();
2175                if (companionObjectDescriptor != null) {
2176                    return StackValue.singleton(companionObjectDescriptor, typeMapper);
2177                }
2178                return StackValue.none();
2179            }
2180    
2181            StackValue localOrCaptured = findLocalOrCapturedValue(descriptor);
2182            if (localOrCaptured != null) {
2183                return localOrCaptured;
2184            }
2185            throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
2186        }
2187    
2188        @Nullable
2189        private StackValue applyIntrinsic(
2190                DeclarationDescriptor descriptor,
2191                Class<? extends IntrinsicPropertyGetter> intrinsicType,
2192                ResolvedCall<?> resolvedCall,
2193                @NotNull StackValue receiver
2194        ) {
2195            if (descriptor instanceof CallableMemberDescriptor) {
2196                CallableMemberDescriptor memberDescriptor = DescriptorUtils.unwrapFakeOverride((CallableMemberDescriptor) descriptor);
2197                IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(memberDescriptor);
2198                if (intrinsicType.isInstance(intrinsic)) {
2199                    //TODO: intrinsic properties (see intermediateValueForProperty)
2200                    Type returnType = typeMapper.mapType(memberDescriptor);
2201                    return ((IntrinsicPropertyGetter) intrinsic).generate(resolvedCall, this, returnType, receiver);
2202                }
2203            }
2204            return null;
2205        }
2206    
2207        @Nullable
2208        private ClassDescriptor getSuperCallTarget(@NotNull Call call) {
2209            KtSuperExpression superExpression = CallResolverUtilKt.getSuperCallExpression(call);
2210            return superExpression == null ? null : getSuperCallLabelTarget(context, superExpression);
2211        }
2212    
2213        @Nullable
2214        public StackValue findLocalOrCapturedValue(@NotNull DeclarationDescriptor descriptor) {
2215            int index = lookupLocalIndex(descriptor);
2216            if (index >= 0) {
2217                return stackValueForLocal(descriptor, index);
2218            }
2219    
2220            return findCapturedValue(descriptor);
2221        }
2222    
2223        @Nullable
2224        public StackValue findCapturedValue(@NotNull DeclarationDescriptor descriptor) {
2225            if (context instanceof ConstructorContext) {
2226                return lookupCapturedValueInConstructorParameters(descriptor);
2227            }
2228    
2229            return context.lookupInContext(descriptor, StackValue.LOCAL_0, state, false);
2230        }
2231    
2232        @Nullable
2233        private StackValue lookupCapturedValueInConstructorParameters(@NotNull DeclarationDescriptor descriptor) {
2234            StackValue parentResult = context.lookupInContext(descriptor, StackValue.LOCAL_0, state, false);
2235            if (context.closure == null || parentResult == null) return parentResult;
2236    
2237            int parameterOffsetInConstructor = context.closure.getCapturedParameterOffsetInConstructor(descriptor);
2238            // when captured parameter is singleton
2239            // see compiler/testData/codegen/box/objects/objectInLocalAnonymousObject.kt (fun local() captured in A)
2240            if (parameterOffsetInConstructor == -1) return parentResult;
2241    
2242            assert parentResult instanceof StackValue.Field || parentResult instanceof StackValue.FieldForSharedVar
2243                    : "Part of closure should be either Field or FieldForSharedVar";
2244    
2245            if (parentResult instanceof StackValue.FieldForSharedVar) {
2246                return StackValue.shared(parameterOffsetInConstructor, parentResult.type);
2247            }
2248    
2249            return StackValue.local(parameterOffsetInConstructor, parentResult.type);
2250        }
2251    
2252        private StackValue stackValueForLocal(DeclarationDescriptor descriptor, int index) {
2253            if (descriptor instanceof VariableDescriptor) {
2254                Type sharedVarType = typeMapper.getSharedVarType(descriptor);
2255                KotlinType outType = ((VariableDescriptor) descriptor).getType();
2256                if (sharedVarType != null) {
2257                    return StackValue.shared(index, asmType(outType));
2258                }
2259                else {
2260                    return StackValue.local(index, asmType(outType));
2261                }
2262            }
2263            else {
2264                return StackValue.local(index, OBJECT_TYPE);
2265            }
2266        }
2267    
2268        @Override
2269        public boolean lookupLocal(DeclarationDescriptor descriptor) {
2270            return lookupLocalIndex(descriptor) != -1;
2271        }
2272    
2273        public int lookupLocalIndex(DeclarationDescriptor descriptor) {
2274            return myFrameMap.getIndex(descriptor);
2275        }
2276    
2277        @Nullable
2278        private static KotlinType getPropertyDelegateType(@NotNull PropertyDescriptor descriptor, @NotNull BindingContext bindingContext) {
2279            PropertyGetterDescriptor getter = descriptor.getGetter();
2280            if (getter != null) {
2281                Call call = bindingContext.get(DELEGATED_PROPERTY_CALL, getter);
2282                if (call != null) {
2283                    assert call.getExplicitReceiver() != null : "No explicit receiver for call:" + call;
2284                    return ((ReceiverValue) call.getExplicitReceiver()).getType();
2285                }
2286            }
2287            return null;
2288        }
2289    
2290        @NotNull
2291        public StackValue.Property intermediateValueForProperty(
2292                @NotNull PropertyDescriptor propertyDescriptor,
2293                boolean forceField,
2294                @Nullable ClassDescriptor superCallTarget,
2295                @NotNull StackValue receiver
2296        ) {
2297            return intermediateValueForProperty(propertyDescriptor, forceField, false, superCallTarget, false, receiver);
2298        }
2299    
2300        private CodegenContext getBackingFieldContext(
2301                @NotNull FieldAccessorKind accessorKind,
2302                @NotNull DeclarationDescriptor containingDeclaration
2303        ) {
2304            switch (accessorKind) {
2305                case NORMAL: return context.getParentContext();
2306                // For companion object property, backing field lives in object containing class
2307                // Otherwise, it lives in its containing declaration
2308                case IN_CLASS_COMPANION: return context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration());
2309                case FIELD_FROM_LOCAL: return context.findParentContextWithDescriptor(containingDeclaration);
2310                default: throw new IllegalStateException();
2311            }
2312        }
2313    
2314        public StackValue.Property intermediateValueForProperty(
2315                @NotNull PropertyDescriptor propertyDescriptor,
2316                boolean forceField,
2317                boolean syntheticBackingField,
2318                @Nullable ClassDescriptor superCallTarget,
2319                boolean skipAccessorsForPrivateFieldInOuterClass,
2320                StackValue receiver
2321        ) {
2322            if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) {
2323                return intermediateValueForSyntheticExtensionProperty((SyntheticJavaPropertyDescriptor) propertyDescriptor, receiver);
2324            }
2325    
2326            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
2327    
2328            FieldAccessorKind fieldAccessorKind = FieldAccessorKind.NORMAL;
2329            boolean isBackingFieldInClassCompanion = JvmAbi.isPropertyWithBackingFieldInOuterClass(propertyDescriptor);
2330            if (isBackingFieldInClassCompanion && (forceField || propertyDescriptor.isConst() && Visibilities.isPrivate(propertyDescriptor.getVisibility()))) {
2331                fieldAccessorKind = FieldAccessorKind.IN_CLASS_COMPANION;
2332            }
2333            else if (syntheticBackingField && context.getFirstCrossInlineOrNonInlineContext().getParentContext().getContextDescriptor() != containingDeclaration) {
2334                fieldAccessorKind = FieldAccessorKind.FIELD_FROM_LOCAL;
2335            }
2336            boolean isStaticBackingField = DescriptorUtils.isStaticDeclaration(propertyDescriptor) ||
2337                                           AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor);
2338            boolean isSuper = superCallTarget != null;
2339            boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
2340    
2341            KotlinType delegateType = getPropertyDelegateType(propertyDescriptor, bindingContext);
2342            boolean isDelegatedProperty = delegateType != null;
2343    
2344            CallableMethod callableGetter = null;
2345            CallableMethod callableSetter = null;
2346    
2347            CodegenContext backingFieldContext = getBackingFieldContext(fieldAccessorKind, containingDeclaration);
2348            DeclarationDescriptor ownerDescriptor = containingDeclaration;
2349            boolean skipPropertyAccessors;
2350    
2351            PropertyDescriptor originalPropertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
2352            if (fieldAccessorKind != FieldAccessorKind.NORMAL) {
2353                int flags = AsmUtil.getVisibilityForBackingField(propertyDescriptor, isDelegatedProperty);
2354                skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || skipAccessorsForPrivateFieldInOuterClass;
2355                if (!skipPropertyAccessors) {
2356                    //noinspection ConstantConditions
2357                    propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(
2358                            propertyDescriptor, fieldAccessorKind, delegateType, superCallTarget
2359                    );
2360                    assert propertyDescriptor instanceof AccessorForPropertyBackingField :
2361                            "Unexpected accessor descriptor: " + propertyDescriptor;
2362                    ownerDescriptor = propertyDescriptor;
2363                }
2364            }
2365            else {
2366                if (!isBackingFieldInClassCompanion) {
2367                    ownerDescriptor = propertyDescriptor;
2368                }
2369                skipPropertyAccessors = forceField;
2370            }
2371    
2372            if (!skipPropertyAccessors) {
2373                if (!couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context)) {
2374                    propertyDescriptor = context.getAccessorForSuperCallIfNeeded(propertyDescriptor, superCallTarget);
2375    
2376                    propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superCallTarget);
2377    
2378                    PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
2379                    if (getter != null && !isConstOrHasJvmFieldAnnotation(propertyDescriptor)) {
2380                        callableGetter = typeMapper.mapToCallableMethod(getter, isSuper);
2381                    }
2382                }
2383    
2384                if (propertyDescriptor.isVar()) {
2385                    PropertySetterDescriptor setter = propertyDescriptor.getSetter();
2386                    if (setter != null &&
2387                        !couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context) &&
2388                        !isConstOrHasJvmFieldAnnotation(propertyDescriptor)) {
2389                        callableSetter = typeMapper.mapToCallableMethod(setter, isSuper);
2390                    }
2391                }
2392            }
2393    
2394            if (!isStaticBackingField) {
2395                propertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
2396            }
2397    
2398            Type backingFieldOwner = typeMapper.mapOwner(ownerDescriptor);
2399    
2400            String fieldName;
2401            if (isExtensionProperty && !isDelegatedProperty) {
2402                fieldName = null;
2403            }
2404            else if (originalPropertyDescriptor.getContainingDeclaration() == backingFieldContext.getContextDescriptor()) {
2405                assert backingFieldContext instanceof FieldOwnerContext
2406                        : "Actual context is " + backingFieldContext + " but should be instance of FieldOwnerContext";
2407                fieldName = ((FieldOwnerContext) backingFieldContext).getFieldName(propertyDescriptor, isDelegatedProperty);
2408            }
2409            else {
2410                fieldName = KotlinTypeMapper.mapDefaultFieldName(propertyDescriptor, isDelegatedProperty);
2411            }
2412    
2413            return StackValue.property(propertyDescriptor, backingFieldOwner,
2414                                       typeMapper.mapType(
2415                                               isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
2416                                       isStaticBackingField, fieldName, callableGetter, callableSetter, state, receiver);
2417        }
2418    
2419        @NotNull
2420        private StackValue.Property intermediateValueForSyntheticExtensionProperty(
2421                @NotNull SyntheticJavaPropertyDescriptor propertyDescriptor,
2422                StackValue receiver
2423        ) {
2424            Type type = typeMapper.mapType(propertyDescriptor.getOriginal().getType());
2425            CallableMethod callableGetter =
2426                    typeMapper.mapToCallableMethod(context.accessibleDescriptor(propertyDescriptor.getGetMethod(), null), false);
2427            FunctionDescriptor setMethod = propertyDescriptor.getSetMethod();
2428            CallableMethod callableSetter =
2429                    setMethod != null ? typeMapper.mapToCallableMethod(context.accessibleDescriptor(setMethod, null), false) : null;
2430            return StackValue.property(propertyDescriptor, null, type, false, null, callableGetter, callableSetter, state, receiver);
2431        }
2432    
2433        @Override
2434        public StackValue visitCallExpression(@NotNull KtCallExpression expression, StackValue receiver) {
2435            ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
2436            FunctionDescriptor descriptor = accessibleFunctionDescriptor(resolvedCall);
2437    
2438            if (descriptor instanceof ConstructorDescriptor) {
2439                return generateNewCall(expression, resolvedCall);
2440            }
2441    
2442            if (descriptor.getOriginal() instanceof SamConstructorDescriptor) {
2443                KtExpression argumentExpression = bindingContext.get(SAM_CONSTRUCTOR_TO_ARGUMENT, expression);
2444                assert argumentExpression != null : "Argument expression is not saved for a SAM constructor: " + descriptor;
2445                return genSamInterfaceValue(argumentExpression, this);
2446            }
2447    
2448            return invokeFunction(resolvedCall, receiver);
2449        }
2450    
2451        @Nullable
2452        private StackValue genSamInterfaceValue(
2453                @NotNull KtExpression probablyParenthesizedExpression,
2454                @NotNull final KtVisitor<StackValue, StackValue> visitor
2455        ) {
2456            final KtExpression expression = KtPsiUtil.deparenthesize(probablyParenthesizedExpression);
2457            final SamType samType = bindingContext.get(SAM_VALUE, probablyParenthesizedExpression);
2458            if (samType == null || expression == null) return null;
2459    
2460            if (expression instanceof KtLambdaExpression) {
2461                return genClosure(((KtLambdaExpression) expression).getFunctionLiteral(), samType);
2462            }
2463    
2464            if (expression instanceof KtNamedFunction) {
2465                return genClosure((KtNamedFunction) expression, samType);
2466            }
2467    
2468            final Type asmType =
2469                    state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingKtFile(), this);
2470    
2471            return StackValue.operation(asmType, new Function1<InstructionAdapter, Unit>() {
2472                @Override
2473                public Unit invoke(InstructionAdapter v) {
2474                    v.anew(asmType);
2475                    v.dup();
2476    
2477                    Type functionType = typeMapper.mapType(samType.getKotlinFunctionType());
2478                    expression.accept(visitor, StackValue.none()).put(functionType, v);
2479    
2480                    Label ifNonNull = new Label();
2481                    Label afterAll = new Label();
2482    
2483                    v.dup();
2484                    v.ifnonnull(ifNonNull);
2485    
2486                    // if null: pop function value and wrapper objects, put null
2487                    v.pop();
2488                    v.pop2();
2489                    v.aconst(null);
2490                    v.goTo(afterAll);
2491    
2492                    v.mark(ifNonNull);
2493                    v.invokespecial(asmType.getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, functionType), false);
2494    
2495                    v.mark(afterAll);
2496                    return null;
2497                }
2498            });
2499        }
2500    
2501        @NotNull
2502        protected FunctionDescriptor accessibleFunctionDescriptor(@NotNull ResolvedCall<?> resolvedCall) {
2503            FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
2504            FunctionDescriptor originalIfSamAdapter = SamCodegenUtil.getOriginalIfSamAdapter(descriptor);
2505            if (originalIfSamAdapter != null) {
2506                descriptor = originalIfSamAdapter;
2507            }
2508            // $default method is not private, so you need no accessor to call it
2509            return CallUtilKt.usesDefaultArguments(resolvedCall)
2510                   ? descriptor
2511                   : context.accessibleDescriptor(descriptor, getSuperCallTarget(resolvedCall.getCall()));
2512        }
2513    
2514        @NotNull
2515        public StackValue invokeFunction(@NotNull ResolvedCall<?> resolvedCall, @NotNull StackValue receiver) {
2516            return invokeFunction(resolvedCall.getCall(), resolvedCall, receiver);
2517        }
2518    
2519        @NotNull
2520        public StackValue invokeFunction(@NotNull Call call, @NotNull ResolvedCall<?> resolvedCall, @NotNull StackValue receiver) {
2521            FunctionDescriptor fd = accessibleFunctionDescriptor(resolvedCall);
2522            ClassDescriptor superCallTarget = getSuperCallTarget(call);
2523    
2524            fd = context.getAccessorForSuperCallIfNeeded(fd, superCallTarget);
2525    
2526            Collection<ExpressionCodegenExtension> codegenExtensions = ExpressionCodegenExtension.Companion.getInstances(state.getProject());
2527            if (!codegenExtensions.isEmpty()) {
2528                ExpressionCodegenExtension.Context context = new ExpressionCodegenExtension.Context(typeMapper, v);
2529                for (ExpressionCodegenExtension extension : codegenExtensions) {
2530                    StackValue stackValue = extension.applyFunction(receiver, resolvedCall, context);
2531                    if (stackValue != null) return stackValue;
2532                }
2533            }
2534    
2535            Callable callable = resolveToCallable(fd, superCallTarget != null, resolvedCall);
2536    
2537            return callable.invokeMethodWithArguments(resolvedCall, receiver, this);
2538        }
2539    
2540        @Nullable
2541        // Find the first parent of the current context which corresponds to a subclass of a given class
2542        public static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) {
2543            CodegenContext c = context;
2544            while (c != null) {
2545                if (c instanceof ClassContext && DescriptorUtils.isSubclass(c.getThisDescriptor(), descriptor)) {
2546                    return c;
2547                }
2548                c = c.getParentContext();
2549            }
2550            return null;
2551        }
2552    
2553        @NotNull
2554        Callable resolveToCallable(@NotNull FunctionDescriptor fd, boolean superCall, @NotNull ResolvedCall resolvedCall) {
2555            IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(fd);
2556            if (intrinsic != null) {
2557                return intrinsic.toCallable(fd, superCall, resolvedCall, this);
2558            }
2559    
2560            return resolveToCallableMethod(fd, superCall);
2561        }
2562    
2563        @NotNull
2564        private CallableMethod resolveToCallableMethod(@NotNull FunctionDescriptor fd, boolean superCall) {
2565            return typeMapper.mapToCallableMethod(SamCodegenUtil.resolveSamAdapter(fd), superCall);
2566        }
2567    
2568        public void invokeMethodWithArguments(
2569                @NotNull Callable callableMethod,
2570                @NotNull ResolvedCall<?> resolvedCall,
2571                @NotNull StackValue receiver
2572        ) {
2573            CallGenerator callGenerator = getOrCreateCallGenerator(resolvedCall);
2574            CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
2575    
2576            assert callGenerator == defaultCallGenerator || !tailRecursionCodegen.isTailRecursion(resolvedCall) :
2577                    "Tail recursive method can't be inlined: " + descriptor;
2578    
2579            ArgumentGenerator argumentGenerator = new CallBasedArgumentGenerator(this, callGenerator, descriptor.getValueParameters(),
2580                                                                                 callableMethod.getValueParameterTypes());
2581    
2582            invokeMethodWithArguments(callableMethod, resolvedCall, receiver, callGenerator, argumentGenerator);
2583        }
2584    
2585        public void invokeMethodWithArguments(
2586                @NotNull Callable callableMethod,
2587                @NotNull ResolvedCall<?> resolvedCall,
2588                @NotNull StackValue receiver,
2589                @NotNull CallGenerator callGenerator,
2590                @NotNull ArgumentGenerator argumentGenerator
2591        ) {
2592            boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor;
2593            if (!isConstructor) { // otherwise already
2594                receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
2595                receiver.put(receiver.type, v);
2596                callableMethod.afterReceiverGeneration(v);
2597            }
2598    
2599            callGenerator.putHiddenParams();
2600    
2601            List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
2602            assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor();
2603    
2604            DefaultCallArgs defaultArgs =
2605                    argumentGenerator.generate(valueArguments, new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()));
2606    
2607            if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
2608                tailRecursionCodegen.generateTailRecursion(resolvedCall);
2609                return;
2610            }
2611    
2612            boolean defaultMaskWasGenerated = defaultArgs.generateOnStackIfNeeded(callGenerator, isConstructor);
2613    
2614            // Extra constructor marker argument
2615            if (callableMethod instanceof CallableMethod) {
2616                List<JvmMethodParameterSignature> callableParameters = ((CallableMethod) callableMethod).getValueParameters();
2617                for (JvmMethodParameterSignature parameter: callableParameters) {
2618                    if (parameter.getKind() == JvmMethodParameterKind.CONSTRUCTOR_MARKER) {
2619                        callGenerator.putValueIfNeeded(parameter.getAsmType(), StackValue.constant(null, parameter.getAsmType()));
2620                    }
2621                }
2622            }
2623    
2624            callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this);
2625    
2626            KotlinType returnType = resolvedCall.getResultingDescriptor().getReturnType();
2627            if (returnType != null && KotlinBuiltIns.isNothing(returnType)) {
2628                v.aconst(null);
2629                v.athrow();
2630            }
2631        }
2632    
2633        @NotNull
2634        private CallGenerator getOrCreateCallGenerator(
2635                @NotNull CallableDescriptor descriptor,
2636                @Nullable KtElement callElement,
2637                @Nullable TypeParameterMappings typeParameterMappings,
2638                boolean isDefaultCompilation
2639        ) {
2640            if (callElement == null) return defaultCallGenerator;
2641    
2642            // We should inline callable containing reified type parameters even if inline is disabled
2643            // because they may contain something to reify and straight call will probably fail at runtime
2644            boolean isInline = (state.isInlineEnabled() || InlineUtil.containsReifiedTypeParameters(descriptor)) &&
2645                               (InlineUtil.isInline(descriptor) || InlineUtil.isArrayConstructorWithLambda(descriptor));
2646    
2647            if (!isInline) return defaultCallGenerator;
2648    
2649            FunctionDescriptor original = DescriptorUtils.unwrapFakeOverride((FunctionDescriptor) descriptor.getOriginal());
2650            if (isDefaultCompilation) {
2651                return new InlineCodegenForDefaultBody(original, this, state);
2652            }
2653            else {
2654                return new InlineCodegen(this, state, original, callElement, typeParameterMappings);
2655            }
2656        }
2657    
2658        @NotNull
2659        protected CallGenerator getOrCreateCallGeneratorForDefaultImplBody(@NotNull FunctionDescriptor descriptor, @Nullable KtNamedFunction function) {
2660            return getOrCreateCallGenerator(descriptor, function, null, true);
2661        }
2662    
2663        @NotNull
2664        CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall) {
2665            Map<TypeParameterDescriptor, KotlinType> typeArguments = resolvedCall.getTypeArguments();
2666            TypeParameterMappings mappings = new TypeParameterMappings();
2667            for (Map.Entry<TypeParameterDescriptor, KotlinType> entry : typeArguments.entrySet()) {
2668                TypeParameterDescriptor key = entry.getKey();
2669                KotlinType type = entry.getValue();
2670    
2671                boolean isReified = key.isReified() || InlineUtil.isArrayConstructorWithLambda(resolvedCall.getResultingDescriptor());
2672    
2673                Pair<TypeParameterDescriptor, ReificationArgument> typeParameterAndReificationArgument = extractReificationArgument(type);
2674                if (typeParameterAndReificationArgument == null) {
2675                    KotlinType approximatedType = CapturedTypeApproximationKt.approximateCapturedTypes(entry.getValue()).getUpper();
2676                    // type is not generic
2677                    JvmSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.TYPE);
2678                    Type asmType = typeMapper.mapTypeParameter(approximatedType, signatureWriter);
2679    
2680                    mappings.addParameterMappingToType(
2681                            key.getName().getIdentifier(), approximatedType, asmType, signatureWriter.toString(), isReified
2682                    );
2683                }
2684                else {
2685                    mappings.addParameterMappingForFurtherReification(
2686                            key.getName().getIdentifier(), type, typeParameterAndReificationArgument.getSecond(), isReified
2687                    );
2688                }
2689            }
2690            return getOrCreateCallGenerator(
2691                    resolvedCall.getResultingDescriptor(), resolvedCall.getCall().getCallElement(), mappings, false);
2692        }
2693    
2694    
2695        @Nullable
2696        private static Pair<TypeParameterDescriptor, ReificationArgument> extractReificationArgument(@NotNull KotlinType type) {
2697            int arrayDepth = 0;
2698            boolean isNullable = type.isMarkedNullable();
2699            while (KotlinBuiltIns.isArray(type)) {
2700                arrayDepth++;
2701                type = type.getArguments().get(0).getType();
2702            }
2703    
2704            TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(type);
2705            if (parameterDescriptor == null) return null;
2706    
2707            return new Pair<TypeParameterDescriptor, ReificationArgument>(
2708                    parameterDescriptor,
2709                    new ReificationArgument(parameterDescriptor.getName().asString(), isNullable, arrayDepth));
2710        }
2711    
2712        @NotNull
2713        public StackValue generateReceiverValue(@Nullable ReceiverValue receiverValue, boolean isSuper) {
2714            if (receiverValue instanceof ImplicitClassReceiver) {
2715                ClassDescriptor receiverDescriptor = ((ImplicitClassReceiver) receiverValue).getDeclarationDescriptor();
2716                if (DescriptorUtils.isCompanionObject(receiverDescriptor)) {
2717                    CallableMemberDescriptor contextDescriptor = context.getContextDescriptor();
2718                    if (contextDescriptor instanceof FunctionDescriptor && receiverDescriptor == contextDescriptor.getContainingDeclaration()) {
2719                        return StackValue.LOCAL_0;
2720                    }
2721                    else {
2722                        return StackValue.singleton(receiverDescriptor, typeMapper);
2723                    }
2724                }
2725                else if (receiverDescriptor instanceof ScriptDescriptor) {
2726                    return generateScriptReceiver
2727                            ((ScriptDescriptor) receiverDescriptor);
2728                }
2729                else {
2730                    return StackValue.thisOrOuter(this, receiverDescriptor, isSuper,
2731                                                  receiverValue instanceof CastImplicitClassReceiver || isEnumEntry(receiverDescriptor));
2732                }
2733            }
2734            else if (receiverValue instanceof ExtensionReceiver) {
2735                return generateReceiver(((ExtensionReceiver) receiverValue).getDeclarationDescriptor());
2736            }
2737            else if (receiverValue instanceof ExpressionReceiver) {
2738                return gen(((ExpressionReceiver) receiverValue).getExpression());
2739            }
2740            else {
2741                throw new UnsupportedOperationException("Unsupported receiver value: " + receiverValue);
2742            }
2743        }
2744    
2745        @NotNull
2746        private StackValue generateReceiver(@NotNull CallableDescriptor descriptor) {
2747            return context.generateReceiver(descriptor, state, false);
2748        }
2749    
2750        @NotNull
2751        private StackValue generateScriptReceiver(@NotNull ScriptDescriptor receiver) {
2752            CodegenContext cur = context;
2753            StackValue result = StackValue.LOCAL_0;
2754            boolean inStartConstructorContext = cur instanceof ConstructorContext;
2755            while (cur != null) {
2756                if (!inStartConstructorContext) {
2757                    cur = getNotNullParentContextForMethod(cur);
2758                }
2759    
2760                if (cur instanceof ScriptContext) {
2761                    ScriptContext scriptContext = (ScriptContext) cur;
2762    
2763                    if (scriptContext.getScriptDescriptor() == receiver) {
2764                        //TODO lazy
2765                        return result;
2766                    }
2767                    Type currentScriptType = typeMapper.mapType(scriptContext.getScriptDescriptor());
2768                    Type classType = typeMapper.mapType(receiver);
2769                    String fieldName = scriptContext.getScriptFieldName(receiver);
2770                    return StackValue.field(classType, currentScriptType, fieldName, false, result, receiver);
2771                }
2772    
2773                result = cur.getOuterExpression(result, false);
2774    
2775                if (inStartConstructorContext) {
2776                    cur = getNotNullParentContextForMethod(cur);
2777                    inStartConstructorContext = false;
2778                }
2779    
2780                cur = cur.getParentContext();
2781            }
2782    
2783            throw new UnsupportedOperationException();
2784        }
2785    
2786        @NotNull
2787        public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) {
2788            return generateThisOrOuter(calleeContainingClass, isSuper, false);
2789        }
2790    
2791        @NotNull
2792        public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper, boolean forceOuter) {
2793            boolean isSingleton = calleeContainingClass.getKind().isSingleton();
2794            if (isSingleton) {
2795                if (calleeContainingClass.equals(context.getThisDescriptor()) &&
2796                    !CodegenUtilKt.isJvmStaticInObjectOrClass(context.getContextDescriptor())) {
2797                    return StackValue.local(0, typeMapper.mapType(calleeContainingClass));
2798                }
2799                else if (isEnumEntry(calleeContainingClass)) {
2800                    return StackValue.enumEntry(calleeContainingClass, typeMapper);
2801                }
2802                else {
2803                    return StackValue.singleton(calleeContainingClass, typeMapper);
2804                }
2805            }
2806    
2807            CodegenContext cur = context;
2808            Type type = asmType(calleeContainingClass.getDefaultType());
2809            StackValue result = StackValue.local(0, type);
2810            boolean inStartConstructorContext = cur instanceof ConstructorContext;
2811            while (cur != null) {
2812                ClassDescriptor thisDescriptor = cur.getThisDescriptor();
2813    
2814                if (!isSuper && thisDescriptor == calleeContainingClass) {
2815                    return result;
2816                }
2817    
2818                if (!forceOuter && isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) {
2819                    return castToRequiredTypeOfInterfaceIfNeeded(result, thisDescriptor, calleeContainingClass);
2820                }
2821    
2822                forceOuter = false;
2823    
2824                //for constructor super call we should access to outer instance through parameter in locals, in other cases through field for captured outer
2825                if (inStartConstructorContext) {
2826                    result = cur.getOuterExpression(result, false);
2827                    cur = getNotNullParentContextForMethod(cur);
2828                    inStartConstructorContext = false;
2829                }
2830                else {
2831                    cur = getNotNullParentContextForMethod(cur);
2832                    result = cur.getOuterExpression(result, false);
2833                }
2834    
2835                cur = cur.getParentContext();
2836            }
2837    
2838            throw new UnsupportedOperationException();
2839        }
2840    
2841        @NotNull
2842        private static CodegenContext getNotNullParentContextForMethod(CodegenContext cur) {
2843            if (cur instanceof MethodContext) {
2844                cur = cur.getParentContext();
2845            }
2846            assert cur != null;
2847            return cur;
2848        }
2849    
2850    
2851        public void genVarargs(@NotNull VarargValueArgument valueArgument, @NotNull KotlinType outType) {
2852            Type type = asmType(outType);
2853            assert type.getSort() == Type.ARRAY;
2854            Type elementType = correctElementType(type);
2855            List<ValueArgument> arguments = valueArgument.getArguments();
2856            int size = arguments.size();
2857    
2858            boolean hasSpread = false;
2859            for (int i = 0; i != size; ++i) {
2860                if (arguments.get(i).getSpreadElement() != null) {
2861                    hasSpread = true;
2862                    break;
2863                }
2864            }
2865    
2866            if (hasSpread) {
2867                boolean arrayOfReferences = KotlinBuiltIns.isArray(outType);
2868                if (size == 1) {
2869                    // Arrays.copyOf(receiverValue, newLength)
2870                    ValueArgument argument = arguments.get(0);
2871                    Type arrayType = arrayOfReferences ? Type.getType("[Ljava/lang/Object;")
2872                                                       : Type.getType("[" + elementType.getDescriptor());
2873                    gen(argument.getArgumentExpression(), type);
2874                    v.dup();
2875                    v.arraylength();
2876                    v.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false);
2877                    if (arrayOfReferences) {
2878                        v.checkcast(type);
2879                    }
2880                }
2881                else {
2882                    String owner;
2883                    String addDescriptor;
2884                    String toArrayDescriptor;
2885                    if (arrayOfReferences) {
2886                        owner = "kotlin/jvm/internal/SpreadBuilder";
2887                        addDescriptor = "(Ljava/lang/Object;)V";
2888                        toArrayDescriptor = "([Ljava/lang/Object;)[Ljava/lang/Object;";
2889                    }
2890                    else {
2891                        String spreadBuilderClassName = AsmUtil.asmPrimitiveTypeToLangPrimitiveType(elementType).getTypeName().getIdentifier() + "SpreadBuilder";
2892                        owner = "kotlin/jvm/internal/" + spreadBuilderClassName;
2893                        addDescriptor = "(" + elementType.getDescriptor() + ")V";
2894                        toArrayDescriptor = "()" + type.getDescriptor();
2895                    }
2896                    v.anew(Type.getObjectType(owner));
2897                    v.dup();
2898                    v.iconst(size);
2899                    v.invokespecial(owner, "<init>", "(I)V", false);
2900                    for (int i = 0; i != size; ++i) {
2901                        v.dup();
2902                        ValueArgument argument = arguments.get(i);
2903                        if (argument.getSpreadElement() != null) {
2904                            gen(argument.getArgumentExpression(), OBJECT_TYPE);
2905                            v.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V", false);
2906                        }
2907                        else {
2908                            gen(argument.getArgumentExpression(), elementType);
2909                            v.invokevirtual(owner, "add", addDescriptor, false);
2910                        }
2911                    }
2912                    if (arrayOfReferences) {
2913                        v.dup();
2914                        v.invokevirtual(owner, "size", "()I", false);
2915                        newArrayInstruction(outType);
2916                        v.invokevirtual(owner, "toArray", toArrayDescriptor, false);
2917                        v.checkcast(type);
2918                    }
2919                    else {
2920                        v.invokevirtual(owner, "toArray", toArrayDescriptor, false);
2921                    }
2922                }
2923            }
2924            else {
2925                v.iconst(arguments.size());
2926                newArrayInstruction(outType);
2927                for (int i = 0; i != size; ++i) {
2928                    v.dup();
2929                    StackValue rightSide = gen(arguments.get(i).getArgumentExpression());
2930                    StackValue.arrayElement(elementType, StackValue.onStack(type), StackValue.constant(i, Type.INT_TYPE)).store(rightSide, v);
2931                }
2932            }
2933        }
2934    
2935        public int indexOfLocal(KtReferenceExpression lhs) {
2936            DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, lhs);
2937            if (isVarCapturedInClosure(bindingContext, declarationDescriptor)) {
2938                return -1;
2939            }
2940            return lookupLocalIndex(declarationDescriptor);
2941        }
2942    
2943        @Override
2944        public StackValue visitClassLiteralExpression(@NotNull KtClassLiteralExpression expression, StackValue data) {
2945            KotlinType type = bindingContext.getType(expression);
2946            assert type != null;
2947    
2948            assert state.getReflectionTypes().getKClass().getTypeConstructor().equals(type.getConstructor())
2949                    : "::class expression should be type checked to a KClass: " + type;
2950    
2951            return generateClassLiteralReference(typeMapper, CollectionsKt.single(type.getArguments()).getType(), this);
2952        }
2953    
2954        @Override
2955        public StackValue visitCallableReferenceExpression(@NotNull KtCallableReferenceExpression expression, StackValue data) {
2956            ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression.getCallableReference(), bindingContext);
2957            FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
2958            if (functionDescriptor != null) {
2959                FunctionReferenceGenerationStrategy strategy = new FunctionReferenceGenerationStrategy(state, functionDescriptor, resolvedCall);
2960                return genClosure(expression, functionDescriptor, strategy, null, (FunctionDescriptor) resolvedCall.getResultingDescriptor());
2961            }
2962    
2963            VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
2964            if (variableDescriptor != null) {
2965                return generatePropertyReference(expression, variableDescriptor, resolvedCall);
2966            }
2967    
2968            throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText());
2969        }
2970    
2971        @NotNull
2972        private StackValue generatePropertyReference(
2973                @NotNull KtElement element,
2974                @NotNull VariableDescriptor variableDescriptor,
2975                @NotNull ResolvedCall<?> resolvedCall
2976        ) {
2977            ClassDescriptor classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor);
2978    
2979            ClassBuilder classBuilder = state.getFactory().newVisitor(
2980                    JvmDeclarationOriginKt.OtherOrigin(element),
2981                    typeMapper.mapClass(classDescriptor),
2982                    element.getContainingFile()
2983            );
2984    
2985            PropertyReferenceCodegen codegen = new PropertyReferenceCodegen(
2986                    state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION),
2987                    element, classBuilder, variableDescriptor, resolvedCall
2988            );
2989            codegen.generate();
2990    
2991            return codegen.putInstanceOnStack();
2992        }
2993    
2994        @NotNull
2995        public static StackValue generateClassLiteralReference(@NotNull KotlinTypeMapper typeMapper, @NotNull KotlinType type) {
2996            return generateClassLiteralReference(typeMapper, type, null);
2997        }
2998    
2999        @NotNull
3000        private static StackValue generateClassLiteralReference(@NotNull final KotlinTypeMapper typeMapper, @NotNull final KotlinType type, @Nullable final ExpressionCodegen codegen) {
3001            return StackValue.operation(K_CLASS_TYPE, new Function1<InstructionAdapter, Unit>() {
3002                @Override
3003                public Unit invoke(InstructionAdapter v) {
3004                    Type classAsmType = typeMapper.mapType(type);
3005                    ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
3006                    if (descriptor instanceof TypeParameterDescriptor) {
3007                        TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor;
3008                        assert typeParameterDescriptor.isReified() :
3009                                "Non-reified type parameter under ::class should be rejected by type checker: " + typeParameterDescriptor;
3010                        assert codegen != null :
3011                                "Reference to member of reified type should be rejected by type checker " + typeParameterDescriptor;
3012                        codegen.putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS);
3013                    }
3014    
3015                    putJavaLangClassInstance(v, classAsmType);
3016                    wrapJavaClassIntoKClass(v);
3017    
3018                    return Unit.INSTANCE;
3019                }
3020            });
3021        }
3022    
3023        @Override
3024        public StackValue visitDotQualifiedExpression(@NotNull KtDotQualifiedExpression expression, StackValue receiver) {
3025            StackValue receiverValue = StackValue.none(); //gen(expression.getReceiverExpression())
3026            return genQualified(receiverValue, expression.getSelectorExpression());
3027        }
3028    
3029        private StackValue generateExpressionWithNullFallback(@NotNull KtExpression expression, @NotNull Label ifnull) {
3030            KtExpression deparenthesized = KtPsiUtil.deparenthesize(expression);
3031            assert deparenthesized != null : "Unexpected empty expression";
3032    
3033            expression = deparenthesized;
3034            Type type = expressionType(expression);
3035    
3036            if (expression instanceof KtSafeQualifiedExpression && !isPrimitive(type)) {
3037                return StackValue.coercion(generateSafeQualifiedExpression((KtSafeQualifiedExpression) expression, ifnull), type);
3038            }
3039            else {
3040                return genLazy(expression, type);
3041            }
3042        }
3043    
3044        private StackValue generateSafeQualifiedExpression(@NotNull KtSafeQualifiedExpression expression, @NotNull Label ifNull) {
3045            KtExpression receiver = expression.getReceiverExpression();
3046            KtExpression selector = expression.getSelectorExpression();
3047    
3048            Type receiverType = expressionType(receiver);
3049            StackValue receiverValue = generateExpressionWithNullFallback(receiver, ifNull);
3050    
3051            //Do not optimize for primitives cause in case of safe call extension receiver should be generated before dispatch one
3052            StackValue newReceiver = new StackValue.SafeCall(receiverType, receiverValue, isPrimitive(receiverType) ? null : ifNull);
3053            return genQualified(newReceiver, selector);
3054        }
3055    
3056        @Override
3057        public StackValue visitSafeQualifiedExpression(@NotNull KtSafeQualifiedExpression expression, StackValue unused) {
3058            Label ifnull = new Label();
3059            Type type = boxType(expressionType(expression));
3060    
3061            StackValue value = generateSafeQualifiedExpression(expression, ifnull);
3062            StackValue newReceiver = StackValue.coercion(value, type);
3063            StackValue result;
3064    
3065            if (!isPrimitive(expressionType(expression.getReceiverExpression()))) {
3066                result = new StackValue.SafeFallback(type, ifnull, newReceiver);
3067            } else {
3068                result = newReceiver;
3069            }
3070    
3071            return result;
3072        }
3073    
3074        @Override
3075        public StackValue visitBinaryExpression(@NotNull KtBinaryExpression expression, @NotNull StackValue receiver) {
3076            KtSimpleNameExpression reference = expression.getOperationReference();
3077            IElementType opToken = reference.getReferencedNameElementType();
3078            if (opToken == KtTokens.EQ) {
3079                return generateAssignmentExpression(expression);
3080            }
3081            else if (KtTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) {
3082                return generateAugmentedAssignment(expression);
3083            }
3084            else if (opToken == KtTokens.ANDAND) {
3085                return generateBooleanAnd(expression);
3086            }
3087            else if (opToken == KtTokens.OROR) {
3088                return generateBooleanOr(expression);
3089            }
3090            else if (opToken == KtTokens.EQEQ || opToken == KtTokens.EXCLEQ ||
3091                     opToken == KtTokens.EQEQEQ || opToken == KtTokens.EXCLEQEQEQ) {
3092                return generateEquals(expression.getLeft(), expression.getRight(), opToken);
3093            }
3094            else if (opToken == KtTokens.LT || opToken == KtTokens.LTEQ ||
3095                     opToken == KtTokens.GT || opToken == KtTokens.GTEQ) {
3096                return generateComparison(expression, receiver);
3097            }
3098            else if (opToken == KtTokens.ELVIS) {
3099                return generateElvis(expression);
3100            }
3101            else if (opToken == KtTokens.IN_KEYWORD || opToken == KtTokens.NOT_IN) {
3102                return generateIn(StackValue.expression(expressionType(expression.getLeft()), expression.getLeft(), this),
3103                                  expression.getRight(), reference);
3104            }
3105            else {
3106                ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext);
3107                if (compileTimeConstant != null) {
3108                    return StackValue.constant(compileTimeConstant.getValue(), expressionType(expression));
3109                }
3110    
3111                ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
3112                FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
3113    
3114                if (descriptor instanceof ConstructorDescriptor) {
3115                    return generateConstructorCall(resolvedCall, expressionType(expression));
3116                }
3117    
3118                return invokeFunction(resolvedCall, receiver);
3119            }
3120        }
3121    
3122        private StackValue generateIn(final StackValue leftValue, KtExpression rangeExpression, final KtSimpleNameExpression operationReference) {
3123            final KtExpression deparenthesized = KtPsiUtil.deparenthesize(rangeExpression);
3124    
3125            assert deparenthesized != null : "For with empty range expression";
3126            final boolean isInverted = operationReference.getReferencedNameElementType() == KtTokens.NOT_IN;
3127            return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
3128                @Override
3129                public Unit invoke(InstructionAdapter v) {
3130                    if (RangeCodegenUtil.isPrimitiveRangeSpecializationOfType(leftValue.type, deparenthesized, bindingContext) ||
3131                        RangeCodegenUtil.isPrimitiveRangeToExtension(operationReference, bindingContext)) {
3132                        generateInPrimitiveRange(leftValue, (KtBinaryExpression) deparenthesized, isInverted);
3133                    }
3134                    else {
3135                        ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilKt
3136                                .getResolvedCallWithAssert(operationReference, bindingContext);
3137                        StackValue result = invokeFunction(resolvedCall.getCall(), resolvedCall, StackValue.none());
3138                        result.put(result.type, v);
3139                        if (isInverted) {
3140                            genInvertBoolean(v);
3141                        }
3142                    }
3143                    return null;
3144                }
3145            });
3146        }
3147    
3148        /*
3149         * Translates x in a..b to a <= x && x <= b
3150         * and x !in a..b to a > x || x > b for any primitive type
3151         */
3152        private void generateInPrimitiveRange(StackValue argument, KtBinaryExpression rangeExpression, boolean isInverted) {
3153            Type rangeType = argument.type;
3154            int localVarIndex = myFrameMap.enterTemp(rangeType);
3155            // Load left bound
3156            gen(rangeExpression.getLeft(), rangeType);
3157            // Load x into local variable to avoid StackValue#put side-effects
3158            argument.put(rangeType, v);
3159            v.store(localVarIndex, rangeType);
3160            v.load(localVarIndex, rangeType);
3161    
3162            // If (x < left) goto L1
3163            Label l1 = new Label();
3164            emitGreaterThan(rangeType, l1);
3165    
3166            // If (x > right) goto L1
3167            v.load(localVarIndex, rangeType);
3168            gen(rangeExpression.getRight(), rangeType);
3169            emitGreaterThan(rangeType, l1);
3170    
3171            Label l2 = new Label();
3172            v.iconst(isInverted ? 0 : 1);
3173            v.goTo(l2);
3174    
3175            v.mark(l1);
3176            v.iconst(isInverted ? 1 : 0);
3177            v.mark(l2);
3178            myFrameMap.leaveTemp(rangeType);
3179        }
3180    
3181        private void emitGreaterThan(Type type, Label label) {
3182            if (AsmUtil.isIntPrimitive(type)) {
3183                v.ificmpgt(label);
3184            }
3185            else if (type == Type.LONG_TYPE) {
3186                v.lcmp();
3187                v.ifgt(label);
3188            }
3189            // '>' != 'compareTo' for NaN and +/- 0.0
3190            else if (type == Type.FLOAT_TYPE) {
3191                v.invokestatic("java/lang/Float", "compare", "(FF)I", false);
3192                v.ifgt(label);
3193            }
3194            else if (type == Type.DOUBLE_TYPE) {
3195                v.invokestatic("java/lang/Double", "compare", "(DD)I", false);
3196                v.ifgt(label);
3197            }
3198            else {
3199                throw new UnsupportedOperationException("Unexpected type: " + type);
3200            }
3201        }
3202    
3203        private StackValue generateBooleanAnd(KtBinaryExpression expression) {
3204            return StackValue.and(gen(expression.getLeft()), gen(expression.getRight()));
3205        }
3206    
3207        private StackValue generateBooleanOr(KtBinaryExpression expression) {
3208            return StackValue.or(gen(expression.getLeft()), gen(expression.getRight()));
3209        }
3210    
3211        private StackValue generateEquals(KtExpression left, KtExpression right, IElementType opToken) {
3212            Type leftType = expressionType(left);
3213            Type rightType = expressionType(right);
3214    
3215            if (KtPsiUtil.isNullConstant(left)) {
3216                return genCmpWithNull(right, opToken);
3217            }
3218    
3219            if (KtPsiUtil.isNullConstant(right)) {
3220                return genCmpWithNull(left, opToken);
3221            }
3222    
3223            if (isIntZero(left, leftType) && isIntPrimitive(rightType)) {
3224                return genCmpWithZero(right, opToken);
3225            }
3226    
3227            if (isIntZero(right, rightType) && isIntPrimitive(leftType)) {
3228                return genCmpWithZero(left, opToken);
3229            }
3230    
3231            if (isPrimitive(leftType) != isPrimitive(rightType)) {
3232                leftType = boxType(leftType);
3233                rightType = boxType(rightType);
3234            }
3235    
3236            StackValue leftValue = genLazy(left, leftType);
3237            StackValue rightValue = genLazy(right, rightType);
3238    
3239            if (opToken == KtTokens.EQEQEQ || opToken == KtTokens.EXCLEQEQEQ) {
3240                // TODO: always casting to the type of the left operand in case of primitives looks wrong
3241                Type operandType = isPrimitive(leftType) ? leftType : OBJECT_TYPE;
3242                return StackValue.cmp(opToken, operandType, leftValue, rightValue);
3243            }
3244    
3245            return genEqualsForExpressionsOnStack(opToken, leftValue, rightValue);
3246        }
3247    
3248        private boolean isIntZero(KtExpression expr, Type exprType) {
3249            ConstantValue<?> exprValue = getPrimitiveOrStringCompileTimeConstant(expr, bindingContext);
3250            return isIntPrimitive(exprType) && exprValue != null && Integer.valueOf(0).equals(exprValue.getValue());
3251        }
3252    
3253        private StackValue genCmpWithZero(KtExpression exp, IElementType opToken) {
3254            return StackValue.compareIntWithZero(gen(exp), (KtTokens.EQEQ == opToken || KtTokens.EQEQEQ == opToken) ? IFNE : IFEQ);
3255        }
3256    
3257        private StackValue genCmpWithNull(KtExpression exp, IElementType opToken) {
3258            return StackValue.compareWithNull(gen(exp), (KtTokens.EQEQ == opToken || KtTokens.EQEQEQ == opToken) ? IFNONNULL : IFNULL);
3259        }
3260    
3261        private StackValue generateElvis(@NotNull final KtBinaryExpression expression) {
3262            KtExpression left = expression.getLeft();
3263    
3264            final Type exprType = expressionType(expression);
3265            final Type leftType = expressionType(left);
3266    
3267            final Label ifNull = new Label();
3268    
3269    
3270            assert left != null : "left expression in elvis should be not null: " + expression.getText();
3271            final StackValue value = generateExpressionWithNullFallback(left, ifNull);
3272    
3273            if (isPrimitive(leftType)) {
3274                return value;
3275            }
3276    
3277            return StackValue.operation(exprType, new Function1<InstructionAdapter, Unit>() {
3278                @Override
3279                public Unit invoke(InstructionAdapter v) {
3280                    value.put(value.type, v);
3281                    v.dup();
3282    
3283                    v.ifnull(ifNull);
3284                    StackValue.onStack(leftType).put(exprType, v);
3285    
3286                    Label end = new Label();
3287                    v.goTo(end);
3288    
3289                    v.mark(ifNull);
3290                    v.pop();
3291                    gen(expression.getRight(), exprType);
3292                    v.mark(end);
3293                    return null;
3294                }
3295            });
3296        }
3297    
3298        private StackValue generateComparison(KtBinaryExpression expression, StackValue receiver) {
3299            ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
3300    
3301            KtExpression left = expression.getLeft();
3302            KtExpression right = expression.getRight();
3303    
3304            Type type;
3305            StackValue leftValue;
3306            StackValue rightValue;
3307            Type leftType = expressionType(left);
3308            Type rightType = expressionType(right);
3309            Callable callable = resolveToCallable((FunctionDescriptor) resolvedCall.getResultingDescriptor(), false, resolvedCall);
3310            if (isPrimitive(leftType) && isPrimitive(rightType) && callable instanceof IntrinsicCallable) {
3311                type = comparisonOperandType(leftType, rightType);
3312                leftValue = gen(left);
3313                rightValue = gen(right);
3314            }
3315            else {
3316                type = Type.INT_TYPE;
3317                leftValue = invokeFunction(resolvedCall, receiver);
3318                rightValue = StackValue.constant(0, type);
3319            }
3320            return StackValue.cmp(expression.getOperationToken(), type, leftValue, rightValue);
3321        }
3322    
3323        private StackValue generateAssignmentExpression(KtBinaryExpression expression) {
3324            StackValue stackValue = gen(expression.getLeft());
3325            KtExpression right = expression.getRight();
3326            assert right != null : expression.getText();
3327            stackValue.store(gen(right), v);
3328            return StackValue.none();
3329        }
3330    
3331        private StackValue generateAugmentedAssignment(KtBinaryExpression expression) {
3332            ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
3333            FunctionDescriptor descriptor = accessibleFunctionDescriptor(resolvedCall);
3334            Callable callable = resolveToCallable(descriptor, false, resolvedCall);
3335            KtExpression lhs = expression.getLeft();
3336            Type lhsType = expressionType(lhs);
3337    
3338            boolean keepReturnValue = Boolean.TRUE.equals(bindingContext.get(VARIABLE_REASSIGNMENT, expression))
3339                    || !KotlinBuiltIns.isUnit(descriptor.getReturnType());
3340    
3341            callAugAssignMethod(expression, resolvedCall, callable, lhsType, keepReturnValue);
3342    
3343            return StackValue.none();
3344        }
3345    
3346        private void callAugAssignMethod(
3347                @NotNull KtBinaryExpression expression,
3348                @NotNull ResolvedCall<?> resolvedCall,
3349                @NotNull Callable callable,
3350                @NotNull Type lhsType,
3351                boolean keepReturnValue
3352        ) {
3353            StackValue value = gen(expression.getLeft());
3354            if (keepReturnValue) {
3355                value = StackValue.complexWriteReadReceiver(value);
3356            }
3357            value.put(lhsType, v);
3358            StackValue receiver = StackValue.onStack(lhsType);
3359    
3360            callable.invokeMethodWithArguments(resolvedCall, receiver, this).put(callable.getReturnType(), v);
3361    
3362            if (keepReturnValue) {
3363                value.store(StackValue.onStack(callable.getReturnType()), v, true);
3364            }
3365        }
3366    
3367        public void invokeAppend(KtExpression expr) {
3368            ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expr, bindingContext);
3369    
3370            if (compileTimeConstant == null && expr instanceof KtBinaryExpression) {
3371                KtBinaryExpression binaryExpression = (KtBinaryExpression) expr;
3372                if (binaryExpression.getOperationToken() == KtTokens.PLUS) {
3373                    KtExpression left = binaryExpression.getLeft();
3374                    KtExpression right = binaryExpression.getRight();
3375                    Type leftType = expressionType(left);
3376    
3377                    if (leftType.equals(JAVA_STRING_TYPE)) {
3378                        invokeAppend(left);
3379                        invokeAppend(right);
3380                        return;
3381                    }
3382                }
3383            }
3384    
3385            Type exprType = expressionType(expr);
3386            if (compileTimeConstant != null) {
3387                StackValue.constant(compileTimeConstant.getValue(), exprType).put(exprType, v);
3388            } else {
3389                gen(expr, exprType);
3390            }
3391            genInvokeAppendMethod(v, exprType.getSort() == Type.ARRAY ? OBJECT_TYPE : exprType);
3392        }
3393    
3394        @Nullable
3395        private static KtSimpleNameExpression targetLabel(KtExpression expression) {
3396            if (expression.getParent() instanceof KtLabeledExpression) {
3397                return ((KtLabeledExpression) expression.getParent()).getTargetLabel();
3398            }
3399            return null;
3400        }
3401    
3402        @Override
3403        public StackValue visitLabeledExpression(
3404                @NotNull KtLabeledExpression expression, StackValue receiver
3405        ) {
3406            return genQualified(receiver, expression.getBaseExpression());
3407        }
3408    
3409        @Override
3410        public StackValue visitPrefixExpression(@NotNull KtPrefixExpression expression, @NotNull StackValue receiver) {
3411            ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext);
3412            if (compileTimeConstant != null) {
3413                return StackValue.constant(compileTimeConstant.getValue(), expressionType(expression));
3414            }
3415    
3416            DeclarationDescriptor originalOperation = bindingContext.get(REFERENCE_TARGET, expression.getOperationReference());
3417            ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
3418            CallableDescriptor op = resolvedCall.getResultingDescriptor();
3419    
3420            assert op instanceof FunctionDescriptor || originalOperation == null : String.valueOf(op);
3421            String operationName = originalOperation == null ? "" : originalOperation.getName().asString();
3422            if (!(operationName.equals("inc") || operationName.equals("dec"))) {
3423                return invokeFunction(resolvedCall, receiver);
3424            }
3425    
3426            int increment = operationName.equals("inc") ? 1 : -1;
3427            Type type = expressionType(expression.getBaseExpression());
3428            StackValue value = gen(expression.getBaseExpression());
3429            return StackValue.preIncrement(type, value, increment, resolvedCall, this);
3430        }
3431    
3432        @Override
3433        public StackValue visitPostfixExpression(@NotNull final KtPostfixExpression expression, StackValue receiver) {
3434            if (expression.getOperationReference().getReferencedNameElementType() == KtTokens.EXCLEXCL) {
3435                final StackValue base = genQualified(receiver, expression.getBaseExpression());
3436                if (isPrimitive(base.type)) {
3437                    return base;
3438                } else {
3439                    return StackValue.operation(base.type, new Function1<InstructionAdapter, Unit>() {
3440                        @Override
3441                        public Unit invoke(InstructionAdapter v) {
3442                            base.put(base.type, v);
3443                            v.dup();
3444                            Label ok = new Label();
3445                            v.ifnonnull(ok);
3446                            v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "throwNpe", "()V", false);
3447                            v.mark(ok);
3448                            return null;
3449                        }
3450                    });
3451                }
3452            }
3453    
3454            DeclarationDescriptor originalOperation = bindingContext.get(REFERENCE_TARGET, expression.getOperationReference());
3455            String originalOperationName = originalOperation != null ? originalOperation.getName().asString() : null;
3456            final ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
3457            DeclarationDescriptor op = resolvedCall.getResultingDescriptor();
3458            if (!(op instanceof FunctionDescriptor) || originalOperation == null) {
3459                throw new UnsupportedOperationException("Don't know how to generate this postfix expression: " + originalOperationName + " " + op);
3460            }
3461    
3462    
3463            final Type asmResultType = expressionType(expression);
3464            final Type asmBaseType = expressionType(expression.getBaseExpression());
3465    
3466            DeclarationDescriptor cls = op.getContainingDeclaration();
3467    
3468            final int increment;
3469            if (originalOperationName.equals("inc")) {
3470                increment = 1;
3471            }
3472            else if (originalOperationName.equals("dec")) {
3473                increment = -1;
3474            }
3475            else {
3476                throw new UnsupportedOperationException("Unsupported postfix operation: " + originalOperationName + " " + op);
3477            }
3478    
3479            final boolean isPrimitiveNumberClassDescriptor = isPrimitiveNumberClassDescriptor(cls);
3480            if (isPrimitiveNumberClassDescriptor && AsmUtil.isPrimitive(asmBaseType)) {
3481                KtExpression operand = expression.getBaseExpression();
3482                // Optimization for j = i++, when j and i are Int without any smart cast: we just work with primitive int
3483                if (operand instanceof KtReferenceExpression && asmResultType == Type.INT_TYPE &&
3484                    bindingContext.get(BindingContext.SMARTCAST, operand) == null) {
3485                    int index = indexOfLocal((KtReferenceExpression) operand);
3486                    if (index >= 0) {
3487                        return StackValue.postIncrement(index, increment);
3488                    }
3489                }
3490            }
3491    
3492            return StackValue.operation(asmBaseType, new Function1<InstructionAdapter, Unit>() {
3493                @Override
3494                public Unit invoke(InstructionAdapter v) {
3495                    StackValue value = StackValue.complexWriteReadReceiver(gen(expression.getBaseExpression()));
3496    
3497                    value.put(asmBaseType, v);
3498                    AsmUtil.dup(v, asmBaseType);
3499    
3500                    StackValue previousValue = StackValue.local(myFrameMap.enterTemp(asmBaseType), asmBaseType);
3501                    previousValue.store(StackValue.onStack(asmBaseType), v);
3502    
3503                    Type storeType;
3504                    if (isPrimitiveNumberClassDescriptor && AsmUtil.isPrimitive(asmBaseType)) {
3505                        genIncrement(asmBaseType, increment, v);
3506                        storeType = asmBaseType;
3507                    }
3508                    else {
3509                        StackValue result = invokeFunction(resolvedCall, StackValue.onStack(asmBaseType));
3510                        result.put(result.type, v);
3511                        storeType = result.type;
3512                    }
3513    
3514                    value.store(StackValue.onStack(storeType), v, true);
3515    
3516                    previousValue.put(asmBaseType, v);
3517    
3518                    myFrameMap.leaveTemp(asmBaseType);
3519    
3520                    return Unit.INSTANCE;
3521                }
3522            });
3523        }
3524    
3525        @Override
3526        public StackValue visitProperty(@NotNull KtProperty property, StackValue receiver) {
3527            KtExpression initializer = property.getInitializer();
3528            if (initializer == null) {
3529                return StackValue.none();
3530            }
3531            initializeLocalVariable(property, gen(initializer));
3532            return StackValue.none();
3533        }
3534    
3535        @Override
3536        public StackValue visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, StackValue receiver) {
3537            KtExpression initializer = multiDeclaration.getInitializer();
3538            if (initializer == null) return StackValue.none();
3539    
3540            KotlinType initializerType = bindingContext.getType(initializer);
3541            assert initializerType != null;
3542    
3543            Type initializerAsmType = asmType(initializerType);
3544    
3545            TransientReceiver initializerAsReceiver = new TransientReceiver(initializerType);
3546    
3547            int tempVarIndex = myFrameMap.enterTemp(initializerAsmType);
3548    
3549            gen(initializer, initializerAsmType);
3550            v.store(tempVarIndex, initializerAsmType);
3551            StackValue.Local local = StackValue.local(tempVarIndex, initializerAsmType);
3552    
3553            for (KtDestructuringDeclarationEntry variableDeclaration : multiDeclaration.getEntries()) {
3554                ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(COMPONENT_RESOLVED_CALL, variableDeclaration);
3555                assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText();
3556                Call call = makeFakeCall(initializerAsReceiver);
3557                initializeLocalVariable(variableDeclaration, invokeFunction(call, resolvedCall, local));
3558            }
3559    
3560            if (initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) {
3561                v.aconst(null);
3562                v.store(tempVarIndex, initializerAsmType);
3563            }
3564            myFrameMap.leaveTemp(initializerAsmType);
3565    
3566            return StackValue.none();
3567        }
3568    
3569        private void initializeLocalVariable(
3570                @NotNull KtVariableDeclaration variableDeclaration,
3571                @NotNull StackValue initializer
3572        ) {
3573            VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, variableDeclaration);
3574    
3575            if (KtPsiUtil.isScriptDeclaration(variableDeclaration)) {
3576                return;
3577            }
3578            int index = lookupLocalIndex(variableDescriptor);
3579    
3580            if (index < 0) {
3581                throw new IllegalStateException("Local variable not found for " + variableDescriptor);
3582            }
3583    
3584            Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
3585            assert variableDescriptor != null;
3586    
3587            Type varType = asmType(variableDescriptor.getType());
3588    
3589            StackValue storeTo = sharedVarType == null ? StackValue.local(index, varType) : StackValue.shared(index, varType);
3590    
3591            storeTo.putReceiver(v, false);
3592            initializer.put(initializer.type, v);
3593    
3594            markLineNumber(variableDeclaration, false);
3595    
3596            storeTo.storeSelector(initializer.type, v);
3597        }
3598    
3599        @NotNull
3600        private StackValue generateNewCall(@NotNull KtCallExpression expression, @NotNull ResolvedCall<?> resolvedCall) {
3601            Type type = expressionType(expression);
3602            if (type.getSort() == Type.ARRAY) {
3603                //noinspection ConstantConditions
3604                return generateNewArray(expression, bindingContext.getType(expression), resolvedCall);
3605            }
3606    
3607            return generateConstructorCall(resolvedCall, type);
3608        }
3609    
3610        @NotNull
3611        public ConstructorDescriptor getConstructorDescriptor(@NotNull ResolvedCall<?> resolvedCall) {
3612            FunctionDescriptor accessibleDescriptor = accessibleFunctionDescriptor(resolvedCall);
3613            assert accessibleDescriptor instanceof ConstructorDescriptor :
3614                    "getConstructorDescriptor must be called only for constructors: " + accessibleDescriptor;
3615            return (ConstructorDescriptor) accessibleDescriptor;
3616        }
3617    
3618        @NotNull
3619        public StackValue generateConstructorCall(@NotNull final ResolvedCall<?> resolvedCall, @NotNull final Type objectType) {
3620            return StackValue.functionCall(objectType, new Function1<InstructionAdapter, Unit>() {
3621                @Override
3622                public Unit invoke(InstructionAdapter v) {
3623                    v.anew(objectType);
3624                    v.dup();
3625    
3626                    ConstructorDescriptor constructor = getConstructorDescriptor(resolvedCall);
3627    
3628                    ReceiverParameterDescriptor dispatchReceiver = constructor.getDispatchReceiverParameter();
3629                    ClassDescriptor containingDeclaration = constructor.getContainingDeclaration();
3630                    if (dispatchReceiver != null) {
3631                        Type receiverType = typeMapper.mapType(dispatchReceiver.getType());
3632                        ReceiverValue receiver = resolvedCall.getDispatchReceiver();
3633                        boolean callSuper = containingDeclaration.isInner() && receiver instanceof ImplicitClassReceiver;
3634                        generateReceiverValue(receiver, callSuper).put(receiverType, v);
3635                    }
3636    
3637                    // Resolved call to local class constructor doesn't have dispatchReceiver, so we need to generate closure on stack
3638                    // See StackValue.receiver for more info
3639                    pushClosureOnStack(containingDeclaration, dispatchReceiver == null, defaultCallGenerator);
3640    
3641                    constructor = SamCodegenUtil.resolveSamAdapter(constructor);
3642                    CallableMethod method = typeMapper.mapToCallableMethod(constructor, false);
3643                    invokeMethodWithArguments(method, resolvedCall, StackValue.none());
3644    
3645                    return Unit.INSTANCE;
3646                }
3647            });
3648        }
3649    
3650        public StackValue generateNewArray(
3651                @NotNull KtCallExpression expression, @NotNull final KotlinType arrayType, @NotNull ResolvedCall<?> resolvedCall
3652        ) {
3653            List<KtValueArgument> args = expression.getValueArguments();
3654            assert args.size() == 1 || args.size() == 2 : "Unknown constructor called: " + args.size() + " arguments";
3655    
3656            if (args.size() == 1) {
3657                final KtExpression sizeExpression = args.get(0).getArgumentExpression();
3658                return StackValue.operation(typeMapper.mapType(arrayType), new Function1<InstructionAdapter, Unit>() {
3659                    @Override
3660                    public Unit invoke(InstructionAdapter v) {
3661                        gen(sizeExpression, Type.INT_TYPE);
3662                        newArrayInstruction(arrayType);
3663                        return Unit.INSTANCE;
3664                    }
3665                });
3666            }
3667    
3668            return invokeFunction(resolvedCall, StackValue.none());
3669        }
3670    
3671        public void newArrayInstruction(@NotNull KotlinType arrayType) {
3672            if (KotlinBuiltIns.isArray(arrayType)) {
3673                KotlinType elementJetType = arrayType.getArguments().get(0).getType();
3674                putReifiedOperationMarkerIfTypeIsReifiedParameter(
3675                        elementJetType,
3676                        ReifiedTypeInliner.OperationKind.NEW_ARRAY
3677                );
3678                v.newarray(boxType(asmType(elementJetType)));
3679            }
3680            else {
3681                Type type = typeMapper.mapType(arrayType);
3682                v.newarray(correctElementType(type));
3683            }
3684        }
3685    
3686        @Override
3687        public StackValue visitArrayAccessExpression(@NotNull KtArrayAccessExpression expression, StackValue receiver) {
3688            KtExpression array = expression.getArrayExpression();
3689            KotlinType type = array != null ? bindingContext.getType(array) : null;
3690            Type arrayType = expressionType(array);
3691            List<KtExpression> indices = expression.getIndexExpressions();
3692            FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(REFERENCE_TARGET, expression);
3693            assert operationDescriptor != null;
3694            if (arrayType.getSort() == Type.ARRAY &&
3695                indices.size() == 1 &&
3696                isInt(operationDescriptor.getValueParameters().get(0).getType())) {
3697                assert type != null;
3698                Type elementType;
3699                if (KotlinBuiltIns.isArray(type)) {
3700                    KotlinType jetElementType = type.getArguments().get(0).getType();
3701                    elementType = boxType(asmType(jetElementType));
3702                }
3703                else {
3704                    elementType = correctElementType(arrayType);
3705                }
3706                StackValue arrayValue = genLazy(array, arrayType);
3707                StackValue index = genLazy(indices.get(0), Type.INT_TYPE);
3708    
3709                return StackValue.arrayElement(elementType, arrayValue, index);
3710            }
3711            else {
3712                ResolvedCall<FunctionDescriptor> resolvedSetCall = bindingContext.get(INDEXED_LVALUE_SET, expression);
3713                ResolvedCall<FunctionDescriptor> resolvedGetCall = bindingContext.get(INDEXED_LVALUE_GET, expression);
3714    
3715                boolean isGetter = "get".equals(operationDescriptor.getName().asString());
3716    
3717                Callable callable = resolveToCallable(operationDescriptor, false, isGetter ? resolvedGetCall : resolvedSetCall);
3718                Callable callableMethod = resolveToCallableMethod(operationDescriptor, false);
3719                Type[] argumentTypes = callableMethod.getParameterTypes();
3720    
3721                StackValue.CollectionElementReceiver collectionElementReceiver = createCollectionElementReceiver(
3722                        expression, receiver, operationDescriptor, isGetter, resolvedGetCall, resolvedSetCall, callable
3723                );
3724    
3725                Type elementType = isGetter ? callableMethod.getReturnType() : ArrayUtil.getLastElement(argumentTypes);
3726                return StackValue.collectionElement(collectionElementReceiver, elementType, resolvedGetCall, resolvedSetCall, this);
3727            }
3728        }
3729    
3730        @NotNull
3731        private StackValue.CollectionElementReceiver createCollectionElementReceiver(
3732                @NotNull KtArrayAccessExpression expression,
3733                @NotNull StackValue receiver,
3734                @NotNull FunctionDescriptor operationDescriptor,
3735                boolean isGetter,
3736                ResolvedCall<FunctionDescriptor> resolvedGetCall,
3737                ResolvedCall<FunctionDescriptor> resolvedSetCall,
3738                @NotNull Callable callable
3739        ) {
3740            ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall;
3741            assert resolvedCall != null : "couldn't find resolved call: " + expression.getText();
3742    
3743            List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
3744            assert valueArguments != null : "Failed to arrange value arguments by index: " + operationDescriptor;
3745    
3746            if (!isGetter) {
3747                assert valueArguments.size() >= 2 : "Setter call should have at least 2 arguments: " + operationDescriptor;
3748                // Skip generation of the right hand side of an indexed assignment, which is the last value argument
3749                valueArguments.remove(valueArguments.size() - 1);
3750            }
3751    
3752            return new StackValue.CollectionElementReceiver(
3753                    callable, receiver, resolvedGetCall, resolvedSetCall, isGetter, this, valueArguments
3754            );
3755        }
3756    
3757        @Override
3758        public StackValue visitThrowExpression(@NotNull final KtThrowExpression expression, StackValue receiver) {
3759            return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
3760                @Override
3761                public Unit invoke(InstructionAdapter adapter) {
3762                    gen(expression.getThrownExpression(), JAVA_THROWABLE_TYPE);
3763                    v.athrow();
3764                    return Unit.INSTANCE;
3765                }
3766            });
3767        }
3768    
3769        @Override
3770        public StackValue visitThisExpression(@NotNull KtThisExpression expression, StackValue receiver) {
3771            DeclarationDescriptor descriptor = bindingContext.get(REFERENCE_TARGET, expression.getInstanceReference());
3772            if (descriptor instanceof ClassDescriptor) {
3773                //TODO rewrite with context.lookupInContext()
3774                return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor, false, true);
3775            }
3776            if (descriptor instanceof CallableDescriptor) {
3777                return generateReceiver((CallableDescriptor) descriptor);
3778            }
3779            throw new UnsupportedOperationException("Neither this nor receiver: " + descriptor);
3780        }
3781    
3782        @Override
3783        public StackValue visitTryExpression(@NotNull KtTryExpression expression, StackValue receiver) {
3784            return generateTryExpression(expression, false);
3785        }
3786    
3787        public StackValue generateTryExpression(final KtTryExpression expression, final boolean isStatement) {
3788            /*
3789    The "returned" value of try expression with no finally is either the last expression in the try block or the last expression in the catch block
3790    (or blocks).
3791             */
3792    
3793            KotlinType jetType = bindingContext.getType(expression);
3794            assert jetType != null;
3795            final Type expectedAsmType = isStatement ? Type.VOID_TYPE : asmType(jetType);
3796    
3797            return StackValue.operation(expectedAsmType, new Function1<InstructionAdapter, Unit>() {
3798                @Override
3799                public Unit invoke(InstructionAdapter v) {
3800                    KtFinallySection finallyBlock = expression.getFinallyBlock();
3801                    FinallyBlockStackElement finallyBlockStackElement = null;
3802                    if (finallyBlock != null) {
3803                        finallyBlockStackElement = new FinallyBlockStackElement(expression);
3804                        blockStackElements.push(finallyBlockStackElement);
3805                    }
3806    
3807                    //PseudoInsnsPackage.saveStackBeforeTryExpr(v);
3808    
3809                    Label tryStart = new Label();
3810                    v.mark(tryStart);
3811                    v.nop(); // prevent verify error on empty try
3812    
3813                    gen(expression.getTryBlock(), expectedAsmType);
3814    
3815                    int savedValue = -1;
3816                    if (!isStatement) {
3817                        savedValue = myFrameMap.enterTemp(expectedAsmType);
3818                        v.store(savedValue, expectedAsmType);
3819                    }
3820    
3821                    Label tryEnd = new Label();
3822                    v.mark(tryEnd);
3823    
3824                    //do it before finally block generation
3825                    List<Label> tryBlockRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, tryEnd);
3826    
3827                    Label end = new Label();
3828    
3829                    genFinallyBlockOrGoto(finallyBlockStackElement, end, null);
3830    
3831                    List<KtCatchClause> clauses = expression.getCatchClauses();
3832                    for (int i = 0, size = clauses.size(); i < size; i++) {
3833                        KtCatchClause clause = clauses.get(i);
3834    
3835                        Label clauseStart = new Label();
3836                        v.mark(clauseStart);
3837    
3838                        KtExpression catchBody = clause.getCatchBody();
3839                        if (catchBody != null) {
3840                            markLineNumber(catchBody, false);
3841                        }
3842    
3843                        VariableDescriptor descriptor = bindingContext.get(VALUE_PARAMETER, clause.getCatchParameter());
3844                        assert descriptor != null;
3845                        Type descriptorType = asmType(descriptor.getType());
3846                        myFrameMap.enter(descriptor, descriptorType);
3847                        int index = lookupLocalIndex(descriptor);
3848                        v.store(index, descriptorType);
3849    
3850                        gen(catchBody, expectedAsmType);
3851    
3852                        if (!isStatement) {
3853                            v.store(savedValue, expectedAsmType);
3854                        }
3855    
3856                        myFrameMap.leave(descriptor);
3857    
3858                        Label clauseEnd = new Label();
3859                        v.mark(clauseEnd);
3860    
3861                        v.visitLocalVariable(descriptor.getName().asString(), descriptorType.getDescriptor(), null, clauseStart, clauseEnd,
3862                                             index);
3863    
3864                        genFinallyBlockOrGoto(finallyBlockStackElement, i != size - 1 || finallyBlock != null ? end : null, null);
3865    
3866                        generateExceptionTable(clauseStart, tryBlockRegions, descriptorType.getInternalName());
3867                    }
3868    
3869    
3870                    //for default catch clause
3871                    if (finallyBlock != null) {
3872                        Label defaultCatchStart = new Label();
3873                        v.mark(defaultCatchStart);
3874                        int savedException = myFrameMap.enterTemp(JAVA_THROWABLE_TYPE);
3875                        v.store(savedException, JAVA_THROWABLE_TYPE);
3876    
3877                        Label defaultCatchEnd = new Label();
3878                        v.mark(defaultCatchEnd);
3879    
3880                        //do it before finally block generation
3881                        //javac also generates entry in exception table for default catch clause too!!!! so defaultCatchEnd as end parameter
3882                        List<Label> defaultCatchRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, defaultCatchEnd);
3883    
3884    
3885                        genFinallyBlockOrGoto(finallyBlockStackElement, null, null);
3886    
3887                        v.load(savedException, JAVA_THROWABLE_TYPE);
3888                        myFrameMap.leaveTemp(JAVA_THROWABLE_TYPE);
3889    
3890                        v.athrow();
3891    
3892                        generateExceptionTable(defaultCatchStart, defaultCatchRegions, null);
3893                    }
3894    
3895                    markLineNumber(expression, isStatement);
3896                    v.mark(end);
3897    
3898                    if (!isStatement) {
3899                        v.load(savedValue, expectedAsmType);
3900                        myFrameMap.leaveTemp(expectedAsmType);
3901                    }
3902    
3903                    if (finallyBlock != null) {
3904                        blockStackElements.pop();
3905                    }
3906                    return Unit.INSTANCE;
3907                }
3908            });
3909        }
3910    
3911        private void generateExceptionTable(@NotNull Label catchStart, @NotNull List<Label> catchedRegions, @Nullable String exception) {
3912            for (int i = 0; i < catchedRegions.size(); i += 2) {
3913                Label startRegion = catchedRegions.get(i);
3914                Label endRegion = catchedRegions.get(i+1);
3915                v.visitTryCatchBlock(startRegion, endRegion, catchStart, exception);
3916            }
3917        }
3918    
3919        @NotNull
3920        private static List<Label> getCurrentCatchIntervals(
3921                @Nullable FinallyBlockStackElement finallyBlockStackElement,
3922                @NotNull Label blockStart,
3923                @NotNull Label blockEnd
3924        ) {
3925            List<Label> gapsInBlock =
3926                    finallyBlockStackElement != null ? new ArrayList<Label>(finallyBlockStackElement.gaps) : Collections.<Label>emptyList();
3927            assert gapsInBlock.size() % 2 == 0;
3928            List<Label> blockRegions = new ArrayList<Label>(gapsInBlock.size() + 2);
3929            blockRegions.add(blockStart);
3930            blockRegions.addAll(gapsInBlock);
3931            blockRegions.add(blockEnd);
3932            return blockRegions;
3933        }
3934    
3935        @Override
3936        public StackValue visitBinaryWithTypeRHSExpression(@NotNull KtBinaryExpressionWithTypeRHS expression, StackValue receiver) {
3937            KtExpression left = expression.getLeft();
3938            final IElementType opToken = expression.getOperationReference().getReferencedNameElementType();
3939    
3940            final KotlinType rightType = bindingContext.get(TYPE, expression.getRight());
3941            assert rightType != null;
3942    
3943            final StackValue value = genQualified(receiver, left);
3944    
3945            return StackValue.operation(boxType(asmType(rightType)), new Function1<InstructionAdapter, Unit>() {
3946                @Override
3947                public Unit invoke(InstructionAdapter v) {
3948                    value.put(boxType(value.type), v);
3949    
3950                    if (value.type == Type.VOID_TYPE) {
3951                        StackValue.putUnitInstance(v);
3952                    }
3953    
3954                    boolean safeAs = opToken == KtTokens.AS_SAFE;
3955                    Type type = boxType(asmType(rightType));
3956                    if (TypeUtils.isReifiedTypeParameter(rightType)) {
3957                        putReifiedOperationMarkerIfTypeIsReifiedParameter(rightType,
3958                                                                          safeAs ? ReifiedTypeInliner.OperationKind.SAFE_AS
3959                                                                                 : ReifiedTypeInliner.OperationKind.AS);
3960                        v.checkcast(type);
3961                        return Unit.INSTANCE;
3962                    }
3963    
3964                    CodegenUtilKt.generateAsCast(v, rightType, type, safeAs);
3965    
3966                    return Unit.INSTANCE;
3967                }
3968            });
3969        }
3970    
3971        @Override
3972        public StackValue visitIsExpression(@NotNull KtIsExpression expression, StackValue receiver) {
3973            StackValue match = StackValue.expression(OBJECT_TYPE, expression.getLeftHandSide(), this);
3974            return generateIsCheck(match, expression.getTypeReference(), expression.isNegated());
3975        }
3976    
3977        private StackValue generateExpressionMatch(StackValue expressionToMatch, KtExpression patternExpression) {
3978            if (expressionToMatch != null) {
3979                Type subjectType = expressionToMatch.type;
3980                markStartLineNumber(patternExpression);
3981                KotlinType condJetType = bindingContext.getType(patternExpression);
3982                Type condType;
3983                if (isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) {
3984                    assert condJetType != null;
3985                    condType = asmType(condJetType);
3986                    if (!(isNumberPrimitive(condType) || condType.getSort() == Type.BOOLEAN)) {
3987                        subjectType = boxType(subjectType);
3988                    }
3989                }
3990                else {
3991                    condType = OBJECT_TYPE;
3992                }
3993                StackValue condition = genLazy(patternExpression, condType);
3994                return genEqualsForExpressionsOnStack(KtTokens.EQEQ, StackValue.coercion(expressionToMatch, subjectType), condition);
3995            }
3996            else {
3997                return gen(patternExpression);
3998            }
3999        }
4000    
4001        private StackValue generateIsCheck(StackValue expressionToMatch, KtTypeReference typeReference, boolean negated) {
4002            KotlinType jetType = bindingContext.get(TYPE, typeReference);
4003            markStartLineNumber(typeReference);
4004            StackValue value = generateIsCheck(expressionToMatch, jetType, false);
4005            return negated ? StackValue.not(value) : value;
4006        }
4007    
4008        private StackValue generateIsCheck(final StackValue expressionToGen, final KotlinType kotlinType, final boolean leaveExpressionOnStack) {
4009            return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
4010                @Override
4011                public Unit invoke(InstructionAdapter v) {
4012                    expressionToGen.put(OBJECT_TYPE, v);
4013                    if (leaveExpressionOnStack) {
4014                        v.dup();
4015                    }
4016    
4017                    Type type = boxType(asmType(kotlinType));
4018                    if (TypeUtils.isReifiedTypeParameter(kotlinType)) {
4019                        putReifiedOperationMarkerIfTypeIsReifiedParameter(kotlinType, ReifiedTypeInliner.OperationKind.IS);
4020                        v.instanceOf(type);
4021                        return null;
4022                    }
4023    
4024                    CodegenUtilKt.generateIsCheck(v, kotlinType, type);
4025                    return null;
4026                }
4027            });
4028        }
4029    
4030        public void putReifiedOperationMarkerIfTypeIsReifiedParameter(
4031                @NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind
4032        ) {
4033            Pair<TypeParameterDescriptor, ReificationArgument> typeParameterAndReificationArgument = extractReificationArgument(type);
4034            if (typeParameterAndReificationArgument != null && typeParameterAndReificationArgument.getFirst().isReified()) {
4035                TypeParameterDescriptor typeParameterDescriptor = typeParameterAndReificationArgument.getFirst();
4036                if (typeParameterDescriptor.getContainingDeclaration() != context.getContextDescriptor()) {
4037                    parentCodegen.getReifiedTypeParametersUsages().
4038                            addUsedReifiedParameter(typeParameterDescriptor.getName().asString());
4039                }
4040                v.iconst(operationKind.getId());
4041                v.visitLdcInsn(typeParameterAndReificationArgument.getSecond().asString());
4042                v.invokestatic(
4043                        IntrinsicMethods.INTRINSICS_CLASS_NAME, ReifiedTypeInliner.REIFIED_OPERATION_MARKER_METHOD_NAME,
4044                        Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, Type.getType(String.class)), false
4045                );
4046            }
4047        }
4048    
4049        public void propagateChildReifiedTypeParametersUsages(@NotNull ReifiedTypeParametersUsages usages) {
4050            parentCodegen.getReifiedTypeParametersUsages().propagateChildUsagesWithinContext(usages, context);
4051        }
4052    
4053        @Override
4054        public StackValue visitWhenExpression(@NotNull KtWhenExpression expression, StackValue receiver) {
4055            return generateWhenExpression(expression, false);
4056        }
4057    
4058        public StackValue generateWhenExpression(final KtWhenExpression expression, final boolean isStatement) {
4059            final KtExpression expr = expression.getSubjectExpression();
4060            final Type subjectType = expressionType(expr);
4061    
4062            final Type resultType = isStatement ? Type.VOID_TYPE : expressionType(expression);
4063    
4064            return StackValue.operation(resultType, new Function1<InstructionAdapter, Unit>() {
4065                @Override
4066                public Unit invoke(InstructionAdapter v) {
4067                    SwitchCodegen switchCodegen = SwitchCodegenUtil.buildAppropriateSwitchCodegenIfPossible(
4068                            expression, isStatement, isExhaustive(expression, isStatement), ExpressionCodegen.this
4069                    );
4070                    if (switchCodegen != null) {
4071                        switchCodegen.generate();
4072                        return Unit.INSTANCE;
4073                    }
4074    
4075                    int subjectLocal = expr != null ? myFrameMap.enterTemp(subjectType) : -1;
4076                    if (subjectLocal != -1) {
4077                        gen(expr, subjectType);
4078                        tempVariables.put(expr, StackValue.local(subjectLocal, subjectType));
4079                        v.store(subjectLocal, subjectType);
4080                    }
4081    
4082                    Label end = new Label();
4083                    boolean hasElse = KtPsiUtil.checkWhenExpressionHasSingleElse(expression);
4084    
4085                    Label nextCondition = null;
4086                    for (KtWhenEntry whenEntry : expression.getEntries()) {
4087                        if (nextCondition != null) {
4088                            v.mark(nextCondition);
4089                        }
4090                        nextCondition = new Label();
4091                        FrameMap.Mark mark = myFrameMap.mark();
4092                        Label thisEntry = new Label();
4093                        if (!whenEntry.isElse()) {
4094                            KtWhenCondition[] conditions = whenEntry.getConditions();
4095                            for (int i = 0; i < conditions.length; i++) {
4096                                StackValue conditionValue = generateWhenCondition(subjectType, subjectLocal, conditions[i]);
4097                                BranchedValue.Companion.condJump(conditionValue, nextCondition, true, v);
4098                                if (i < conditions.length - 1) {
4099                                    v.goTo(thisEntry);
4100                                    v.mark(nextCondition);
4101                                    nextCondition = new Label();
4102                                }
4103                            }
4104                        }
4105    
4106                        v.visitLabel(thisEntry);
4107                        gen(whenEntry.getExpression(), resultType);
4108                        mark.dropTo();
4109                        if (!whenEntry.isElse()) {
4110                            v.goTo(end);
4111                        }
4112                    }
4113                    if (!hasElse && nextCondition != null) {
4114                        v.mark(nextCondition);
4115                        putUnitInstanceOntoStackForNonExhaustiveWhen(expression, isStatement);
4116                    }
4117    
4118                    markLineNumber(expression, isStatement);
4119                    v.mark(end);
4120    
4121                    myFrameMap.leaveTemp(subjectType);
4122                    tempVariables.remove(expr);
4123                    return null;
4124                }
4125            });
4126        }
4127    
4128        private boolean isExhaustive(@NotNull KtWhenExpression whenExpression, boolean isStatement) {
4129            if (isStatement && !BindingContextUtilsKt.isUsedAsExpression(whenExpression, bindingContext)) {
4130                return Boolean.TRUE.equals(bindingContext.get(BindingContext.IMPLICIT_EXHAUSTIVE_WHEN, whenExpression));
4131            }
4132            else {
4133                return Boolean.TRUE.equals(bindingContext.get(BindingContext.EXHAUSTIVE_WHEN, whenExpression));
4134            }
4135        }
4136    
4137        public void putUnitInstanceOntoStackForNonExhaustiveWhen(
4138                @NotNull KtWhenExpression whenExpression,
4139                boolean isStatement
4140        ) {
4141            if (isExhaustive(whenExpression, isStatement)) {
4142                // when() is supposed to be exhaustive
4143                genThrow(v, "kotlin/NoWhenBranchMatchedException", null);
4144            }
4145            else if (!isStatement) {
4146                // non-exhaustive when() with no else -> Unit must be expected
4147                StackValue.putUnitInstance(v);
4148            }
4149        }
4150    
4151        private StackValue generateWhenCondition(Type subjectType, int subjectLocal, KtWhenCondition condition) {
4152            if (condition instanceof KtWhenConditionInRange) {
4153                KtWhenConditionInRange conditionInRange = (KtWhenConditionInRange) condition;
4154                return generateIn(StackValue.local(subjectLocal, subjectType),
4155                                  conditionInRange.getRangeExpression(),
4156                                  conditionInRange.getOperationReference());
4157            }
4158            StackValue.Local match = subjectLocal == -1 ? null : StackValue.local(subjectLocal, subjectType);
4159            if (condition instanceof KtWhenConditionIsPattern) {
4160                KtWhenConditionIsPattern patternCondition = (KtWhenConditionIsPattern) condition;
4161                return generateIsCheck(match, patternCondition.getTypeReference(), patternCondition.isNegated());
4162            }
4163            else if (condition instanceof KtWhenConditionWithExpression) {
4164                KtExpression patternExpression = ((KtWhenConditionWithExpression) condition).getExpression();
4165                return generateExpressionMatch(match, patternExpression);
4166            }
4167            else {
4168                throw new UnsupportedOperationException("unsupported kind of when condition");
4169            }
4170        }
4171    
4172        private Call makeFakeCall(ReceiverValue initializerAsReceiver) {
4173            KtSimpleNameExpression fake = KtPsiFactoryKt.KtPsiFactory(state.getProject()).createSimpleName("fake");
4174            return CallMaker.makeCall(fake, initializerAsReceiver);
4175        }
4176    
4177        @Override
4178        public String toString() {
4179            return context.getContextDescriptor().toString();
4180        }
4181    
4182        @NotNull
4183        public FrameMap getFrameMap() {
4184            return myFrameMap;
4185        }
4186    
4187        @NotNull
4188        public MethodContext getContext() {
4189            return context;
4190        }
4191    
4192        @NotNull
4193        public NameGenerator getInlineNameGenerator() {
4194            NameGenerator nameGenerator = getParentCodegen().getInlineNameGenerator();
4195            Name name = context.getContextDescriptor().getName();
4196            return nameGenerator.subGenerator((name.isSpecial() ? "$special" : name.asString()) + "$$inlined" );
4197        }
4198    
4199        public Type getReturnType() {
4200            return returnType;
4201        }
4202    
4203        public Stack<BlockStackElement> getBlockStackElements() {
4204            return new Stack<BlockStackElement>(blockStackElements);
4205        }
4206    
4207        public void addBlockStackElementsForNonLocalReturns(@NotNull Stack<BlockStackElement> elements, int finallyDepth) {
4208            blockStackElements.addAll(elements);
4209            this.finallyDepth = finallyDepth;
4210        }
4211    
4212        private static class NonLocalReturnInfo {
4213    
4214            final Type returnType;
4215    
4216            final String labelName;
4217    
4218            private NonLocalReturnInfo(Type type, String name) {
4219                returnType = type;
4220                labelName = name;
4221            }
4222        }
4223    }