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