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