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