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