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);
2446                }
2447                else {
2448                    throw new UnsupportedOperationException("Unsupported callable reference container: " + containingDeclaration);
2449                }
2450            }
2451    
2452            throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText());
2453        }
2454    
2455        @NotNull
2456        private StackValue generateTopLevelPropertyReference(@NotNull VariableDescriptor descriptor) {
2457            PackageFragmentDescriptor containingPackage = (PackageFragmentDescriptor) descriptor.getContainingDeclaration();
2458            String packageClassInternalName = PackageClassUtils.getPackageClassInternalName(containingPackage.getFqName());
2459    
2460            ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter();
2461            Method factoryMethod;
2462            if (receiverParameter != null) {
2463                Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_IMPL_TYPE, getType(Class.class)};
2464                factoryMethod = descriptor.isVar()
2465                                ? method("mutableTopLevelExtensionProperty", K_MUTABLE_TOP_LEVEL_EXTENSION_PROPERTY_IMPL_TYPE, parameterTypes)
2466                                : method("topLevelExtensionProperty", K_TOP_LEVEL_EXTENSION_PROPERTY_IMPL_TYPE, parameterTypes);
2467            }
2468            else {
2469                Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_IMPL_TYPE};
2470                factoryMethod = descriptor.isVar()
2471                                ? method("mutableTopLevelVariable", K_MUTABLE_TOP_LEVEL_VARIABLE_IMPL_TYPE, parameterTypes)
2472                                : method("topLevelVariable", K_TOP_LEVEL_VARIABLE_IMPL_TYPE, parameterTypes);
2473            }
2474    
2475            v.visitLdcInsn(descriptor.getName().asString());
2476            v.getstatic(packageClassInternalName, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, K_PACKAGE_IMPL_TYPE.getDescriptor());
2477    
2478            if (receiverParameter != null) {
2479                putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter));
2480            }
2481    
2482            v.invokestatic(REFLECTION_INTERNAL_PACKAGE, factoryMethod.getName(), factoryMethod.getDescriptor(), false);
2483    
2484            return StackValue.onStack(factoryMethod.getReturnType());
2485        }
2486    
2487        @NotNull
2488        private StackValue generateMemberPropertyReference(@NotNull VariableDescriptor descriptor) {
2489            ClassDescriptor containingClass = (ClassDescriptor) descriptor.getContainingDeclaration();
2490            Type classAsmType = typeMapper.mapClass(containingClass);
2491    
2492            if (containingClass instanceof JavaClassDescriptor) {
2493                v.aconst(classAsmType);
2494                v.invokestatic(REFLECTION_INTERNAL_PACKAGE, "foreignKotlinClass",
2495                               Type.getMethodDescriptor(K_CLASS_IMPL_TYPE, getType(Class.class)), false);
2496            }
2497            else {
2498                v.getstatic(classAsmType.getInternalName(), JvmAbi.KOTLIN_CLASS_FIELD_NAME, K_CLASS_IMPL_TYPE.getDescriptor());
2499            }
2500    
2501            Method factoryMethod = descriptor.isVar()
2502                                   ? method("mutableMemberProperty", K_MUTABLE_MEMBER_PROPERTY_TYPE, JAVA_STRING_TYPE)
2503                                   : method("memberProperty", K_MEMBER_PROPERTY_TYPE, JAVA_STRING_TYPE);
2504    
2505            v.visitLdcInsn(descriptor.getName().asString());
2506            v.invokevirtual(K_CLASS_IMPL_TYPE.getInternalName(), factoryMethod.getName(), factoryMethod.getDescriptor(), false);
2507    
2508            return StackValue.onStack(factoryMethod.getReturnType());
2509        }
2510    
2511        private static class CallableReferenceGenerationStrategy extends FunctionGenerationStrategy.CodegenBased<FunctionDescriptor> {
2512            private final ResolvedCall<?> resolvedCall;
2513            private final FunctionDescriptor referencedFunction;
2514    
2515            public CallableReferenceGenerationStrategy(
2516                    @NotNull GenerationState state,
2517                    @NotNull FunctionDescriptor functionDescriptor,
2518                    @NotNull ResolvedCall<?> resolvedCall
2519            ) {
2520                super(state, functionDescriptor);
2521                this.resolvedCall = resolvedCall;
2522                this.referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
2523            }
2524    
2525            @Override
2526            public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
2527                /*
2528                 Here we need to put the arguments from our locals to the stack and invoke the referenced method. Since invocation
2529                 of methods is highly dependent on expressions, we create a fake call expression. Then we create a new instance of
2530                 ExpressionCodegen and, in order for it to generate code correctly, we save to its 'tempVariables' field every
2531                 argument of our fake expression, pointing it to the corresponding index in our locals. This way generation of
2532                 every argument boils down to calling LOAD with the corresponding index
2533                 */
2534    
2535                JetCallExpression fakeExpression = constructFakeFunctionCall();
2536                final List<? extends ValueArgument> fakeArguments = fakeExpression.getValueArguments();
2537    
2538                final ReceiverValue thisObject = computeAndSaveReceiver(signature, codegen, referencedFunction.getExpectedThisObject());
2539                final ReceiverValue extensionReceiver = computeAndSaveReceiver(signature, codegen, referencedFunction.getReceiverParameter());
2540                computeAndSaveArguments(fakeArguments, codegen);
2541    
2542                ResolvedCall<CallableDescriptor> fakeResolvedCall = new DelegatingResolvedCall<CallableDescriptor>(resolvedCall) {
2543                    @NotNull
2544                    @Override
2545                    public ReceiverValue getReceiverArgument() {
2546                        return extensionReceiver;
2547                    }
2548    
2549                    @NotNull
2550                    @Override
2551                    public ReceiverValue getThisObject() {
2552                        return thisObject;
2553                    }
2554    
2555                    @NotNull
2556                    @Override
2557                    public List<ResolvedValueArgument> getValueArgumentsByIndex() {
2558                        List<ResolvedValueArgument> result = new ArrayList<ResolvedValueArgument>(fakeArguments.size());
2559                        for (ValueArgument argument : fakeArguments) {
2560                            result.add(new ExpressionValueArgument(argument));
2561                        }
2562                        return result;
2563                    }
2564                };
2565    
2566                StackValue result;
2567                Type returnType = codegen.returnType;
2568                if (referencedFunction instanceof ConstructorDescriptor) {
2569                    if (returnType.getSort() == Type.ARRAY) {
2570                        //noinspection ConstantConditions
2571                        codegen.generateNewArray(fakeExpression, referencedFunction.getReturnType());
2572                        result = StackValue.onStack(returnType);
2573                    }
2574                    else {
2575                        result = codegen.generateConstructorCall(fakeResolvedCall, returnType);
2576                    }
2577                }
2578                else {
2579                    Call call = CallMaker.makeCall(fakeExpression, NO_RECEIVER, null, fakeExpression, fakeArguments);
2580                    result = codegen.invokeFunction(call, fakeResolvedCall, StackValue.none());
2581                }
2582    
2583                InstructionAdapter v = codegen.v;
2584                result.put(returnType, v);
2585                v.areturn(returnType);
2586            }
2587    
2588            @NotNull
2589            private JetCallExpression constructFakeFunctionCall() {
2590                StringBuilder fakeFunctionCall = new StringBuilder("callableReferenceFakeCall(");
2591                for (Iterator<ValueParameterDescriptor> iterator = referencedFunction.getValueParameters().iterator(); iterator.hasNext(); ) {
2592                    ValueParameterDescriptor descriptor = iterator.next();
2593                    fakeFunctionCall.append("p").append(descriptor.getIndex());
2594                    if (iterator.hasNext()) {
2595                        fakeFunctionCall.append(", ");
2596                    }
2597                }
2598                fakeFunctionCall.append(")");
2599                return (JetCallExpression) JetPsiFactory(state.getProject()).createExpression(fakeFunctionCall.toString());
2600            }
2601    
2602            private void computeAndSaveArguments(@NotNull List<? extends ValueArgument> fakeArguments, @NotNull ExpressionCodegen codegen) {
2603                for (ValueParameterDescriptor parameter : callableDescriptor.getValueParameters()) {
2604                    ValueArgument fakeArgument = fakeArguments.get(parameter.getIndex());
2605                    Type type = state.getTypeMapper().mapType(parameter);
2606                    int localIndex = codegen.myFrameMap.getIndex(parameter);
2607                    codegen.tempVariables.put(fakeArgument.getArgumentExpression(), StackValue.local(localIndex, type));
2608                }
2609            }
2610    
2611            @NotNull
2612            private ReceiverValue computeAndSaveReceiver(
2613                    @NotNull JvmMethodSignature signature,
2614                    @NotNull ExpressionCodegen codegen,
2615                    @Nullable ReceiverParameterDescriptor receiver
2616            ) {
2617                if (receiver == null) return NO_RECEIVER;
2618    
2619                JetExpression receiverExpression = JetPsiFactory(state.getProject()).createExpression("callableReferenceFakeReceiver");
2620                codegen.tempVariables.put(receiverExpression, receiverParameterStackValue(signature));
2621                return new ExpressionReceiver(receiverExpression, receiver.getType());
2622            }
2623    
2624            @NotNull
2625            private static StackValue.Local receiverParameterStackValue(@NotNull JvmMethodSignature signature) {
2626                // 0 is this (the callable reference class), 1 is the invoke() method's first parameter
2627                return StackValue.local(1, signature.getAsmMethod().getArgumentTypes()[0]);
2628            }
2629        }
2630    
2631        @Override
2632        public StackValue visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, StackValue receiver) {
2633            StackValue receiverValue = StackValue.none();
2634            return genQualified(receiverValue, expression.getSelectorExpression());
2635        }
2636    
2637        private void generateExpressionWithNullFallback(@NotNull JetExpression expression, @NotNull Label ifnull) {
2638            expression = JetPsiUtil.deparenthesize(expression);
2639            Type type = expressionType(expression);
2640    
2641            if (expression instanceof JetSafeQualifiedExpression && !isPrimitive(type)) {
2642                StackValue value = generateSafeQualifiedExpression((JetSafeQualifiedExpression) expression, ifnull);
2643                value.put(type, v);
2644            }
2645            else {
2646                gen(expression, type);
2647            }
2648        }
2649    
2650        private StackValue generateSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression, @NotNull Label ifnull) {
2651            JetExpression receiver = expression.getReceiverExpression();
2652            JetExpression selector = expression.getSelectorExpression();
2653            Type receiverType = expressionType(receiver);
2654    
2655            generateExpressionWithNullFallback(receiver, ifnull);
2656    
2657            if (isPrimitive(receiverType)) {
2658                return genQualified(StackValue.onStack(receiverType), selector);
2659            }
2660    
2661            v.dup();
2662            v.ifnull(ifnull);
2663            return genQualified(StackValue.onStack(receiverType), selector);
2664        }
2665    
2666        @Override
2667        public StackValue visitSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression, StackValue unused) {
2668            Label ifnull = new Label();
2669            Type type = boxType(expressionType(expression));
2670    
2671            StackValue value = generateSafeQualifiedExpression(expression, ifnull);
2672            value.put(type, v);
2673    
2674            if (!isPrimitive(expressionType(expression.getReceiverExpression()))) {
2675                Label end = new Label();
2676    
2677                v.goTo(end);
2678                v.mark(ifnull);
2679                v.pop();
2680                if (!type.equals(Type.VOID_TYPE)) {
2681                    v.aconst(null);
2682                }
2683                v.mark(end);
2684            }
2685    
2686            return StackValue.onStack(type);
2687        }
2688    
2689        @Override
2690        public StackValue visitBinaryExpression(@NotNull JetBinaryExpression expression, StackValue receiver) {
2691            JetSimpleNameExpression reference = expression.getOperationReference();
2692            IElementType opToken = reference.getReferencedNameElementType();
2693            if (opToken == JetTokens.EQ) {
2694                return generateAssignmentExpression(expression);
2695            }
2696            else if (JetTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) {
2697                return generateAugmentedAssignment(expression);
2698            }
2699            else if (opToken == JetTokens.ANDAND) {
2700                return generateBooleanAnd(expression);
2701            }
2702            else if (opToken == JetTokens.OROR) {
2703                return generateBooleanOr(expression);
2704            }
2705            else if (opToken == JetTokens.EQEQ || opToken == JetTokens.EXCLEQ ||
2706                     opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
2707                return generateEquals(expression.getLeft(), expression.getRight(), opToken);
2708            }
2709            else if (opToken == JetTokens.LT || opToken == JetTokens.LTEQ ||
2710                     opToken == JetTokens.GT || opToken == JetTokens.GTEQ) {
2711                return generateComparison(expression, receiver);
2712            }
2713            else if (opToken == JetTokens.ELVIS) {
2714                return generateElvis(expression);
2715            }
2716            else if (opToken == JetTokens.IN_KEYWORD || opToken == JetTokens.NOT_IN) {
2717                return generateIn(StackValue.expression(Type.INT_TYPE, expression.getLeft(), this), expression.getRight(), reference);
2718            }
2719            else {
2720                ResolvedCall<?> resolvedCall = getResolvedCallWithAssert(expression, bindingContext);
2721                FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
2722    
2723                Callable callable = resolveToCallable(descriptor, false);
2724                if (callable instanceof IntrinsicMethod) {
2725                    Type returnType = typeMapper.mapType(descriptor);
2726                    ((IntrinsicMethod) callable).generate(this, v, returnType, expression,
2727                                                          Arrays.asList(expression.getLeft(), expression.getRight()), receiver);
2728                    return StackValue.onStack(returnType);
2729                }
2730    
2731                return invokeFunction(resolvedCall, receiver);
2732            }
2733        }
2734    
2735        private StackValue generateIn(StackValue leftValue, JetExpression rangeExpression, JetSimpleNameExpression operationReference) {
2736            JetExpression deparenthesized = JetPsiUtil.deparenthesize(rangeExpression);
2737            if (isIntRangeExpr(deparenthesized)) {
2738                genInIntRange(leftValue, (JetBinaryExpression) deparenthesized);
2739            }
2740            else {
2741                ResolvedCall<? extends CallableDescriptor> resolvedCall = getResolvedCallWithAssert(operationReference, bindingContext);
2742                invokeFunction(resolvedCall, StackValue.none());
2743            }
2744            if (operationReference.getReferencedNameElementType() == JetTokens.NOT_IN) {
2745                genInvertBoolean(v);
2746            }
2747            return StackValue.onStack(Type.BOOLEAN_TYPE);
2748        }
2749    
2750        private void genInIntRange(StackValue leftValue, JetBinaryExpression rangeExpression) {
2751            v.iconst(1);
2752            // 1
2753            leftValue.put(Type.INT_TYPE, v);
2754            // 1 l
2755            v.dup2();
2756            // 1 l 1 l
2757    
2758            //noinspection ConstantConditions
2759            gen(rangeExpression.getLeft(), Type.INT_TYPE);
2760            // 1 l 1 l r
2761            Label lok = new Label();
2762            v.ificmpge(lok);
2763            // 1 l 1
2764            v.pop();
2765            v.iconst(0);
2766            v.mark(lok);
2767            // 1 l c
2768            v.dupX2();
2769            // c 1 l c
2770            v.pop();
2771            // c 1 l
2772    
2773            gen(rangeExpression.getRight(), Type.INT_TYPE);
2774            // c 1 l r
2775            Label rok = new Label();
2776            v.ificmple(rok);
2777            // c 1
2778            v.pop();
2779            v.iconst(0);
2780            v.mark(rok);
2781            // c c
2782    
2783            v.and(Type.INT_TYPE);
2784        }
2785    
2786        private StackValue generateBooleanAnd(JetBinaryExpression expression) {
2787            gen(expression.getLeft(), Type.BOOLEAN_TYPE);
2788            Label ifFalse = new Label();
2789            v.ifeq(ifFalse);
2790            gen(expression.getRight(), Type.BOOLEAN_TYPE);
2791            Label end = new Label();
2792            v.goTo(end);
2793            v.mark(ifFalse);
2794            v.iconst(0);
2795            v.mark(end);
2796            return StackValue.onStack(Type.BOOLEAN_TYPE);
2797        }
2798    
2799        private StackValue generateBooleanOr(JetBinaryExpression expression) {
2800            gen(expression.getLeft(), Type.BOOLEAN_TYPE);
2801            Label ifTrue = new Label();
2802            v.ifne(ifTrue);
2803            gen(expression.getRight(), Type.BOOLEAN_TYPE);
2804            Label end = new Label();
2805            v.goTo(end);
2806            v.mark(ifTrue);
2807            v.iconst(1);
2808            v.mark(end);
2809            return StackValue.onStack(Type.BOOLEAN_TYPE);
2810        }
2811    
2812        private StackValue generateEquals(JetExpression left, JetExpression right, IElementType opToken) {
2813            Type leftType = expressionType(left);
2814            Type rightType = expressionType(right);
2815    
2816            if (JetPsiUtil.isNullConstant(left)) {
2817                return genCmpWithNull(right, rightType, opToken);
2818            }
2819    
2820            if (JetPsiUtil.isNullConstant(right)) {
2821                return genCmpWithNull(left, leftType, opToken);
2822            }
2823    
2824            if (isIntZero(left, leftType) && isIntPrimitive(rightType)) {
2825                return genCmpWithZero(right, rightType, opToken);
2826            }
2827    
2828            if (isIntZero(right, rightType) && isIntPrimitive(leftType)) {
2829                return genCmpWithZero(left, leftType, opToken);
2830            }
2831    
2832            if (isPrimitive(leftType) != isPrimitive(rightType)) {
2833                leftType = boxType(leftType);
2834                gen(left, leftType);
2835                rightType = boxType(rightType);
2836                gen(right, rightType);
2837            }
2838            else {
2839                gen(left, leftType);
2840                gen(right, rightType);
2841            }
2842    
2843            return genEqualsForExpressionsOnStack(v, opToken, leftType, rightType);
2844        }
2845    
2846        private boolean isIntZero(JetExpression expr, Type exprType) {
2847            CompileTimeConstant<?> exprValue = getCompileTimeConstant(expr, bindingContext);
2848            return isIntPrimitive(exprType) && exprValue != null && Integer.valueOf(0).equals(exprValue.getValue());
2849        }
2850    
2851        private StackValue genCmpWithZero(JetExpression exp, Type expType, IElementType opToken) {
2852            v.iconst(1);
2853            gen(exp, expType);
2854            Label ok = new Label();
2855            if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) {
2856                v.ifeq(ok);
2857            }
2858            else {
2859                v.ifne(ok);
2860            }
2861            v.pop();
2862            v.iconst(0);
2863            v.mark(ok);
2864            return StackValue.onStack(Type.BOOLEAN_TYPE);
2865        }
2866    
2867        private StackValue genCmpWithNull(JetExpression exp, Type expType, IElementType opToken) {
2868            v.iconst(1);
2869            gen(exp, boxType(expType));
2870            Label ok = new Label();
2871            if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) {
2872                v.ifnull(ok);
2873            }
2874            else {
2875                v.ifnonnull(ok);
2876            }
2877            v.pop();
2878            v.iconst(0);
2879            v.mark(ok);
2880            return StackValue.onStack(Type.BOOLEAN_TYPE);
2881        }
2882    
2883        private StackValue generateElvis(JetBinaryExpression expression) {
2884            JetExpression left = expression.getLeft();
2885    
2886            Type exprType = expressionType(expression);
2887            Type leftType = expressionType(left);
2888    
2889            Label ifNull = new Label();
2890    
2891    
2892            assert left != null : "left expression in elvis should be not null: " + expression.getText();
2893            generateExpressionWithNullFallback(left, ifNull);
2894    
2895            if (isPrimitive(leftType)) {
2896                return StackValue.onStack(leftType);
2897            }
2898    
2899            v.dup();
2900    
2901            v.ifnull(ifNull);
2902            StackValue.onStack(leftType).put(exprType, v);
2903    
2904            Label end = new Label();
2905            v.goTo(end);
2906    
2907            v.mark(ifNull);
2908            v.pop();
2909            gen(expression.getRight(), exprType);
2910            v.mark(end);
2911    
2912            return StackValue.onStack(exprType);
2913        }
2914    
2915        private StackValue generateComparison(JetBinaryExpression expression, StackValue receiver) {
2916            ResolvedCall<?> resolvedCall = getResolvedCallWithAssert(expression, bindingContext);
2917            FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
2918    
2919            JetExpression left = expression.getLeft();
2920            JetExpression right = expression.getRight();
2921            Callable callable = resolveToCallable(descriptor, false);
2922    
2923            Type type;
2924            if (callable instanceof IntrinsicMethod) {
2925                // Compare two primitive values
2926                type = comparisonOperandType(expressionType(left), expressionType(right));
2927                StackValue recv = gen(left);
2928                recv.put(type, v);
2929                gen(right, type);
2930            }
2931            else {
2932                StackValue result = invokeFunction(resolvedCall, receiver);
2933                type = Type.INT_TYPE;
2934                result.put(type, v);
2935                v.iconst(0);
2936            }
2937            return StackValue.cmp(expression.getOperationToken(), type);
2938        }
2939    
2940        private StackValue generateAssignmentExpression(JetBinaryExpression expression) {
2941            StackValue stackValue = gen(expression.getLeft());
2942            JetExpression right = expression.getRight();
2943            assert right != null : expression.getText();
2944            gen(right, stackValue.type);
2945            stackValue.store(stackValue.type, v);
2946            return StackValue.none();
2947        }
2948    
2949        private StackValue generateAugmentedAssignment(JetBinaryExpression expression) {
2950            ResolvedCall<?> resolvedCall = getResolvedCallWithAssert(expression, bindingContext);
2951            FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
2952            Callable callable = resolveToCallable(descriptor, false);
2953            JetExpression lhs = expression.getLeft();
2954            Type lhsType = expressionType(lhs);
2955    
2956            boolean keepReturnValue;
2957            if (Boolean.TRUE.equals(bindingContext.get(VARIABLE_REASSIGNMENT, expression))) {
2958                if (callable instanceof IntrinsicMethod) {
2959                    StackValue value = gen(lhs);              // receiver
2960                    value.dupReceiver(v);                     // receiver receiver
2961                    value.put(lhsType, v);                    // receiver lhs
2962                    ((IntrinsicMethod) callable).generate(this, v, typeMapper.mapType(descriptor), expression,
2963                                                          Collections.singletonList(expression.getRight()), StackValue.onStack(lhsType));
2964                    value.store(lhsType, v);
2965                    return StackValue.none();
2966                }
2967                else {
2968                    keepReturnValue = true;
2969                }
2970            }
2971            else {
2972                keepReturnValue = !KotlinBuiltIns.getInstance().getUnitType().equals(descriptor.getReturnType());
2973            }
2974    
2975            callAugAssignMethod(expression, resolvedCall, (CallableMethod) callable, lhsType, keepReturnValue);
2976    
2977            return StackValue.none();
2978        }
2979    
2980        private void callAugAssignMethod(
2981                @NotNull JetBinaryExpression expression,
2982                @NotNull ResolvedCall<?> resolvedCall,
2983                @NotNull CallableMethod callable,
2984                @NotNull Type lhsType,
2985                boolean keepReturnValue
2986        ) {
2987            StackValue value = gen(expression.getLeft());
2988            if (keepReturnValue) {
2989                value.dupReceiver(v);
2990            }
2991            value.put(lhsType, v);
2992            StackValue receiver = StackValue.onStack(lhsType);
2993    
2994            invokeMethodWithArguments(callable, resolvedCall, receiver);
2995    
2996            if (keepReturnValue) {
2997                value.store(callable.getReturnType(), v);
2998            }
2999        }
3000    
3001        public void invokeAppend(JetExpression expr) {
3002            if (expr instanceof JetBinaryExpression) {
3003                JetBinaryExpression binaryExpression = (JetBinaryExpression) expr;
3004                if (binaryExpression.getOperationToken() == JetTokens.PLUS) {
3005                    JetExpression left = binaryExpression.getLeft();
3006                    JetExpression right = binaryExpression.getRight();
3007                    Type leftType = expressionType(left);
3008                    Type rightType = expressionType(right);
3009    
3010                    if (leftType.equals(JAVA_STRING_TYPE) && rightType.equals(JAVA_STRING_TYPE)) {
3011                        invokeAppend(left);
3012                        invokeAppend(right);
3013                        return;
3014                    }
3015                }
3016            }
3017            Type exprType = expressionType(expr);
3018            gen(expr, exprType);
3019            genInvokeAppendMethod(v, exprType.getSort() == Type.ARRAY ? OBJECT_TYPE : exprType);
3020        }
3021    
3022        @Nullable
3023        private static JetSimpleNameExpression targetLabel(JetExpression expression) {
3024            if (expression.getParent() instanceof JetLabeledExpression) {
3025                return ((JetLabeledExpression) expression.getParent()).getTargetLabel();
3026            }
3027            return null;
3028        }
3029    
3030        @Override
3031        public StackValue visitLabeledExpression(
3032                @NotNull JetLabeledExpression expression, StackValue receiver
3033        ) {
3034            return genQualified(receiver, expression.getBaseExpression());
3035        }
3036    
3037        @Override
3038        public StackValue visitPrefixExpression(@NotNull JetPrefixExpression expression, StackValue receiver) {
3039            DeclarationDescriptor op = bindingContext.get(REFERENCE_TARGET, expression.getOperationReference());
3040            assert op instanceof FunctionDescriptor : String.valueOf(op);
3041            Callable callable = resolveToCallable((FunctionDescriptor) op, false);
3042            if (callable instanceof IntrinsicMethod) {
3043                Type returnType = typeMapper.mapType((FunctionDescriptor) op);
3044                ((IntrinsicMethod) callable).generate(this, v, returnType, expression,
3045                                                      Collections.singletonList(expression.getBaseExpression()), receiver);
3046                return StackValue.onStack(returnType);
3047            }
3048    
3049            DeclarationDescriptor cls = op.getContainingDeclaration();
3050            ResolvedCall<?> resolvedCall = getResolvedCallWithAssert(expression, bindingContext);
3051    
3052            if (isPrimitiveNumberClassDescriptor(cls) || !(op.getName().asString().equals("inc") || op.getName().asString().equals("dec"))) {
3053                return invokeFunction(resolvedCall, receiver);
3054            }
3055    
3056            CallableMethod callableMethod = (CallableMethod) callable;
3057    
3058            StackValue value = gen(expression.getBaseExpression());
3059            value.dupReceiver(v);
3060            value.dupReceiver(v);
3061    
3062            Type type = expressionType(expression.getBaseExpression());
3063            value.put(type, v);
3064            callableMethod.invokeWithNotNullAssertion(v, state, resolvedCall);
3065    
3066            value.store(callableMethod.getReturnType(), v);
3067            value.put(type, v);
3068            return StackValue.onStack(type);
3069        }
3070    
3071        @Override
3072        public StackValue visitPostfixExpression(@NotNull JetPostfixExpression expression, StackValue receiver) {
3073            if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL) {
3074                StackValue base = genQualified(receiver, expression.getBaseExpression());
3075                if (isPrimitive(base.type)) {
3076                    return base;
3077                }
3078                base.put(base.type, v);
3079                v.dup();
3080                Label ok = new Label();
3081                v.ifnonnull(ok);
3082                v.invokestatic("kotlin/jvm/internal/Intrinsics", "throwNpe", "()V", false);
3083                v.mark(ok);
3084                return StackValue.onStack(base.type);
3085            }
3086    
3087            DeclarationDescriptor op = bindingContext.get(REFERENCE_TARGET, expression.getOperationReference());
3088            if (!(op instanceof FunctionDescriptor)) {
3089                throw new UnsupportedOperationException("Don't know how to generate this postfix expression: " + op);
3090            }
3091    
3092            Type asmType = expressionType(expression);
3093            DeclarationDescriptor cls = op.getContainingDeclaration();
3094    
3095            int increment;
3096            if (op.getName().asString().equals("inc")) {
3097                increment = 1;
3098            }
3099            else if (op.getName().asString().equals("dec")) {
3100                increment = -1;
3101            }
3102            else {
3103                throw new UnsupportedOperationException("Unsupported postfix operation: " + op);
3104            }
3105    
3106            boolean isPrimitiveNumberClassDescriptor = isPrimitiveNumberClassDescriptor(cls);
3107            if (isPrimitiveNumberClassDescriptor) {
3108                JetExpression operand = expression.getBaseExpression();
3109                if (operand instanceof JetReferenceExpression && asmType == Type.INT_TYPE) {
3110                    int index = indexOfLocal((JetReferenceExpression) operand);
3111                    if (index >= 0) {
3112                        return StackValue.postIncrement(index, increment);
3113                    }
3114                }
3115            }
3116    
3117            StackValue value = gen(expression.getBaseExpression());
3118            value.dupReceiver(v);
3119    
3120            Type type = expressionType(expression.getBaseExpression());
3121            value.put(type, v); // old value
3122    
3123            pushReceiverAndValueViaDup(value, type); // receiver and new value
3124    
3125            Type storeType;
3126            if (isPrimitiveNumberClassDescriptor) {
3127                genIncrement(asmType, increment, v);
3128                storeType = type;
3129            }
3130            else {
3131                ResolvedCall<?> resolvedCall = getResolvedCallWithAssert(expression, bindingContext);
3132                Callable callable = resolveToCallable((FunctionDescriptor) op, false);
3133                CallableMethod callableMethod = (CallableMethod) callable;
3134                callableMethod.invokeWithNotNullAssertion(v, state, resolvedCall);
3135                storeType = callableMethod.getReturnType();
3136            }
3137    
3138            value.store(storeType, v);
3139            return StackValue.onStack(asmType);  // old value
3140        }
3141    
3142        private void pushReceiverAndValueViaDup(StackValue value, Type type) {
3143            switch (value.receiverSize()) {
3144                case 0:
3145                    dup(v, type);
3146                    break;
3147    
3148                case 1:
3149                    if (type.getSize() == 2) {
3150                        v.dup2X1();
3151                    }
3152                    else {
3153                        v.dupX1();
3154                    }
3155                    break;
3156    
3157                case 2:
3158                    if (type.getSize() == 2) {
3159                        v.dup2X2();
3160                    }
3161                    else {
3162                        v.dupX2();
3163                    }
3164                    break;
3165    
3166                case -1:
3167                    throw new UnsupportedOperationException();
3168            }
3169        }
3170    
3171        @Override
3172        public StackValue visitProperty(@NotNull JetProperty property, StackValue receiver) {
3173            final JetExpression initializer = property.getInitializer();
3174            if (initializer == null) {
3175                return StackValue.none();
3176            }
3177            initializeLocalVariable(property, new Function<VariableDescriptor, Void>() {
3178                @Override
3179                public Void fun(VariableDescriptor descriptor) {
3180                    Type varType = asmType(descriptor.getType());
3181                    gen(initializer, varType);
3182                    return null;
3183                }
3184            });
3185            return StackValue.none();
3186        }
3187    
3188        @Override
3189        public StackValue visitMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration, StackValue receiver) {
3190            JetExpression initializer = multiDeclaration.getInitializer();
3191            if (initializer == null) return StackValue.none();
3192    
3193            JetType initializerType = bindingContext.get(EXPRESSION_TYPE, initializer);
3194            assert initializerType != null;
3195    
3196            Type initializerAsmType = asmType(initializerType);
3197    
3198            final TransientReceiver initializerAsReceiver = new TransientReceiver(initializerType);
3199    
3200            int tempVarIndex = myFrameMap.enterTemp(initializerAsmType);
3201    
3202            gen(initializer, initializerAsmType);
3203            v.store(tempVarIndex, initializerAsmType);
3204            final StackValue.Local local = StackValue.local(tempVarIndex, initializerAsmType);
3205    
3206            for (final JetMultiDeclarationEntry variableDeclaration : multiDeclaration.getEntries()) {
3207                initializeLocalVariable(variableDeclaration, new Function<VariableDescriptor, Void>() {
3208                    @Override
3209                    public Void fun(VariableDescriptor descriptor) {
3210                        ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(COMPONENT_RESOLVED_CALL, variableDeclaration);
3211                        assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText();
3212                        Call call = makeFakeCall(initializerAsReceiver);
3213                        invokeFunction(call, resolvedCall, local);
3214                        return null;
3215                    }
3216                });
3217            }
3218    
3219            if (initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) {
3220                v.aconst(null);
3221                v.store(tempVarIndex, initializerAsmType);
3222            }
3223            myFrameMap.leaveTemp(initializerAsmType);
3224    
3225            return StackValue.none();
3226        }
3227    
3228        private void initializeLocalVariable(
3229                @NotNull JetVariableDeclaration variableDeclaration,
3230                @NotNull Function<VariableDescriptor, Void> generateInitializer
3231        ) {
3232            VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, variableDeclaration);
3233    
3234            if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) {
3235                return;
3236            }
3237            int index = lookupLocalIndex(variableDescriptor);
3238    
3239            if (index < 0) {
3240                throw new IllegalStateException("Local variable not found for " + variableDescriptor);
3241            }
3242    
3243            Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
3244            assert variableDescriptor != null;
3245    
3246            Type varType = asmType(variableDescriptor.getType());
3247    
3248            // SCRIPT: Variable at the top of the script is generated as field
3249            if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) {
3250                generateInitializer.fun(variableDescriptor);
3251                JetScript scriptPsi = JetPsiUtil.getScript(variableDeclaration);
3252                assert scriptPsi != null;
3253                Type scriptClassType = asmTypeForScriptPsi(bindingContext, scriptPsi);
3254                v.putfield(scriptClassType.getInternalName(), variableDeclaration.getName(), varType.getDescriptor());
3255            }
3256            else if (sharedVarType == null) {
3257                generateInitializer.fun(variableDescriptor);
3258                v.store(index, varType);
3259            }
3260            else {
3261                v.load(index, OBJECT_TYPE);
3262                generateInitializer.fun(variableDescriptor);
3263                v.putfield(sharedVarType.getInternalName(), "element",
3264                           sharedVarType.equals(OBJECT_REF_TYPE) ? "Ljava/lang/Object;" : varType.getDescriptor());
3265            }
3266        }
3267    
3268        @NotNull
3269        private StackValue generateNewCall(@NotNull JetCallExpression expression, @NotNull ResolvedCall<?> resolvedCall) {
3270            Type type = expressionType(expression);
3271            if (type.getSort() == Type.ARRAY) {
3272                generateNewArray(expression);
3273                return StackValue.onStack(type);
3274            }
3275    
3276            return generateConstructorCall(resolvedCall, type);
3277        }
3278    
3279        @NotNull
3280        private StackValue generateConstructorCall(@NotNull ResolvedCall<?> resolvedCall, @NotNull Type type) {
3281            v.anew(type);
3282            v.dup();
3283    
3284            ConstructorDescriptor constructor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
3285    
3286            ReceiverParameterDescriptor expectedThisObject = constructor.getExpectedThisObject();
3287            if (expectedThisObject != null) {
3288                Type receiverType = typeMapper.mapType(expectedThisObject.getType());
3289                generateReceiverValue(resolvedCall.getThisObject(), receiverType);
3290            }
3291    
3292            MutableClosure closure = bindingContext.get(CLOSURE, constructor.getContainingDeclaration());
3293    
3294            // Resolved call to local class constructor doesn't have expectedThisObject, so we need to generate closure on stack
3295            // See StackValue.receiver for more info
3296            pushClosureOnStack(closure, expectedThisObject != null, defaultCallGenerator);
3297    
3298            ConstructorDescriptor originalOfSamAdapter = (ConstructorDescriptor) SamCodegenUtil.getOriginalIfSamAdapter(constructor);
3299            CallableMethod method = typeMapper.mapToCallableMethod(originalOfSamAdapter == null ? constructor : originalOfSamAdapter);
3300            invokeMethodWithArguments(method, resolvedCall, StackValue.none());
3301    
3302            return StackValue.onStack(type);
3303        }
3304    
3305        public void generateNewArray(@NotNull JetCallExpression expression) {
3306            JetType arrayType = bindingContext.get(EXPRESSION_TYPE, expression);
3307            assert arrayType != null : "Array instantiation isn't type checked: " + expression.getText();
3308    
3309            generateNewArray(expression, arrayType);
3310        }
3311    
3312        private void generateNewArray(@NotNull JetCallExpression expression, @NotNull JetType arrayType) {
3313            List<JetExpression> args = new ArrayList<JetExpression>();
3314            for (ValueArgument va : expression.getValueArguments()) {
3315                args.add(va.getArgumentExpression());
3316            }
3317    
3318            boolean isArray = KotlinBuiltIns.getInstance().isArray(arrayType);
3319            if (!isArray && args.size() != 1) {
3320                throw new CompilationException("primitive array constructor requires one argument", null, expression);
3321            }
3322    
3323            if (isArray) {
3324                gen(args.get(0), Type.INT_TYPE);
3325                v.newarray(boxType(asmType(arrayType.getArguments().get(0).getType())));
3326            }
3327            else {
3328                Type type = typeMapper.mapType(arrayType);
3329                gen(args.get(0), Type.INT_TYPE);
3330                v.newarray(correctElementType(type));
3331            }
3332    
3333            if (args.size() == 2) {
3334                int sizeIndex = myFrameMap.enterTemp(Type.INT_TYPE);
3335                int indexIndex = myFrameMap.enterTemp(Type.INT_TYPE);
3336    
3337                v.dup();
3338                v.arraylength();
3339                v.store(sizeIndex, Type.INT_TYPE);
3340    
3341                v.iconst(0);
3342                v.store(indexIndex, Type.INT_TYPE);
3343    
3344                gen(args.get(1), FUNCTION1_TYPE);
3345    
3346                Label begin = new Label();
3347                Label end = new Label();
3348                v.visitLabel(begin);
3349                v.load(indexIndex, Type.INT_TYPE);
3350                v.load(sizeIndex, Type.INT_TYPE);
3351                v.ificmpge(end);
3352    
3353                v.dup2();
3354                v.load(indexIndex, Type.INT_TYPE);
3355                v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
3356                v.invokeinterface(FUNCTION1_TYPE.getInternalName(), "invoke", "(Ljava/lang/Object;)Ljava/lang/Object;");
3357                v.load(indexIndex, Type.INT_TYPE);
3358                v.iinc(indexIndex, 1);
3359                v.swap();
3360                v.astore(OBJECT_TYPE);
3361    
3362                v.goTo(begin);
3363                v.visitLabel(end);
3364                v.pop();
3365    
3366                myFrameMap.leaveTemp(Type.INT_TYPE);
3367                myFrameMap.leaveTemp(Type.INT_TYPE);
3368            }
3369        }
3370    
3371        @Override
3372        public StackValue visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, StackValue receiver) {
3373            JetExpression array = expression.getArrayExpression();
3374            JetType type = bindingContext.get(EXPRESSION_TYPE, array);
3375            Type arrayType = expressionType(array);
3376            List<JetExpression> indices = expression.getIndexExpressions();
3377            FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(REFERENCE_TARGET, expression);
3378            assert operationDescriptor != null;
3379            if (arrayType.getSort() == Type.ARRAY &&
3380                indices.size() == 1 &&
3381                operationDescriptor.getValueParameters().get(0).getType().equals(KotlinBuiltIns.getInstance().getIntType())) {
3382                gen(array, arrayType);
3383                for (JetExpression index : indices) {
3384                    gen(index, Type.INT_TYPE);
3385                }
3386                assert type != null;
3387                if (KotlinBuiltIns.getInstance().isArray(type)) {
3388                    JetType elementType = type.getArguments().get(0).getType();
3389                    return StackValue.arrayElement(boxType(asmType(elementType)));
3390                }
3391                else {
3392                    return StackValue.arrayElement(correctElementType(arrayType));
3393                }
3394            }
3395            else {
3396                ResolvedCall<FunctionDescriptor> resolvedSetCall = bindingContext.get(INDEXED_LVALUE_SET, expression);
3397                ResolvedCall<FunctionDescriptor> resolvedGetCall = bindingContext.get(INDEXED_LVALUE_GET, expression);
3398    
3399                boolean isGetter = "get".equals(operationDescriptor.getName().asString());
3400    
3401                ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall;
3402                assert resolvedCall != null : "couldn't find resolved call: " + expression.getText();
3403    
3404                Callable callable = resolveToCallable(operationDescriptor, false);
3405                Method asmMethod = resolveToCallableMethod(operationDescriptor, false, context).getAsmMethod();
3406                Type[] argumentTypes = asmMethod.getArgumentTypes();
3407    
3408                if (callable instanceof CallableMethod) {
3409                    CallableMethod callableMethod = (CallableMethod) callable;
3410                    ArgumentGenerator argumentGenerator =
3411                            new CallBasedArgumentGenerator(this, defaultCallGenerator,
3412                                                           resolvedCall.getResultingDescriptor().getValueParameters(),
3413                                                           callableMethod.getValueParameterTypes());
3414    
3415                    receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
3416                    receiver.put(receiver.type, v);
3417    
3418                    List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
3419                    assert valueArguments != null : "Failed to arrange value arguments by index: " + operationDescriptor;
3420    
3421                    if (!isGetter) {
3422                        assert valueArguments.size() >= 2 : "Setter call should have at least 2 arguments: " + operationDescriptor;
3423    
3424                        // Skip generation of the right hand side of an indexed assignment, which is the last value argument
3425                        valueArguments.remove(valueArguments.size() - 1);
3426                    }
3427    
3428                    argumentGenerator.generate(valueArguments);
3429                }
3430                else {
3431                    gen(array, arrayType); // intrinsic method
3432    
3433                    int index = operationDescriptor.getReceiverParameter() != null ? 1 : 0;
3434    
3435                    for (JetExpression jetExpression : expression.getIndexExpressions()) {
3436                        gen(jetExpression, argumentTypes[index]);
3437                        index++;
3438                    }
3439                }
3440    
3441                Type elementType = isGetter ? asmMethod.getReturnType() : ArrayUtil.getLastElement(argumentTypes);
3442                return StackValue.collectionElement(elementType, resolvedGetCall, resolvedSetCall, this, state);
3443            }
3444        }
3445    
3446        @Override
3447        public StackValue visitThrowExpression(@NotNull JetThrowExpression expression, StackValue receiver) {
3448            gen(expression.getThrownExpression(), JAVA_THROWABLE_TYPE);
3449            v.athrow();
3450            return StackValue.none();
3451        }
3452    
3453        @Override
3454        public StackValue visitThisExpression(@NotNull JetThisExpression expression, StackValue receiver) {
3455            DeclarationDescriptor descriptor = bindingContext.get(REFERENCE_TARGET, expression.getInstanceReference());
3456            if (descriptor instanceof ClassDescriptor) {
3457                return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor, false, true);
3458            }
3459            if (descriptor instanceof CallableDescriptor) {
3460                return generateReceiver((CallableDescriptor) descriptor);
3461            }
3462            throw new UnsupportedOperationException("Neither this nor receiver: " + descriptor);
3463        }
3464    
3465        @Override
3466        public StackValue visitTryExpression(@NotNull JetTryExpression expression, StackValue receiver) {
3467            return generateTryExpression(expression, false);
3468        }
3469    
3470        public StackValue generateTryExpression(JetTryExpression expression, boolean isStatement) {
3471            /*
3472    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
3473    (or blocks).
3474             */
3475            JetFinallySection finallyBlock = expression.getFinallyBlock();
3476            FinallyBlockStackElement finallyBlockStackElement = null;
3477            if (finallyBlock != null) {
3478                finallyBlockStackElement = new FinallyBlockStackElement(expression);
3479                blockStackElements.push(finallyBlockStackElement);
3480            }
3481    
3482            JetType jetType = bindingContext.get(EXPRESSION_TYPE, expression);
3483            assert jetType != null;
3484            Type expectedAsmType = isStatement ? Type.VOID_TYPE : asmType(jetType);
3485    
3486            Label tryStart = new Label();
3487            v.mark(tryStart);
3488            v.nop(); // prevent verify error on empty try
3489    
3490            gen(expression.getTryBlock(), expectedAsmType);
3491    
3492            int savedValue = -1;
3493            if (!isStatement) {
3494                savedValue = myFrameMap.enterTemp(expectedAsmType);
3495                v.store(savedValue, expectedAsmType);
3496            }
3497    
3498            Label tryEnd = new Label();
3499            v.mark(tryEnd);
3500    
3501            //do it before finally block generation
3502            List<Label> tryBlockRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, tryEnd);
3503    
3504            Label end = new Label();
3505    
3506            genFinallyBlockOrGoto(finallyBlockStackElement, end);
3507    
3508            List<JetCatchClause> clauses = expression.getCatchClauses();
3509            for (int i = 0, size = clauses.size(); i < size; i++) {
3510                JetCatchClause clause = clauses.get(i);
3511    
3512                Label clauseStart = new Label();
3513                v.mark(clauseStart);
3514    
3515                VariableDescriptor descriptor = bindingContext.get(VALUE_PARAMETER, clause.getCatchParameter());
3516                assert descriptor != null;
3517                Type descriptorType = asmType(descriptor.getType());
3518                myFrameMap.enter(descriptor, descriptorType);
3519                int index = lookupLocalIndex(descriptor);
3520                v.store(index, descriptorType);
3521    
3522                gen(clause.getCatchBody(), expectedAsmType);
3523    
3524                if (!isStatement) {
3525                    v.store(savedValue, expectedAsmType);
3526                }
3527    
3528                myFrameMap.leave(descriptor);
3529    
3530                Label clauseEnd = new Label();
3531                v.mark(clauseEnd);
3532    
3533                v.visitLocalVariable(descriptor.getName().asString(), descriptorType.getDescriptor(), null, clauseStart, clauseEnd, index);
3534    
3535                genFinallyBlockOrGoto(finallyBlockStackElement, i != size - 1 || finallyBlock != null ? end : null);
3536    
3537                generateExceptionTable(clauseStart, tryBlockRegions, descriptorType.getInternalName());
3538            }
3539    
3540    
3541            //for default catch clause
3542            if (finallyBlock != null) {
3543                Label defaultCatchStart = new Label();
3544                v.mark(defaultCatchStart);
3545                int savedException = myFrameMap.enterTemp(JAVA_THROWABLE_TYPE);
3546                v.store(savedException, JAVA_THROWABLE_TYPE);
3547                Label defaultCatchEnd = new Label();
3548                v.mark(defaultCatchEnd);
3549    
3550                //do it before finally block generation
3551                //javac also generates entry in exception table for default catch clause too!!!! so defaultCatchEnd as end parameter
3552                List<Label> defaultCatchRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, defaultCatchEnd);
3553    
3554    
3555                genFinallyBlockOrGoto(finallyBlockStackElement, null);
3556    
3557                v.load(savedException, JAVA_THROWABLE_TYPE);
3558                myFrameMap.leaveTemp(JAVA_THROWABLE_TYPE);
3559    
3560                v.athrow();
3561    
3562                generateExceptionTable(defaultCatchStart, defaultCatchRegions, null);
3563            }
3564    
3565            markLineNumber(expression);
3566            v.mark(end);
3567    
3568            if (!isStatement) {
3569                v.load(savedValue, expectedAsmType);
3570                myFrameMap.leaveTemp(expectedAsmType);
3571            }
3572    
3573            if (finallyBlock != null) {
3574                blockStackElements.pop();
3575            }
3576    
3577            return StackValue.onStack(expectedAsmType);
3578        }
3579    
3580        private void generateExceptionTable(@NotNull Label catchStart, @NotNull List<Label> catchedRegions, @Nullable String exception) {
3581            for (int i = 0; i < catchedRegions.size(); i += 2) {
3582                Label startRegion = catchedRegions.get(i);
3583                Label endRegion = catchedRegions.get(i+1);
3584                v.visitTryCatchBlock(startRegion, endRegion, catchStart, exception);
3585            }
3586        }
3587    
3588        @NotNull
3589        private static List<Label> getCurrentCatchIntervals(
3590                @Nullable FinallyBlockStackElement finallyBlockStackElement,
3591                @NotNull Label blockStart,
3592                @NotNull Label blockEnd
3593        ) {
3594            List<Label> gapsInBlock =
3595                    finallyBlockStackElement != null ? new ArrayList<Label>(finallyBlockStackElement.gaps) : Collections.<Label>emptyList();
3596            assert gapsInBlock.size() % 2 == 0;
3597            List<Label> blockRegions = new ArrayList<Label>(gapsInBlock.size() + 2);
3598            blockRegions.add(blockStart);
3599            blockRegions.addAll(gapsInBlock);
3600            blockRegions.add(blockEnd);
3601            return blockRegions;
3602        }
3603    
3604        @Override
3605        public StackValue visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression, StackValue receiver) {
3606            JetSimpleNameExpression operationSign = expression.getOperationReference();
3607            IElementType opToken = operationSign.getReferencedNameElementType();
3608            if (opToken == JetTokens.COLON) {
3609                return gen(expression.getLeft());
3610            }
3611            else {
3612                JetTypeReference typeReference = expression.getRight();
3613                JetType rightType = bindingContext.get(TYPE, typeReference);
3614                assert rightType != null;
3615                Type rightTypeAsm = boxType(asmType(rightType));
3616                JetExpression left = expression.getLeft();
3617                DeclarationDescriptor descriptor = rightType.getConstructor().getDeclarationDescriptor();
3618                if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) {
3619                    StackValue value = genQualified(receiver, left);
3620                    value.put(boxType(value.type), v);
3621    
3622                    if (opToken != JetTokens.AS_SAFE) {
3623                        if (!TypeUtils.isNullableType(rightType)) {
3624                            v.dup();
3625                            Label nonnull = new Label();
3626                            v.ifnonnull(nonnull);
3627                            JetType leftType = bindingContext.get(EXPRESSION_TYPE, left);
3628                            assert leftType != null;
3629                            throwNewException("kotlin/TypeCastException", DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(leftType) +
3630                                                                         " cannot be cast to " +
3631                                                                         DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(rightType));
3632                            v.mark(nonnull);
3633                        }
3634                    }
3635                    else {
3636                        v.dup();
3637                        v.instanceOf(rightTypeAsm);
3638                        Label ok = new Label();
3639                        v.ifne(ok);
3640                        v.pop();
3641                        v.aconst(null);
3642                        v.mark(ok);
3643                    }
3644    
3645                    v.checkcast(rightTypeAsm);
3646                    return StackValue.onStack(rightTypeAsm);
3647                }
3648                else {
3649                    throw new UnsupportedOperationException("Don't know how to handle non-class types in as/as? : " + descriptor);
3650                }
3651            }
3652        }
3653    
3654        @Override
3655        public StackValue visitIsExpression(@NotNull JetIsExpression expression, StackValue receiver) {
3656            StackValue match = StackValue.expression(OBJECT_TYPE, expression.getLeftHandSide(), this);
3657            return generateIsCheck(match, expression.getTypeRef(), expression.isNegated());
3658        }
3659    
3660        private StackValue generateExpressionMatch(StackValue expressionToMatch, JetExpression patternExpression) {
3661            if (expressionToMatch != null) {
3662                Type subjectType = expressionToMatch.type;
3663                expressionToMatch.put(subjectType, v);
3664                JetType condJetType = bindingContext.get(EXPRESSION_TYPE, patternExpression);
3665                Type condType;
3666                if (isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) {
3667                    assert condJetType != null;
3668                    condType = asmType(condJetType);
3669                    if (!(isNumberPrimitive(condType) || condType.getSort() == Type.BOOLEAN)) {
3670                        subjectType = boxType(subjectType);
3671                        expressionToMatch.coerceTo(subjectType, v);
3672                    }
3673                }
3674                else {
3675                    condType = OBJECT_TYPE;
3676                }
3677                gen(patternExpression, condType);
3678                return genEqualsForExpressionsOnStack(v, JetTokens.EQEQ, subjectType, condType);
3679            }
3680            else {
3681                return gen(patternExpression);
3682            }
3683        }
3684    
3685        private StackValue generateIsCheck(StackValue expressionToMatch, JetTypeReference typeReference, boolean negated) {
3686            JetType jetType = bindingContext.get(TYPE, typeReference);
3687            generateInstanceOf(expressionToMatch, jetType, false);
3688            StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE);
3689            return negated ? StackValue.not(value) : value;
3690        }
3691    
3692        private void generateInstanceOf(StackValue expressionToGen, JetType jetType, boolean leaveExpressionOnStack) {
3693            expressionToGen.put(OBJECT_TYPE, v);
3694            if (leaveExpressionOnStack) {
3695                v.dup();
3696            }
3697            Type type = boxType(asmType(jetType));
3698            if (jetType.isNullable()) {
3699                Label nope = new Label();
3700                Label end = new Label();
3701    
3702                v.dup();
3703                v.ifnull(nope);
3704                v.instanceOf(type);
3705                v.goTo(end);
3706                v.mark(nope);
3707                v.pop();
3708                v.iconst(1);
3709                v.mark(end);
3710            }
3711            else {
3712                v.instanceOf(type);
3713            }
3714        }
3715    
3716        @Override
3717        public StackValue visitWhenExpression(@NotNull JetWhenExpression expression, StackValue receiver) {
3718            return generateWhenExpression(expression, false);
3719        }
3720    
3721        public StackValue generateWhenExpression(JetWhenExpression expression, boolean isStatement) {
3722            JetExpression expr = expression.getSubjectExpression();
3723            Type subjectType = expressionType(expr);
3724    
3725            Type resultType = isStatement ? Type.VOID_TYPE : expressionType(expression);
3726    
3727            SwitchCodegen switchCodegen = SwitchCodegenUtil.buildAppropriateSwitchCodegenIfPossible(expression, isStatement, this);
3728            if (switchCodegen != null) {
3729                switchCodegen.generate();
3730                return StackValue.onStack(resultType);
3731            }
3732    
3733            int subjectLocal = expr != null ? myFrameMap.enterTemp(subjectType) : -1;
3734            if (subjectLocal != -1) {
3735                gen(expr, subjectType);
3736                tempVariables.put(expr, StackValue.local(subjectLocal, subjectType));
3737                v.store(subjectLocal, subjectType);
3738            }
3739    
3740            Label end = new Label();
3741            boolean hasElse = JetPsiUtil.checkWhenExpressionHasSingleElse(expression);
3742    
3743            Label nextCondition = null;
3744            for (JetWhenEntry whenEntry : expression.getEntries()) {
3745                if (nextCondition != null) {
3746                    v.mark(nextCondition);
3747                }
3748                nextCondition = new Label();
3749                FrameMap.Mark mark = myFrameMap.mark();
3750                Label thisEntry = new Label();
3751                if (!whenEntry.isElse()) {
3752                    JetWhenCondition[] conditions = whenEntry.getConditions();
3753                    for (int i = 0; i < conditions.length; i++) {
3754                        StackValue conditionValue = generateWhenCondition(subjectType, subjectLocal, conditions[i]);
3755                        conditionValue.condJump(nextCondition, true, v);
3756                        if (i < conditions.length - 1) {
3757                            v.goTo(thisEntry);
3758                            v.mark(nextCondition);
3759                            nextCondition = new Label();
3760                        }
3761                    }
3762                }
3763    
3764                v.visitLabel(thisEntry);
3765                gen(whenEntry.getExpression(), resultType);
3766                mark.dropTo();
3767                if (!whenEntry.isElse()) {
3768                    v.goTo(end);
3769                }
3770            }
3771            if (!hasElse && nextCondition != null) {
3772                v.mark(nextCondition);
3773                if (!isStatement) {
3774                    putUnitInstanceOntoStackForNonExhaustiveWhen(expression);
3775                }
3776            }
3777    
3778            markLineNumber(expression);
3779            v.mark(end);
3780    
3781            myFrameMap.leaveTemp(subjectType);
3782            tempVariables.remove(expr);
3783            return StackValue.onStack(resultType);
3784        }
3785    
3786        public void putUnitInstanceOntoStackForNonExhaustiveWhen(
3787                @NotNull JetWhenExpression expression
3788        ) {
3789            if (Boolean.TRUE.equals(bindingContext.get(BindingContext.EXHAUSTIVE_WHEN, expression))) {
3790                // when() is supposed to be exhaustive
3791                throwNewException("kotlin/NoWhenBranchMatchedException");
3792            }
3793            else {
3794                // non-exhaustive when() with no else -> Unit must be expected
3795                StackValue.putUnitInstance(v);
3796            }
3797        }
3798    
3799        private StackValue generateWhenCondition(Type subjectType, int subjectLocal, JetWhenCondition condition) {
3800            if (condition instanceof JetWhenConditionInRange) {
3801                JetWhenConditionInRange conditionInRange = (JetWhenConditionInRange) condition;
3802                return generateIn(StackValue.local(subjectLocal, subjectType),
3803                                  conditionInRange.getRangeExpression(),
3804                                  conditionInRange.getOperationReference());
3805            }
3806            StackValue.Local match = subjectLocal == -1 ? null : StackValue.local(subjectLocal, subjectType);
3807            if (condition instanceof JetWhenConditionIsPattern) {
3808                JetWhenConditionIsPattern patternCondition = (JetWhenConditionIsPattern) condition;
3809                return generateIsCheck(match, patternCondition.getTypeRef(), patternCondition.isNegated());
3810            }
3811            else if (condition instanceof JetWhenConditionWithExpression) {
3812                JetExpression patternExpression = ((JetWhenConditionWithExpression) condition).getExpression();
3813                return generateExpressionMatch(match, patternExpression);
3814            }
3815            else {
3816                throw new UnsupportedOperationException("unsupported kind of when condition");
3817            }
3818        }
3819    
3820        private boolean isIntRangeExpr(JetExpression rangeExpression) {
3821            if (rangeExpression instanceof JetBinaryExpression) {
3822                JetBinaryExpression binaryExpression = (JetBinaryExpression) rangeExpression;
3823                if (binaryExpression.getOperationReference().getReferencedNameElementType() == JetTokens.RANGE) {
3824                    JetType jetType = bindingContext.get(EXPRESSION_TYPE, rangeExpression);
3825                    assert jetType != null;
3826                    DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
3827                    return INTEGRAL_RANGES.contains(descriptor);
3828                }
3829            }
3830            return false;
3831        }
3832    
3833        private void throwNewException(@NotNull String className) {
3834            throwNewException(className, null);
3835        }
3836    
3837        private void throwNewException(@NotNull String className, @Nullable String message) {
3838            v.anew(Type.getObjectType(className));
3839            v.dup();
3840            if (message != null) {
3841                v.visitLdcInsn(message);
3842                v.invokespecial(className, "<init>", "(Ljava/lang/String;)V", false);
3843            }
3844            else {
3845                v.invokespecial(className, "<init>", "()V", false);
3846            }
3847            v.athrow();
3848        }
3849    
3850        private Call makeFakeCall(ReceiverValue initializerAsReceiver) {
3851            JetSimpleNameExpression fake = JetPsiFactory(state.getProject()).createSimpleName("fake");
3852            return CallMaker.makeCall(fake, initializerAsReceiver);
3853        }
3854    
3855        @Override
3856        public String toString() {
3857            return context.getContextDescriptor().toString();
3858        }
3859    
3860        @NotNull
3861        public FrameMap getFrameMap() {
3862            return myFrameMap;
3863        }
3864    
3865        @NotNull
3866        public MethodContext getContext() {
3867            return context;
3868        }
3869    
3870        @NotNull
3871        public NameGenerator getInlineNameGenerator() {
3872            NameGenerator nameGenerator = getParentCodegen().getInlineNameGenerator();
3873            Name name = context.getContextDescriptor().getName();
3874            return nameGenerator.subGenerator((name.isSpecial() ? "$special" : name.asString()) + "$$inlined" );
3875        }
3876    
3877        public Type getReturnType() {
3878            return returnType;
3879        }
3880    
3881        public Stack<BlockStackElement> getBlockStackElements() {
3882            return new Stack<BlockStackElement>(blockStackElements);
3883        }
3884    
3885        public void addBlockStackElementsForNonLocalReturns(@NotNull Stack<BlockStackElement> elements) {
3886            blockStackElements.addAll(elements);
3887        }
3888    
3889        private static class NonLocalReturnInfo {
3890    
3891            final Type returnType;
3892    
3893            final String labelName;
3894    
3895            private NonLocalReturnInfo(Type type, String name) {
3896                returnType = type;
3897                labelName = name;
3898            }
3899        }
3900    }