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