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