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