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