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