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