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