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