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