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