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