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