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