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