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