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