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(@NotNull 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(@NotNull JetObjectDeclaration declaration, StackValue data) {
301            return visitClassOrObject(declaration);
302        }
303    
304        @Override
305        public StackValue visitExpression(@NotNull JetExpression expression, StackValue receiver) {
306            throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented");
307        }
308    
309        @Override
310        public StackValue visitSuperExpression(@NotNull 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(@NotNull JetParenthesizedExpression expression, StackValue receiver) {
343            return genQualified(receiver, expression.getExpression());
344        }
345    
346        @Override
347        public StackValue visitAnnotatedExpression(@NotNull 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(@NotNull 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(@NotNull 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(@NotNull 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(@NotNull 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(@NotNull JetBreakExpression expression, StackValue receiver) {
1146            return visitBreakOrContinueExpression(expression, receiver, true);
1147        }
1148    
1149        @Override
1150        public StackValue visitContinueExpression(@NotNull 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(@NotNull 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(@NotNull 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(@NotNull 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(@NotNull 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(@NotNull 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(@NotNull 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(@NotNull 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(@NotNull 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            assert descriptor != null : "Couldn't find descriptor for '" + expression.getText() + "'";
1628            descriptor = descriptor.getOriginal();
1629    
1630            if (descriptor instanceof CallableMemberDescriptor) {
1631                CallableMemberDescriptor memberDescriptor = (CallableMemberDescriptor) descriptor;
1632                memberDescriptor = unwrapFakeOverride(memberDescriptor);
1633    
1634                IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(memberDescriptor);
1635                if (intrinsic != null) {
1636                    Type expectedType = expressionType(expression);
1637                    return intrinsic.generate(this, v, expectedType, expression, Collections.<JetExpression>emptyList(), receiver, state);
1638                }
1639            }
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(@NotNull 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.getResultingDescriptor().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 instanceof ExpressionAsFunctionDescriptor) {
2099                JetExpression deparenthesize = JetPsiUtil.deparenthesize(((ExpressionAsFunctionDescriptor) fd).getExpression());
2100                return !(deparenthesize instanceof JetCallableReferenceExpression || deparenthesize instanceof JetFunctionLiteralExpression);
2101            }
2102            return false;
2103        }
2104    
2105    
2106        public void invokeMethodWithArguments(
2107                @NotNull CallableMethod callableMethod,
2108                @NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
2109                @Nullable Call callToGenerateCallee,
2110                @NotNull StackValue receiver
2111        ) {
2112            Type calleeType = callableMethod.getGenerateCalleeType();
2113            if (calleeType != null) {
2114                assert !callableMethod.isNeedsThis();
2115                assert callToGenerateCallee != null : "Call can't be null when generating callee: " + resolvedCall.getResultingDescriptor();
2116                gen(callToGenerateCallee.getCalleeExpression(), calleeType);
2117            }
2118    
2119            if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
2120                resolvedCall = ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall();
2121            }
2122    
2123            if (!(resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor)) { // otherwise already
2124                receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
2125                receiver.put(receiver.type, v);
2126            }
2127    
2128            pushArgumentsAndInvoke(resolvedCall, callableMethod);
2129        }
2130    
2131        private void pushArgumentsAndInvoke(@NotNull ResolvedCall<?> resolvedCall, @NotNull CallableMethod callable) {
2132            int mask = pushMethodArguments(resolvedCall, callable.getValueParameterTypes());
2133            if (mask == 0) {
2134                callable.invokeWithNotNullAssertion(v, state, resolvedCall);
2135            }
2136            else {
2137                callable.invokeDefaultWithNotNullAssertion(v, state, resolvedCall, mask);
2138            }
2139        }
2140    
2141        private void genThisAndReceiverFromResolvedCall(
2142                StackValue receiver,
2143                ResolvedCall<? extends CallableDescriptor> resolvedCall,
2144                CallableMethod callableMethod
2145        ) {
2146            receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
2147            receiver.put(receiver.type, v);
2148        }
2149    
2150        public void generateFromResolvedCall(@NotNull ReceiverValue descriptor, @NotNull Type type) {
2151            if (descriptor instanceof ClassReceiver) {
2152                Type exprType = asmType(descriptor.getType());
2153                ClassReceiver classReceiver = (ClassReceiver) descriptor;
2154                ClassDescriptor classReceiverDeclarationDescriptor = classReceiver.getDeclarationDescriptor();
2155                if (DescriptorUtils.isClassObject(classReceiverDeclarationDescriptor)) {
2156                    if (context.getContextDescriptor() instanceof FunctionDescriptor &&
2157                        classReceiverDeclarationDescriptor == context.getContextDescriptor().getContainingDeclaration()) {
2158                        v.load(0, OBJECT_TYPE);
2159                    }
2160                    else {
2161                        FieldInfo info = FieldInfo.createForSingleton(classReceiverDeclarationDescriptor, typeMapper);
2162                        v.getstatic(info.getOwnerInternalName(), info.getFieldName(), info.getFieldType().getDescriptor());
2163                    }
2164                    StackValue.onStack(exprType).put(type, v);
2165                }
2166                else {
2167                    StackValue.thisOrOuter(this, classReceiverDeclarationDescriptor, false).put(type, v);
2168                }
2169            }
2170            else if (descriptor instanceof ScriptReceiver) {
2171                generateScript((ScriptReceiver) descriptor);
2172            }
2173            else if (descriptor instanceof ExtensionReceiver) {
2174                ExtensionReceiver extensionReceiver = (ExtensionReceiver) descriptor;
2175                generateReceiver(extensionReceiver.getDeclarationDescriptor()).put(type, v);
2176            }
2177            else if (descriptor instanceof ExpressionReceiver) {
2178                ExpressionReceiver expressionReceiver = (ExpressionReceiver) descriptor;
2179                JetExpression expr = expressionReceiver.getExpression();
2180                gen(expr, type);
2181            }
2182            else if (descriptor instanceof AutoCastReceiver) {
2183                AutoCastReceiver autoCastReceiver = (AutoCastReceiver) descriptor;
2184                Type originalType = asmType(autoCastReceiver.getOriginal().getType());
2185                generateFromResolvedCall(autoCastReceiver.getOriginal(), originalType);
2186                StackValue.onStack(originalType).put(type, v);
2187            }
2188            else {
2189                throw new UnsupportedOperationException("Unsupported receiver type: " + descriptor);
2190            }
2191        }
2192    
2193        @Nullable
2194        private static JetExpression getReceiverForSelector(PsiElement expression) {
2195            if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) {
2196                JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
2197                return parent.getReceiverExpression();
2198            }
2199            return null;
2200        }
2201    
2202        private StackValue generateReceiver(DeclarationDescriptor provided) {
2203            if (context.getCallableDescriptorWithReceiver() == provided) {
2204                StackValue result = context.getReceiverExpression(typeMapper);
2205                return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null);
2206            }
2207    
2208            StackValue result = context.lookupInContext(provided, StackValue.local(0, OBJECT_TYPE), state, false);
2209            return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null);
2210        }
2211    
2212        private void generateScript(@NotNull ScriptReceiver receiver) {
2213            CodegenContext cur = context;
2214            StackValue result = StackValue.local(0, OBJECT_TYPE);
2215            while (cur != null) {
2216                if (cur instanceof MethodContext && !(cur instanceof ConstructorContext)) {
2217                    cur = cur.getParentContext();
2218                }
2219    
2220                if (cur instanceof ScriptContext) {
2221                    ScriptContext scriptContext = (ScriptContext) cur;
2222    
2223                    JvmClassName currentScriptClassName =
2224                            classNameForScriptDescriptor(bindingContext,
2225                                                                        scriptContext.getScriptDescriptor());
2226                    if (scriptContext.getScriptDescriptor() == receiver.getDeclarationDescriptor()) {
2227                        result.put(currentScriptClassName.getAsmType(), v);
2228                    }
2229                    else {
2230                        JvmClassName className =
2231                                classNameForScriptDescriptor(bindingContext,
2232                                                                            receiver.getDeclarationDescriptor());
2233                        String fieldName = state.getScriptCodegen().getScriptFieldName(receiver.getDeclarationDescriptor());
2234                        result.put(currentScriptClassName.getAsmType(), v);
2235                        StackValue.field(className.getAsmType(), currentScriptClassName, fieldName, false).put(className.getAsmType(), v);
2236                    }
2237                    return;
2238                }
2239    
2240                assert cur != null;
2241                result = cur.getOuterExpression(result, false);
2242    
2243                if (cur instanceof ConstructorContext) {
2244                    cur = cur.getParentContext();
2245                }
2246                assert cur != null;
2247                cur = cur.getParentContext();
2248            }
2249    
2250            throw new UnsupportedOperationException();
2251        }
2252    
2253        public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) {
2254            boolean isSingleton = CodegenBinding.isSingleton(bindingContext, calleeContainingClass);
2255            if (isSingleton) {
2256                assert !isSuper;
2257    
2258                if (context.hasThisDescriptor() && context.getThisDescriptor().equals(calleeContainingClass)) {
2259                    return StackValue.local(0, typeMapper.mapType(calleeContainingClass));
2260                }
2261                else {
2262                    return StackValue.singleton(calleeContainingClass, typeMapper);
2263                }
2264            }
2265    
2266            CodegenContext cur = context;
2267            Type type = asmType(calleeContainingClass.getDefaultType());
2268            StackValue result = StackValue.local(0, type);
2269            while (cur != null) {
2270                if (cur instanceof MethodContext && !(cur instanceof ConstructorContext)) {
2271                    cur = cur.getParentContext();
2272                }
2273    
2274                assert cur != null;
2275                ClassDescriptor thisDescriptor = cur.getThisDescriptor();
2276                if (!isSuper && thisDescriptor.equals(calleeContainingClass)
2277                || isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) {
2278                    return castToRequiredTypeOfInterfaceIfNeeded(result, thisDescriptor, calleeContainingClass);
2279                }
2280    
2281                result = cur.getOuterExpression(result, false);
2282    
2283                if (cur instanceof ConstructorContext) {
2284                    cur = cur.getParentContext();
2285                }
2286                assert cur != null;
2287                cur = cur.getParentContext();
2288            }
2289    
2290            throw new UnsupportedOperationException();
2291        }
2292    
2293        private static boolean isReceiver(PsiElement expression) {
2294            PsiElement parent = expression.getParent();
2295            if (parent instanceof JetQualifiedExpression) {
2296                JetExpression receiverExpression = ((JetQualifiedExpression) parent).getReceiverExpression();
2297                return expression == receiverExpression;
2298            }
2299            return false;
2300        }
2301    
2302        private int pushMethodArguments(@NotNull ResolvedCall resolvedCall, List<Type> valueParameterTypes) {
2303            @SuppressWarnings("unchecked")
2304            List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
2305            CallableDescriptor fd = resolvedCall.getResultingDescriptor();
2306    
2307            if (fd.getValueParameters().size() != valueArguments.size()) {
2308                throw new IllegalStateException();
2309            }
2310    
2311            int mask = 0;
2312    
2313            for (ValueParameterDescriptor valueParameter : fd.getValueParameters()) {
2314                ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex());
2315                Type parameterType = valueParameterTypes.get(valueParameter.getIndex());
2316                if (resolvedValueArgument instanceof ExpressionValueArgument) {
2317                    ValueArgument valueArgument = ((ExpressionValueArgument) resolvedValueArgument).getValueArgument();
2318                    assert valueArgument != null;
2319                    JetExpression argumentExpression = valueArgument.getArgumentExpression();
2320                    assert argumentExpression != null : valueArgument.asElement().getText();
2321    
2322                    gen(argumentExpression, parameterType);
2323                }
2324                else if (resolvedValueArgument instanceof DefaultValueArgument) {
2325                    pushDefaultValueOnStack(parameterType, v);
2326                    mask |= (1 << valueParameter.getIndex());
2327                }
2328                else if (resolvedValueArgument instanceof VarargValueArgument) {
2329                    VarargValueArgument valueArgument = (VarargValueArgument) resolvedValueArgument;
2330                    genVarargs(valueParameter, valueArgument);
2331                }
2332                else {
2333                    throw new UnsupportedOperationException();
2334                }
2335            }
2336            return mask;
2337        }
2338    
2339        public void genVarargs(ValueParameterDescriptor valueParameterDescriptor, VarargValueArgument valueArgument) {
2340            JetType outType = valueParameterDescriptor.getType();
2341    
2342            Type type = asmType(outType);
2343            assert type.getSort() == Type.ARRAY;
2344            Type elementType = correctElementType(type);
2345            List<ValueArgument> arguments = valueArgument.getArguments();
2346            int size = arguments.size();
2347    
2348            boolean hasSpread = false;
2349            for (int i = 0; i != size; ++i) {
2350                if (arguments.get(i).getSpreadElement() != null) {
2351                    hasSpread = true;
2352                    break;
2353                }
2354            }
2355    
2356            if (hasSpread) {
2357                if (size == 1) {
2358                    gen(arguments.get(0).getArgumentExpression(), type);
2359                }
2360                else {
2361                    String owner = "jet/runtime/Intrinsics$SpreadBuilder";
2362                    v.anew(Type.getObjectType(owner));
2363                    v.dup();
2364                    v.invokespecial(owner, "<init>", "()V");
2365                    for (int i = 0; i != size; ++i) {
2366                        v.dup();
2367                        ValueArgument argument = arguments.get(i);
2368                        if (argument.getSpreadElement() != null) {
2369                            gen(argument.getArgumentExpression(), OBJECT_TYPE);
2370                            v.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V");
2371                        }
2372                        else {
2373                            gen(argument.getArgumentExpression(), elementType);
2374                            v.invokevirtual(owner, "add", "(Ljava/lang/Object;)Z");
2375                            v.pop();
2376                        }
2377                    }
2378                    v.dup();
2379                    v.invokevirtual(owner, "size", "()I");
2380                    v.newarray(elementType);
2381                    v.invokevirtual(owner, "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;");
2382                    v.checkcast(type);
2383                }
2384            }
2385            else {
2386                v.iconst(arguments.size());
2387                v.newarray(elementType);
2388                for (int i = 0; i != size; ++i) {
2389                    v.dup();
2390                    v.iconst(i);
2391                    gen(arguments.get(i).getArgumentExpression(), elementType);
2392                    StackValue.arrayElement(elementType, false).store(elementType, v);
2393                }
2394            }
2395        }
2396    
2397        public int pushMethodArguments(JetCallElement expression, List<Type> valueParameterTypes) {
2398            ResolvedCall<? extends CallableDescriptor> resolvedCall =
2399                    bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
2400            if (resolvedCall != null) {
2401                return pushMethodArguments(resolvedCall, valueParameterTypes);
2402            }
2403            else {
2404                List<? extends ValueArgument> args = expression.getValueArguments();
2405                for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
2406                    ValueArgument arg = args.get(i);
2407                    gen(arg.getArgumentExpression(), valueParameterTypes.get(i));
2408                }
2409                return 0;
2410            }
2411        }
2412    
2413        @NotNull
2414        public Type expressionType(JetExpression expr) {
2415            return typeMapper.expressionType(expr);
2416        }
2417    
2418        public int indexOfLocal(JetReferenceExpression lhs) {
2419            DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, lhs);
2420            if (isVarCapturedInClosure(bindingContext, declarationDescriptor)) {
2421                return -1;
2422            }
2423            return lookupLocalIndex(declarationDescriptor);
2424        }
2425    
2426        @Override
2427        public StackValue visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, StackValue data) {
2428            // TODO: properties
2429            final FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
2430            assert functionDescriptor != null : "Callable reference is not resolved to descriptor: " + expression.getText();
2431    
2432            final ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(RESOLVED_CALL, expression.getCallableReference());
2433            assert resolvedCall != null : "Callable reference is not resolved: " + functionDescriptor + " " + expression.getText();
2434    
2435            JetType kFunctionType = bindingContext.get(EXPRESSION_TYPE, expression);
2436            assert kFunctionType != null : "Callable reference is not type checked: " + expression.getText();
2437            ClassDescriptor kFunctionImpl = functionTypeToImpl(kFunctionType);
2438            assert kFunctionImpl != null : "Impl type is not found for the function type: " + kFunctionType;
2439    
2440            JvmClassName closureSuperClass = JvmClassName.byType(typeMapper.mapType(kFunctionImpl));
2441    
2442            ClosureCodegen closureCodegen = new ClosureCodegen(state, expression, functionDescriptor, null, closureSuperClass, context, this,
2443                    new FunctionGenerationStrategy.CodegenBased<CallableDescriptor>(state, functionDescriptor) {
2444    
2445                        @NotNull
2446                        @Override
2447                        public ExpressionCodegen initializeExpressionCodegen(
2448                                JvmMethodSignature signature, MethodContext context, MethodVisitor mv,
2449                                Type returnType
2450                        ) {
2451                            FunctionDescriptor referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
2452                            JetType returnJetType = referencedFunction.getReturnType();
2453                            assert returnJetType != null : "Return type can't be null: " + referencedFunction;
2454    
2455                            return super.initializeExpressionCodegen(signature, context,
2456                                                              mv, typeMapper.mapReturnType(returnJetType));
2457                        }
2458    
2459                        @Override
2460                        public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
2461                            /*
2462                             Here we need to put the arguments from our locals to the stack and invoke the referenced method. Since invocation
2463                             of methods is highly dependent on expressions, we create a fake call expression. Then we create a new instance of
2464                             ExpressionCodegen and, in order for it to generate code correctly, we save to its 'tempVariables' field every
2465                             argument of our fake expression, pointing it to the corresponding index in our locals. This way generation of
2466                             every argument boils down to calling LOAD with the corresponding index
2467                             */
2468    
2469                            FunctionDescriptor referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
2470    
2471                            JetCallExpression fakeExpression = constructFakeFunctionCall(referencedFunction);
2472                            final List<? extends ValueArgument> fakeArguments = fakeExpression.getValueArguments();
2473    
2474                            final ReceiverValue receiverValue = computeAndSaveReceiver(signature, codegen);
2475                            computeAndSaveArguments(codegen.myFrameMap, fakeArguments, codegen);
2476    
2477                            ResolvedCall<CallableDescriptor> fakeResolvedCall = new DelegatingResolvedCall<CallableDescriptor>(resolvedCall) {
2478                                @NotNull
2479                                @Override
2480                                public ReceiverValue getReceiverArgument() {
2481                                    return resolvedCall.getExplicitReceiverKind() == RECEIVER_ARGUMENT ? receiverValue : NO_RECEIVER;
2482                                }
2483    
2484                                @NotNull
2485                                @Override
2486                                public ReceiverValue getThisObject() {
2487                                    return resolvedCall.getExplicitReceiverKind() == THIS_OBJECT ? receiverValue : NO_RECEIVER;
2488                                }
2489    
2490                                @NotNull
2491                                @Override
2492                                public List<ResolvedValueArgument> getValueArgumentsByIndex() {
2493                                    List<ResolvedValueArgument> result = new ArrayList<ResolvedValueArgument>(fakeArguments.size());
2494                                    for (ValueArgument argument : fakeArguments) {
2495                                        result.add(new ExpressionValueArgument(argument));
2496                                    }
2497                                    return result;
2498                                }
2499                            };
2500    
2501                            StackValue result;
2502                            Type returnType = codegen.returnType;
2503                            if (referencedFunction instanceof ConstructorDescriptor) {
2504                                if (returnType.getSort() == Type.ARRAY) {
2505                                    JetType returnJetType = referencedFunction.getReturnType();
2506                                    assert returnJetType != null;
2507                                    codegen.generateNewArray(fakeExpression, returnJetType);
2508                                    result = StackValue.onStack(returnType);
2509                                }
2510                                else {
2511                                    result = codegen.generateConstructorCall(fakeResolvedCall, StackValue.none(), returnType);
2512                                }
2513                            }
2514                            else {
2515                                Call call = CallMaker.makeCall(fakeExpression, NO_RECEIVER, null, fakeExpression, fakeArguments);
2516                                result = codegen.invokeFunction(call, StackValue.none(), fakeResolvedCall);
2517                            }
2518    
2519                            InstructionAdapter v = codegen.v;
2520                            result.put(returnType, v);
2521                            v.areturn(returnType);
2522                        }
2523    
2524                        @NotNull
2525                        private JetCallExpression constructFakeFunctionCall(@NotNull CallableDescriptor referencedFunction) {
2526                            StringBuilder fakeFunctionCall = new StringBuilder("callableReferenceFakeCall(");
2527                            for (Iterator<ValueParameterDescriptor> iterator = referencedFunction.getValueParameters().iterator();
2528                                 iterator.hasNext(); ) {
2529                                ValueParameterDescriptor descriptor = iterator.next();
2530                                fakeFunctionCall.append("p").append(descriptor.getIndex());
2531                                if (iterator.hasNext()) {
2532                                    fakeFunctionCall.append(", ");
2533                                }
2534                            }
2535                            fakeFunctionCall.append(")");
2536                            return (JetCallExpression) JetPsiFactory.createExpression(state.getProject(), fakeFunctionCall.toString());
2537                        }
2538    
2539                        private void computeAndSaveArguments(
2540                                @NotNull FrameMap frameMap,
2541                                @NotNull List<? extends ValueArgument> fakeArguments,
2542                                @NotNull ExpressionCodegen codegen
2543                        ) {
2544                            for (ValueParameterDescriptor parameter : functionDescriptor.getValueParameters()) {
2545                                ValueArgument fakeArgument = fakeArguments.get(parameter.getIndex());
2546                                Type type = typeMapper.mapType(parameter);
2547                                int localIndex = frameMap.getIndex(parameter);
2548                                codegen.tempVariables.put(fakeArgument.getArgumentExpression(), StackValue.local(localIndex, type));
2549                            }
2550                        }
2551    
2552                        @NotNull
2553                        private ReceiverValue computeAndSaveReceiver(
2554                                @NotNull JvmMethodSignature signature,
2555                                @NotNull ExpressionCodegen codegen
2556                        ) {
2557                            CallableDescriptor referencedFunction = resolvedCall.getCandidateDescriptor();
2558    
2559                            ReceiverParameterDescriptor receiverParameter = referencedFunction.getReceiverParameter();
2560                            ReceiverParameterDescriptor expectedThisObject = referencedFunction.getExpectedThisObject();
2561                            assert receiverParameter == null || expectedThisObject == null :
2562                                    "Extensions in classes can't be referenced via callable reference expressions: " + referencedFunction;
2563    
2564                            ReceiverParameterDescriptor receiver = receiverParameter != null ? receiverParameter : expectedThisObject;
2565    
2566                            if (receiver == null) {
2567                                return NO_RECEIVER;
2568                            }
2569    
2570                            JetExpression receiverExpression = JetPsiFactory.createExpression(state.getProject(),
2571                                                                                              "callableReferenceFakeReceiver");
2572    
2573                            Type firstParameterType = signature.getAsmMethod().getArgumentTypes()[0];
2574                            // 0 is this (the closure class), 1 is the method's first parameter
2575                            codegen.tempVariables.put(receiverExpression, StackValue.local(1, firstParameterType));
2576    
2577                            return new ExpressionReceiver(receiverExpression, receiver.getType());
2578                        }
2579                    }
2580            );
2581    
2582            closureCodegen.gen();
2583    
2584            return closureCodegen.putInstanceOnStack(v, this);
2585        }
2586    
2587        @Override
2588        public StackValue visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, StackValue receiver) {
2589            StackValue receiverValue = StackValue.none();
2590            return genQualified(receiverValue, expression.getSelectorExpression());
2591        }
2592    
2593        @Override
2594        public StackValue visitSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression, StackValue receiver) {
2595            JetExpression expr = expression.getReceiverExpression();
2596            Type receiverType = expressionType(expr);
2597            gen(expr, receiverType);
2598            if (isPrimitive(receiverType)) {
2599                StackValue propValue = genQualified(StackValue.onStack(receiverType), expression.getSelectorExpression());
2600                Type type = boxType(propValue.type);
2601                propValue.put(type, v);
2602    
2603                return StackValue.onStack(type);
2604            }
2605            else {
2606                Label ifnull = new Label();
2607                Label end = new Label();
2608                v.dup();
2609                v.ifnull(ifnull);
2610                StackValue propValue = genQualified(StackValue.onStack(receiverType), expression.getSelectorExpression());
2611                Type type = boxType(propValue.type);
2612                propValue.put(type, v);
2613                v.goTo(end);
2614    
2615                v.mark(ifnull);
2616                v.pop();
2617                if (!type.equals(Type.VOID_TYPE)) {
2618                    v.aconst(null);
2619                }
2620                v.mark(end);
2621    
2622                return StackValue.onStack(type);
2623            }
2624        }
2625    
2626        @Override
2627        public StackValue visitBinaryExpression(@NotNull JetBinaryExpression expression, StackValue receiver) {
2628            IElementType opToken = expression.getOperationReference().getReferencedNameElementType();
2629            if (opToken == JetTokens.EQ) {
2630                return generateAssignmentExpression(expression);
2631            }
2632            else if (JetTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) {
2633                return generateAugmentedAssignment(expression);
2634            }
2635            else if (opToken == JetTokens.ANDAND) {
2636                return generateBooleanAnd(expression);
2637            }
2638            else if (opToken == JetTokens.OROR) {
2639                return generateBooleanOr(expression);
2640            }
2641            else if (opToken == JetTokens.EQEQ || opToken == JetTokens.EXCLEQ ||
2642                     opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
2643                return generateEquals(expression.getLeft(), expression.getRight(), opToken);
2644            }
2645            else if (opToken == JetTokens.LT || opToken == JetTokens.LTEQ ||
2646                     opToken == JetTokens.GT || opToken == JetTokens.GTEQ) {
2647                return generateComparison(expression);
2648            }
2649            else if (opToken == JetTokens.ELVIS) {
2650                return generateElvis(expression);
2651            }
2652            else if (opToken == JetTokens.IN_KEYWORD || opToken == JetTokens.NOT_IN) {
2653                return generateIn(expression);
2654            }
2655            else {
2656                DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
2657                assert op instanceof FunctionDescriptor : String.valueOf(op);
2658                Callable callable = resolveToCallable((FunctionDescriptor) op, false);
2659                if (callable instanceof IntrinsicMethod) {
2660                    IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
2661                    return intrinsic.generate(this, v, expressionType(expression), expression,
2662                                              Arrays.asList(expression.getLeft(), expression.getRight()), receiver, state);
2663                }
2664                else {
2665                    return invokeOperation(expression, (FunctionDescriptor) op, (CallableMethod) callable);
2666                }
2667            }
2668        }
2669    
2670        private StackValue generateIn(JetBinaryExpression expression) {
2671            boolean inverted = expression.getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IN;
2672            if (isIntRangeExpr(expression.getRight())) {
2673                StackValue leftValue = StackValue.expression(Type.INT_TYPE, expression.getLeft(), this);
2674                JetBinaryExpression rangeExpression = (JetBinaryExpression) expression.getRight();
2675                getInIntRange(leftValue, rangeExpression, inverted);
2676            }
2677            else {
2678                invokeFunctionByReference(expression.getOperationReference());
2679                if (inverted) {
2680                    genInvertBoolean(v);
2681                }
2682            }
2683            return StackValue.onStack(Type.BOOLEAN_TYPE);
2684        }
2685    
2686        private void getInIntRange(StackValue leftValue, JetBinaryExpression rangeExpression, boolean inverted) {
2687            v.iconst(1);
2688            // 1
2689            leftValue.put(Type.INT_TYPE, v);
2690            // 1 l
2691            v.dup2();
2692            // 1 l 1 l
2693    
2694            //noinspection ConstantConditions
2695            gen(rangeExpression.getLeft(), Type.INT_TYPE);
2696            // 1 l 1 l r
2697            Label lok = new Label();
2698            v.ificmpge(lok);
2699            // 1 l 1
2700            v.pop();
2701            v.iconst(0);
2702            v.mark(lok);
2703            // 1 l c
2704            v.dupX2();
2705            // c 1 l c
2706            v.pop();
2707            // c 1 l
2708    
2709            gen(rangeExpression.getRight(), Type.INT_TYPE);
2710            // c 1 l r
2711            Label rok = new Label();
2712            v.ificmple(rok);
2713            // c 1
2714            v.pop();
2715            v.iconst(0);
2716            v.mark(rok);
2717            // c c
2718    
2719            v.and(Type.INT_TYPE);
2720            if (inverted) {
2721                genInvertBoolean(v);
2722            }
2723        }
2724    
2725        private StackValue generateBooleanAnd(JetBinaryExpression expression) {
2726            gen(expression.getLeft(), Type.BOOLEAN_TYPE);
2727            Label ifFalse = new Label();
2728            v.ifeq(ifFalse);
2729            gen(expression.getRight(), Type.BOOLEAN_TYPE);
2730            Label end = new Label();
2731            v.goTo(end);
2732            v.mark(ifFalse);
2733            v.iconst(0);
2734            v.mark(end);
2735            return StackValue.onStack(Type.BOOLEAN_TYPE);
2736        }
2737    
2738        private StackValue generateBooleanOr(JetBinaryExpression expression) {
2739            gen(expression.getLeft(), Type.BOOLEAN_TYPE);
2740            Label ifTrue = new Label();
2741            v.ifne(ifTrue);
2742            gen(expression.getRight(), Type.BOOLEAN_TYPE);
2743            Label end = new Label();
2744            v.goTo(end);
2745            v.mark(ifTrue);
2746            v.iconst(1);
2747            v.mark(end);
2748            return StackValue.onStack(Type.BOOLEAN_TYPE);
2749        }
2750    
2751        private StackValue generateEquals(JetExpression left, JetExpression right, IElementType opToken) {
2752            Type leftType = expressionType(left);
2753            Type rightType = expressionType(right);
2754    
2755            if (JetPsiUtil.isNullConstant(left)) {
2756                return genCmpWithNull(right, rightType, opToken);
2757            }
2758    
2759            if (JetPsiUtil.isNullConstant(right)) {
2760                return genCmpWithNull(left, leftType, opToken);
2761            }
2762    
2763            if (isIntZero(left, leftType) && isIntPrimitive(rightType)) {
2764                return genCmpWithZero(right, rightType, opToken);
2765            }
2766    
2767            if (isIntZero(right, rightType) && isIntPrimitive(leftType)) {
2768                return genCmpWithZero(left, leftType, opToken);
2769            }
2770    
2771            if (isPrimitive(leftType) != isPrimitive(rightType)) {
2772                leftType = boxType(leftType);
2773                gen(left, leftType);
2774                rightType = boxType(rightType);
2775                gen(right, rightType);
2776            }
2777            else {
2778                gen(left, leftType);
2779                gen(right, rightType);
2780            }
2781    
2782            return genEqualsForExpressionsOnStack(v, opToken, leftType, rightType);
2783        }
2784    
2785        private boolean isIntZero(JetExpression expr, Type exprType) {
2786            CompileTimeConstant<?> exprValue = bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expr);
2787            return isIntPrimitive(exprType) && exprValue != null && exprValue.getValue().equals(0);
2788        }
2789    
2790        private StackValue genCmpWithZero(JetExpression exp, Type expType, IElementType opToken) {
2791            v.iconst(1);
2792            gen(exp, expType);
2793            Label ok = new Label();
2794            if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) {
2795                v.ifeq(ok);
2796            }
2797            else {
2798                v.ifne(ok);
2799            }
2800            v.pop();
2801            v.iconst(0);
2802            v.mark(ok);
2803            return StackValue.onStack(Type.BOOLEAN_TYPE);
2804        }
2805    
2806        private StackValue genCmpWithNull(JetExpression exp, Type expType, IElementType opToken) {
2807            v.iconst(1);
2808            gen(exp, boxType(expType));
2809            Label ok = new Label();
2810            if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) {
2811                v.ifnull(ok);
2812            }
2813            else {
2814                v.ifnonnull(ok);
2815            }
2816            v.pop();
2817            v.iconst(0);
2818            v.mark(ok);
2819            return StackValue.onStack(Type.BOOLEAN_TYPE);
2820        }
2821    
2822        private StackValue generateElvis(JetBinaryExpression expression) {
2823            Type exprType = expressionType(expression);
2824            Type leftType = expressionType(expression.getLeft());
2825    
2826            gen(expression.getLeft(), leftType);
2827    
2828            if (isPrimitive(leftType)) {
2829                return StackValue.onStack(leftType);
2830            }
2831    
2832            v.dup();
2833            Label ifNull = new Label();
2834            v.ifnull(ifNull);
2835            StackValue.onStack(leftType).put(exprType, v);
2836            Label end = new Label();
2837            v.goTo(end);
2838            v.mark(ifNull);
2839            v.pop();
2840            gen(expression.getRight(), exprType);
2841            v.mark(end);
2842    
2843            return StackValue.onStack(exprType);
2844        }
2845    
2846        private StackValue generateComparison(JetBinaryExpression expression) {
2847            DeclarationDescriptor target = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
2848            assert target instanceof FunctionDescriptor : "compareTo target should be a function: " + target;
2849            FunctionDescriptor descriptor = (FunctionDescriptor) target;
2850    
2851            JetExpression left = expression.getLeft();
2852            JetExpression right = expression.getRight();
2853            Callable callable = resolveToCallable(descriptor, false);
2854    
2855            Type type;
2856            if (callable instanceof IntrinsicMethod) {
2857                // Compare two primitive values
2858                type = comparisonOperandType(expressionType(left), expressionType(right));
2859                StackValue receiver = gen(left);
2860                receiver.put(type, v);
2861                gen(right, type);
2862            }
2863            else {
2864                type = Type.INT_TYPE;
2865                StackValue result = invokeOperation(expression, descriptor, (CallableMethod) callable);
2866                result.put(type, v);
2867                v.iconst(0);
2868            }
2869            return StackValue.cmp(expression.getOperationToken(), type);
2870        }
2871    
2872        private StackValue generateAssignmentExpression(JetBinaryExpression expression) {
2873            StackValue stackValue = gen(expression.getLeft());
2874            JetExpression right = expression.getRight();
2875            assert right != null : expression.getText();
2876            gen(right, stackValue.type);
2877            stackValue.store(stackValue.type, v);
2878            return StackValue.none();
2879        }
2880    
2881        private StackValue generateAugmentedAssignment(JetBinaryExpression expression) {
2882            DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
2883            assert op instanceof FunctionDescriptor : String.valueOf(op);
2884            Callable callable = resolveToCallable((FunctionDescriptor) op, false);
2885            JetExpression lhs = expression.getLeft();
2886    
2887            //        if (lhs instanceof JetArrayAccessExpression) {
2888            //            JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) lhs;
2889            //            if (arrayAccessExpression.getIndexExpressions().size() != 1) {
2890            //                throw new UnsupportedOperationException("Augmented assignment with multi-index");
2891            //            }
2892            //        }
2893    
2894            Type lhsType = expressionType(lhs);
2895            //noinspection ConstantConditions
2896            if (bindingContext.get(BindingContext.VARIABLE_REASSIGNMENT, expression)) {
2897                if (callable instanceof IntrinsicMethod) {
2898                    StackValue value = gen(lhs);              // receiver
2899                    value.dupReceiver(v);                                        // receiver receiver
2900                    value.put(lhsType, v);                                          // receiver lhs
2901                    IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
2902                    //noinspection NullableProblems
2903                    JetExpression right = expression.getRight();
2904                    assert right != null;
2905                    StackValue stackValue = intrinsic.generate(this, v, lhsType, expression,
2906                                                               Arrays.asList(right),
2907                                                               StackValue.onStack(lhsType), state);
2908                    value.store(stackValue.type, v);
2909                }
2910                else {
2911                    callAugAssignMethod(expression, (CallableMethod) callable, lhsType, true);
2912                }
2913            }
2914            else {
2915                JetType type = ((FunctionDescriptor) op).getReturnType();
2916                assert type != null;
2917                boolean keepReturnValue = !type.equals(KotlinBuiltIns.getInstance().getUnitType());
2918                callAugAssignMethod(expression, (CallableMethod) callable, lhsType, keepReturnValue);
2919            }
2920    
2921            return StackValue.none();
2922        }
2923    
2924        private void callAugAssignMethod(JetBinaryExpression expression, CallableMethod callable, Type lhsType, boolean keepReturnValue) {
2925            ResolvedCall<? extends CallableDescriptor> resolvedCall =
2926                    bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
2927            assert resolvedCall != null;
2928    
2929            StackValue value = gen(expression.getLeft());
2930            if (keepReturnValue) {
2931                value.dupReceiver(v);
2932            }
2933            value.put(lhsType, v);
2934            StackValue receiver = StackValue.onStack(lhsType);
2935    
2936            if (!(resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor)) { // otherwise already
2937                receiver = StackValue.receiver(resolvedCall, receiver, this, callable);
2938                receiver.put(receiver.type, v);
2939            }
2940    
2941            pushArgumentsAndInvoke(resolvedCall, callable);
2942    
2943            if (keepReturnValue) {
2944                value.store(callable.getReturnType(), v);
2945            }
2946        }
2947    
2948        public void invokeAppend(JetExpression expr) {
2949            if (expr instanceof JetBinaryExpression) {
2950                JetBinaryExpression binaryExpression = (JetBinaryExpression) expr;
2951                if (binaryExpression.getOperationToken() == JetTokens.PLUS) {
2952                    JetExpression left = binaryExpression.getLeft();
2953                    JetExpression right = binaryExpression.getRight();
2954                    Type leftType = expressionType(left);
2955                    Type rightType = expressionType(right);
2956    
2957                    if (leftType.equals(JAVA_STRING_TYPE) && rightType.equals(JAVA_STRING_TYPE)) {
2958                        invokeAppend(left);
2959                        invokeAppend(right);
2960                        return;
2961                    }
2962                }
2963            }
2964            Type exprType = expressionType(expr);
2965            gen(expr, exprType);
2966            genInvokeAppendMethod(v, exprType.getSort() == Type.ARRAY ? OBJECT_TYPE : exprType);
2967        }
2968    
2969        @Nullable
2970        private static JetSimpleNameExpression targetLabel(JetExpression expression) {
2971            if (expression.getParent() instanceof JetPrefixExpression) {
2972                JetPrefixExpression parent = (JetPrefixExpression) expression.getParent();
2973                JetSimpleNameExpression operationSign = parent.getOperationReference();
2974                if (JetTokens.LABELS.contains(operationSign.getReferencedNameElementType())) {
2975                    return operationSign;
2976                }
2977            }
2978            return null;
2979        }
2980    
2981        @Override
2982        public StackValue visitPrefixExpression(@NotNull JetPrefixExpression expression, StackValue receiver) {
2983            JetSimpleNameExpression operationSign = expression.getOperationReference();
2984            if (JetTokens.LABELS.contains(operationSign.getReferencedNameElementType())) {
2985                return genQualified(receiver, expression.getBaseExpression());
2986            }
2987    
2988            DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
2989            assert op instanceof FunctionDescriptor : String.valueOf(op);
2990            Callable callable = resolveToCallable((FunctionDescriptor) op, false);
2991            if (callable instanceof IntrinsicMethod) {
2992                IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
2993                //noinspection ConstantConditions
2994                return intrinsic.generate(this, v, expressionType(expression), expression,
2995                                          Arrays.asList(expression.getBaseExpression()), receiver, state);
2996            }
2997            else {
2998                DeclarationDescriptor cls = op.getContainingDeclaration();
2999                CallableMethod callableMethod = (CallableMethod) callable;
3000                if (isPrimitiveNumberClassDescriptor(cls) || !(op.getName().asString().equals("inc") || op.getName().asString().equals("dec"))) {
3001                    return invokeOperation(expression, (FunctionDescriptor) op, callableMethod);
3002                }
3003                else {
3004                    ResolvedCall<? extends CallableDescriptor> resolvedCall =
3005                            bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
3006                    assert resolvedCall != null;
3007    
3008                    StackValue value = gen(expression.getBaseExpression());
3009                    value.dupReceiver(v);
3010                    value.dupReceiver(v);
3011    
3012                    Type type = expressionType(expression.getBaseExpression());
3013                    value.put(type, v);
3014                    callableMethod.invokeWithNotNullAssertion(v, state, resolvedCall);
3015    
3016                    value.store(callableMethod.getReturnType(), v);
3017                    value.put(type, v);
3018                    return StackValue.onStack(type);
3019                }
3020            }
3021        }
3022    
3023        private StackValue invokeOperation(JetOperationExpression expression, FunctionDescriptor op, CallableMethod callable) {
3024            int functionLocalIndex = lookupLocalIndex(op);
3025            if (functionLocalIndex >= 0) {
3026                stackValueForLocal(op, functionLocalIndex).put(callable.getOwner().getAsmType(), v);
3027            }
3028            ResolvedCall<? extends CallableDescriptor> resolvedCall =
3029                    bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
3030            assert resolvedCall != null;
3031            genThisAndReceiverFromResolvedCall(StackValue.none(), resolvedCall, callable);
3032            pushArgumentsAndInvoke(resolvedCall, callable);
3033    
3034            return returnValueAsStackValue(op, callable.getSignature().getAsmMethod().getReturnType());
3035        }
3036    
3037        @Override
3038        public StackValue visitPostfixExpression(@NotNull JetPostfixExpression expression, StackValue receiver) {
3039            if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL) {
3040                StackValue base = genQualified(receiver, expression.getBaseExpression());
3041                if (isPrimitive(base.type)) {
3042                    return base;
3043                }
3044                base.put(base.type, v);
3045                v.dup();
3046                Label ok = new Label();
3047                v.ifnonnull(ok);
3048                v.invokestatic("jet/runtime/Intrinsics", "throwNpe", "()V");
3049                v.mark(ok);
3050                return StackValue.onStack(base.type);
3051            }
3052    
3053            DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
3054            if (!(op instanceof FunctionDescriptor)) {
3055                throw new UnsupportedOperationException("Don't know how to generate this postfix expression: " + op);
3056            }
3057    
3058            Type asmType = expressionType(expression);
3059            DeclarationDescriptor cls = op.getContainingDeclaration();
3060    
3061            int increment;
3062            if (op.getName().asString().equals("inc")) {
3063                increment = 1;
3064            }
3065            else if (op.getName().asString().equals("dec")) {
3066                increment = -1;
3067            }
3068            else {
3069                throw new UnsupportedOperationException("Unsupported postfix operation: " + op);
3070            }
3071    
3072            if (isPrimitiveNumberClassDescriptor(cls)) {
3073                receiver.put(receiver.type, v);
3074                JetExpression operand = expression.getBaseExpression();
3075                if (operand instanceof JetReferenceExpression && asmType == Type.INT_TYPE) {
3076                    int index = indexOfLocal((JetReferenceExpression) operand);
3077                    if (index >= 0) {
3078                        return StackValue.postIncrement(index, increment);
3079                    }
3080                }
3081                gen(operand, asmType);                               // old value
3082                generateIncrement(increment, asmType, operand, receiver);   // increment in-place
3083                return StackValue.onStack(asmType);                                         // old value
3084            }
3085            else {
3086                ResolvedCall<? extends CallableDescriptor> resolvedCall =
3087                        bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
3088                assert resolvedCall != null;
3089    
3090                Callable callable = resolveToCallable((FunctionDescriptor) op, false);
3091    
3092                StackValue value = gen(expression.getBaseExpression());
3093                value.dupReceiver(v);
3094    
3095                Type type = expressionType(expression.getBaseExpression());
3096                value.put(type, v);
3097    
3098                switch (value.receiverSize()) {
3099                    case 0:
3100                        dup(v, type);
3101                        break;
3102    
3103                    case 1:
3104                        if (type.getSize() == 2) {
3105                            v.dup2X1();
3106                        }
3107                        else {
3108                            v.dupX1();
3109                        }
3110                        break;
3111    
3112                    case 2:
3113                        if (type.getSize() == 2) {
3114                            v.dup2X2();
3115                        }
3116                        else {
3117                            v.dupX2();
3118                        }
3119                        break;
3120    
3121                    case -1:
3122                        throw new UnsupportedOperationException();
3123                }
3124    
3125                CallableMethod callableMethod = (CallableMethod) callable;
3126                callableMethod.invokeWithNotNullAssertion(v, state, resolvedCall);
3127    
3128                value.store(callableMethod.getReturnType(), v);
3129                return StackValue.onStack(type);
3130            }
3131        }
3132    
3133        private void generateIncrement(int increment, Type asmType, JetExpression operand, StackValue receiver) {
3134            StackValue value = genQualified(receiver, operand);
3135            value.dupReceiver(v);
3136            value.put(asmType, v);
3137            genIncrement(asmType, increment, v);
3138            value.store(asmType, v);
3139        }
3140    
3141        @Override
3142        public StackValue visitProperty(@NotNull JetProperty property, StackValue receiver) {
3143            final JetExpression initializer = property.getInitializer();
3144            if (initializer == null) {
3145                return StackValue.none();
3146            }
3147            initializeLocalVariable(property, new Function<VariableDescriptor, Void>() {
3148                @Override
3149                public Void fun(VariableDescriptor descriptor) {
3150                    Type varType = asmType(descriptor.getType());
3151                    gen(initializer, varType);
3152                    return null;
3153                }
3154            });
3155            return StackValue.none();
3156        }
3157    
3158        @Override
3159        public StackValue visitMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration, StackValue receiver) {
3160            JetExpression initializer = multiDeclaration.getInitializer();
3161            if (initializer == null) return StackValue.none();
3162    
3163            JetType initializerType = bindingContext.get(EXPRESSION_TYPE, initializer);
3164            assert initializerType != null;
3165    
3166            Type initializerAsmType = asmType(initializerType);
3167    
3168            final TransientReceiver initializerAsReceiver = new TransientReceiver(initializerType);
3169    
3170            int tempVarIndex = myFrameMap.enterTemp(initializerAsmType);
3171    
3172            gen(initializer, initializerAsmType);
3173            v.store(tempVarIndex, initializerAsmType);
3174            final StackValue.Local local = StackValue.local(tempVarIndex, initializerAsmType);
3175    
3176            for (final JetMultiDeclarationEntry variableDeclaration : multiDeclaration.getEntries()) {
3177                initializeLocalVariable(variableDeclaration, new Function<VariableDescriptor, Void>() {
3178                    @Override
3179                    public Void fun(VariableDescriptor descriptor) {
3180                        ResolvedCall<FunctionDescriptor> resolvedCall =
3181                                bindingContext.get(BindingContext.COMPONENT_RESOLVED_CALL, variableDeclaration);
3182                        assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText();
3183                        Call call = makeFakeCall(initializerAsReceiver);
3184                        invokeFunction(call, local, resolvedCall);
3185                        return null;
3186                    }
3187                });
3188            }
3189    
3190            if(initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) {
3191                v.aconst(null);
3192                v.store(tempVarIndex, initializerAsmType);
3193            }
3194            myFrameMap.leaveTemp(initializerAsmType);
3195    
3196            return StackValue.none();
3197        }
3198    
3199        private void initializeLocalVariable(
3200                @NotNull JetVariableDeclaration variableDeclaration,
3201                @NotNull Function<VariableDescriptor, Void> generateInitializer
3202        ) {
3203    
3204            VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, variableDeclaration);
3205    
3206            if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) {
3207                return;
3208            }
3209            int index = lookupLocalIndex(variableDescriptor);
3210    
3211            if (index < 0) {
3212                throw new IllegalStateException("Local variable not found for " + variableDescriptor);
3213            }
3214    
3215            Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
3216            assert variableDescriptor != null;
3217    
3218            Type varType = asmType(variableDescriptor.getType());
3219    
3220            if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) {
3221                generateInitializer.fun(variableDescriptor);
3222                JetScript scriptPsi = JetPsiUtil.getScript(variableDeclaration);
3223                assert scriptPsi != null;
3224                JvmClassName scriptClassName = classNameForScriptPsi(bindingContext, scriptPsi);
3225                v.putfield(scriptClassName.getInternalName(), variableDeclaration.getName(), varType.getDescriptor());
3226            }
3227            else if (sharedVarType == null) {
3228                generateInitializer.fun(variableDescriptor);
3229                v.store(index, varType);
3230            }
3231            else {
3232                v.load(index, OBJECT_TYPE);
3233                generateInitializer.fun(variableDescriptor);
3234                v.putfield(sharedVarType.getInternalName(), "ref",
3235                           sharedVarType == JET_SHARED_VAR_TYPE ? "Ljava/lang/Object;" : varType.getDescriptor());
3236            }
3237        }
3238    
3239        @NotNull
3240        private StackValue generateNewCall(
3241                @NotNull JetCallExpression expression,
3242                @NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
3243                @NotNull StackValue receiver
3244        ) {
3245            Type type = expressionType(expression);
3246            if (type.getSort() == Type.ARRAY) {
3247                generateNewArray(expression);
3248                return StackValue.onStack(type);
3249            }
3250    
3251            return generateConstructorCall(resolvedCall, receiver, type);
3252        }
3253    
3254        @NotNull
3255        private StackValue generateConstructorCall(
3256                @NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
3257                @NotNull StackValue receiver,
3258                @NotNull Type type
3259        ) {
3260            v.anew(type);
3261            v.dup();
3262    
3263            receiver = StackValue.receiver(resolvedCall, receiver, this, null);
3264            receiver.put(receiver.type, v);
3265    
3266            ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
3267            MutableClosure closure = bindingContext.get(CLOSURE, constructorDescriptor.getContainingDeclaration());
3268    
3269            ClassDescriptor descriptor = getExpectedThisObjectForConstructorCall(constructorDescriptor, closure);
3270            if (receiver.type.getSort() != Type.VOID && descriptor == null) {
3271                v.pop();
3272            }
3273    
3274            //Resolved call to local class constructor doesn't have resolvedCall.getThisObject() and resolvedCall.getReceiverArgument()
3275            //so we need generate closure on stack
3276            //See StackValue.receiver for more info
3277            pushClosureOnStack(closure, resolvedCall.getThisObject().exists() || resolvedCall.getReceiverArgument().exists());
3278    
3279            ConstructorDescriptor originalOfSamAdapter = (ConstructorDescriptor) SamCodegenUtil.getOriginalIfSamAdapter(constructorDescriptor);
3280            CallableMethod method = typeMapper.mapToCallableMethod(originalOfSamAdapter == null ? constructorDescriptor : originalOfSamAdapter);
3281            invokeMethodWithArguments(method, resolvedCall, null, StackValue.none());
3282    
3283            return StackValue.onStack(type);
3284        }
3285    
3286        public void generateNewArray(@NotNull JetCallExpression expression) {
3287            JetType arrayType = bindingContext.get(EXPRESSION_TYPE, expression);
3288            assert arrayType != null : "Array instantiation isn't type checked: " + expression.getText();
3289    
3290            generateNewArray(expression, arrayType);
3291        }
3292    
3293        private void generateNewArray(@NotNull JetCallExpression expression, @NotNull JetType arrayType) {
3294            List<JetExpression> args = new ArrayList<JetExpression>();
3295            for (ValueArgument va : expression.getValueArguments()) {
3296                args.add(va.getArgumentExpression());
3297            }
3298            args.addAll(expression.getFunctionLiteralArguments());
3299    
3300            boolean isArray = KotlinBuiltIns.getInstance().isArray(arrayType);
3301            if (!isArray && args.size() != 1) {
3302                throw new CompilationException("primitive array constructor requires one argument", null, expression);
3303            }
3304    
3305            if (isArray) {
3306                gen(args.get(0), Type.INT_TYPE);
3307                v.newarray(boxType(asmType(arrayType.getArguments().get(0).getType())));
3308            }
3309            else {
3310                Type type = typeMapper.mapType(arrayType);
3311                gen(args.get(0), Type.INT_TYPE);
3312                v.newarray(correctElementType(type));
3313            }
3314    
3315            if (args.size() == 2) {
3316                int sizeIndex = myFrameMap.enterTemp(Type.INT_TYPE);
3317                int indexIndex = myFrameMap.enterTemp(Type.INT_TYPE);
3318    
3319                v.dup();
3320                v.arraylength();
3321                v.store(sizeIndex, Type.INT_TYPE);
3322    
3323                v.iconst(0);
3324                v.store(indexIndex, Type.INT_TYPE);
3325    
3326                gen(args.get(1), JET_FUNCTION1_TYPE);
3327    
3328                Label begin = new Label();
3329                Label end = new Label();
3330                v.visitLabel(begin);
3331                v.load(indexIndex, Type.INT_TYPE);
3332                v.load(sizeIndex, Type.INT_TYPE);
3333                v.ificmpge(end);
3334    
3335                v.dup2();
3336                v.load(indexIndex, Type.INT_TYPE);
3337                v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
3338                v.invokeinterface("jet/Function1", "invoke", "(Ljava/lang/Object;)Ljava/lang/Object;");
3339                v.load(indexIndex, Type.INT_TYPE);
3340                v.iinc(indexIndex, 1);
3341                v.swap();
3342                v.astore(OBJECT_TYPE);
3343    
3344                v.goTo(begin);
3345                v.visitLabel(end);
3346                v.pop();
3347    
3348                myFrameMap.leaveTemp(Type.INT_TYPE);
3349                myFrameMap.leaveTemp(Type.INT_TYPE);
3350            }
3351        }
3352    
3353        @Override
3354        public StackValue visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, StackValue receiver) {
3355            JetExpression array = expression.getArrayExpression();
3356            JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, array);
3357            Type arrayType = asmTypeOrVoid(type);
3358            List<JetExpression> indices = expression.getIndexExpressions();
3359            FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, expression);
3360            assert operationDescriptor != null;
3361            if (arrayType.getSort() == Type.ARRAY &&
3362                indices.size() == 1 &&
3363                operationDescriptor.getValueParameters().get(0).getType().equals(KotlinBuiltIns.getInstance().getIntType())) {
3364                gen(array, arrayType);
3365                for (JetExpression index : indices) {
3366                    gen(index, Type.INT_TYPE);
3367                }
3368                assert type != null;
3369                if (KotlinBuiltIns.getInstance().isArray(type)) {
3370                    JetType elementType = type.getArguments().get(0).getType();
3371                    Type notBoxed = asmType(elementType);
3372                    return StackValue.arrayElement(notBoxed, true);
3373                }
3374                else {
3375                    return StackValue.arrayElement(correctElementType(arrayType), false);
3376                }
3377            }
3378            else {
3379                ResolvedCall<FunctionDescriptor> resolvedSetCall = bindingContext.get(BindingContext.INDEXED_LVALUE_SET, expression);
3380                ResolvedCall<FunctionDescriptor> resolvedGetCall = bindingContext.get(BindingContext.INDEXED_LVALUE_GET, expression);
3381    
3382                boolean isGetter = "get".equals(operationDescriptor.getName().asString());
3383    
3384                ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall;
3385                assert resolvedCall != null : "couldn't find resolved call: " + expression.getText();
3386    
3387                Callable callable = resolveToCallable(operationDescriptor, false);
3388                if (callable instanceof CallableMethod) {
3389                    genThisAndReceiverFromResolvedCall(receiver, resolvedCall, (CallableMethod) callable);
3390                }
3391                else {
3392                    gen(array, arrayType); // intrinsic method
3393                }
3394    
3395                int index = operationDescriptor.getReceiverParameter() != null ? 1 : 0;
3396    
3397                Method asmMethod = resolveToCallableMethod(operationDescriptor, false, context).getSignature().getAsmMethod();
3398                Type[] argumentTypes = asmMethod.getArgumentTypes();
3399                for (JetExpression jetExpression : expression.getIndexExpressions()) {
3400                    gen(jetExpression, argumentTypes[index]);
3401                    index++;
3402                }
3403    
3404                Type elementType = isGetter ? asmMethod.getReturnType() : ArrayUtil.getLastElement(argumentTypes);
3405                return StackValue.collectionElement(elementType, resolvedGetCall, resolvedSetCall, this, state);
3406            }
3407        }
3408    
3409        @Override
3410        public StackValue visitThrowExpression(@NotNull JetThrowExpression expression, StackValue receiver) {
3411            gen(expression.getThrownExpression(), JAVA_THROWABLE_TYPE);
3412            v.athrow();
3413            return StackValue.none();
3414        }
3415    
3416        @Override
3417        public StackValue visitThisExpression(@NotNull JetThisExpression expression, StackValue receiver) {
3418            DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
3419            if (descriptor instanceof ClassDescriptor) {
3420                return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor, false);
3421            }
3422            else {
3423                if (descriptor instanceof CallableDescriptor) {
3424                    return generateReceiver(descriptor);
3425                }
3426                throw new UnsupportedOperationException("neither this nor receiver");
3427            }
3428        }
3429    
3430        @Override
3431        public StackValue visitTryExpression(@NotNull JetTryExpression expression, StackValue receiver) {
3432            return generateTryExpression(expression, false);
3433        }
3434    
3435        public StackValue generateTryExpression(JetTryExpression expression, boolean isStatement) {
3436            /*
3437    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
3438    (or blocks).
3439             */
3440            JetFinallySection finallyBlock = expression.getFinallyBlock();
3441            FinallyBlockStackElement finallyBlockStackElement = null;
3442            if (finallyBlock != null) {
3443                finallyBlockStackElement = new FinallyBlockStackElement(expression);
3444                blockStackElements.push(finallyBlockStackElement);
3445            }
3446    
3447            JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
3448            assert jetType != null;
3449            Type expectedAsmType = isStatement ? Type.VOID_TYPE : asmType(jetType);
3450    
3451            Label tryStart = new Label();
3452            v.mark(tryStart);
3453            v.nop(); // prevent verify error on empty try
3454    
3455            gen(expression.getTryBlock(), expectedAsmType);
3456    
3457            int savedValue = -1;
3458            if (!isStatement) {
3459                savedValue = myFrameMap.enterTemp(expectedAsmType);
3460                v.store(savedValue, expectedAsmType);
3461            }
3462    
3463            Label tryEnd = new Label();
3464            v.mark(tryEnd);
3465    
3466            //do it before finally block generation
3467            List<Label> tryBlockRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, tryEnd);
3468    
3469            Label end = new Label();
3470    
3471            genFinallyBlockOrGoto(finallyBlockStackElement, end);
3472    
3473            List<JetCatchClause> clauses = expression.getCatchClauses();
3474            for (int i = 0, size = clauses.size(); i < size; i++) {
3475                JetCatchClause clause = clauses.get(i);
3476    
3477                Label clauseStart = new Label();
3478                v.mark(clauseStart);
3479    
3480                VariableDescriptor descriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, clause.getCatchParameter());
3481                assert descriptor != null;
3482                Type descriptorType = asmType(descriptor.getType());
3483                myFrameMap.enter(descriptor, descriptorType);
3484                int index = lookupLocalIndex(descriptor);
3485                v.store(index, descriptorType);
3486    
3487                gen(clause.getCatchBody(), expectedAsmType);
3488    
3489                if (!isStatement) {
3490                    v.store(savedValue, expectedAsmType);
3491                }
3492    
3493                myFrameMap.leave(descriptor);
3494    
3495                genFinallyBlockOrGoto(finallyBlockStackElement, i != size - 1 || finallyBlock != null ? end : null);
3496    
3497                generateExceptionTable(clauseStart, tryBlockRegions, descriptorType.getInternalName());
3498            }
3499    
3500    
3501            //for default catch clause
3502            if (finallyBlock != null) {
3503                Label defaultCatchStart = new Label();
3504                v.mark(defaultCatchStart);
3505                int savedException = myFrameMap.enterTemp(JAVA_THROWABLE_TYPE);
3506                v.store(savedException, JAVA_THROWABLE_TYPE);
3507                Label defaultCatchEnd = new Label();
3508                v.mark(defaultCatchEnd);
3509    
3510                //do it before finally block generation
3511                //javac also generates entry in exception table for default catch clause too!!!! so defaultCatchEnd as end parameter
3512                List<Label> defaultCatchRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, defaultCatchEnd);
3513    
3514    
3515                genFinallyBlockOrGoto(finallyBlockStackElement, null);
3516    
3517                v.load(savedException, JAVA_THROWABLE_TYPE);
3518                myFrameMap.leaveTemp(JAVA_THROWABLE_TYPE);
3519    
3520                v.athrow();
3521    
3522                generateExceptionTable(defaultCatchStart, defaultCatchRegions, null);
3523            }
3524    
3525            markLineNumber(expression);
3526            v.mark(end);
3527    
3528            if (!isStatement) {
3529                v.load(savedValue, expectedAsmType);
3530                myFrameMap.leaveTemp(expectedAsmType);
3531            }
3532    
3533            if (finallyBlock != null) {
3534                blockStackElements.pop();
3535            }
3536    
3537            return StackValue.onStack(expectedAsmType);
3538        }
3539    
3540        private void generateExceptionTable(@NotNull Label catchStart, @NotNull List<Label> catchedRegions, @Nullable String exception) {
3541            for (int i = 0; i < catchedRegions.size(); i += 2) {
3542                Label startRegion = catchedRegions.get(i);
3543                Label endRegion = catchedRegions.get(i+1);
3544                v.visitTryCatchBlock(startRegion, endRegion, catchStart, exception);
3545            }
3546        }
3547    
3548    
3549        private List<Label> getCurrentCatchIntervals(
3550                @Nullable FinallyBlockStackElement finallyBlockStackElement,
3551                @NotNull Label blockStart,
3552                @NotNull Label blockEnd
3553        ) {
3554            List<Label> gapsInBlock =
3555                    finallyBlockStackElement != null ? new ArrayList<Label>(finallyBlockStackElement.gaps) : Collections.<Label>emptyList();
3556            assert gapsInBlock.size() % 2 == 0;
3557            List<Label> blockRegions = new ArrayList<Label>(gapsInBlock.size() + 2);
3558            blockRegions.add(blockStart);
3559            blockRegions.addAll(gapsInBlock);
3560            blockRegions.add(blockEnd);
3561            return blockRegions;
3562        }
3563    
3564        @Override
3565        public StackValue visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression, StackValue receiver) {
3566            JetSimpleNameExpression operationSign = expression.getOperationReference();
3567            IElementType opToken = operationSign.getReferencedNameElementType();
3568            if (opToken == JetTokens.COLON) {
3569                return gen(expression.getLeft());
3570            }
3571            else {
3572                JetTypeReference typeReference = expression.getRight();
3573                JetType rightType = bindingContext.get(BindingContext.TYPE, typeReference);
3574                assert rightType != null;
3575                Type rightTypeAsm = boxType(asmType(rightType));
3576                JetExpression left = expression.getLeft();
3577                DeclarationDescriptor descriptor = rightType.getConstructor().getDeclarationDescriptor();
3578                if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) {
3579                    StackValue value = genQualified(receiver, left);
3580                    value.put(boxType(value.type), v);
3581    
3582                    if (opToken != JetTokens.AS_SAFE) {
3583                        if (!CodegenUtil.isNullableType(rightType)) {
3584                            v.dup();
3585                            Label nonnull = new Label();
3586                            v.ifnonnull(nonnull);
3587                            JetType leftType = bindingContext.get(BindingContext.EXPRESSION_TYPE, left);
3588                            assert leftType != null;
3589                            throwNewException(CLASS_TYPE_CAST_EXCEPTION, DescriptorRenderer.TEXT.renderType(leftType) +
3590                                                                         " cannot be cast to " +
3591                                                                         DescriptorRenderer.TEXT.renderType(rightType));
3592                            v.mark(nonnull);
3593                        }
3594                    }
3595                    else {
3596                        v.dup();
3597                        v.instanceOf(rightTypeAsm);
3598                        Label ok = new Label();
3599                        v.ifne(ok);
3600                        v.pop();
3601                        v.aconst(null);
3602                        v.mark(ok);
3603                    }
3604    
3605                    v.checkcast(rightTypeAsm);
3606                    return StackValue.onStack(rightTypeAsm);
3607                }
3608                else {
3609                    throw new UnsupportedOperationException("Don't know how to handle non-class types in as/as? : " + descriptor);
3610                }
3611            }
3612        }
3613    
3614        @Override
3615        public StackValue visitIsExpression(@NotNull JetIsExpression expression, StackValue receiver) {
3616            StackValue match = StackValue.expression(OBJECT_TYPE, expression.getLeftHandSide(), this);
3617            return generateIsCheck(match, expression.getTypeRef(), expression.isNegated());
3618        }
3619    
3620        private StackValue generateExpressionMatch(StackValue expressionToMatch, JetExpression patternExpression) {
3621            if (expressionToMatch != null) {
3622                Type subjectType = expressionToMatch.type;
3623                expressionToMatch.dupReceiver(v);
3624                expressionToMatch.put(subjectType, v);
3625                JetType condJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, patternExpression);
3626                Type condType;
3627                if (isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) {
3628                    assert condJetType != null;
3629                    condType = asmType(condJetType);
3630                    if (!(isNumberPrimitive(condType) || condType.getSort() == Type.BOOLEAN)) {
3631                        subjectType = boxType(subjectType);
3632                        expressionToMatch.coerceTo(subjectType, v);
3633                    }
3634                }
3635                else {
3636                    condType = OBJECT_TYPE;
3637                }
3638                gen(patternExpression, condType);
3639                return genEqualsForExpressionsOnStack(v, JetTokens.EQEQ, subjectType, condType);
3640            }
3641            else {
3642                return gen(patternExpression);
3643            }
3644        }
3645    
3646        private StackValue generateIsCheck(StackValue expressionToMatch, JetTypeReference typeReference, boolean negated) {
3647            JetType jetType = bindingContext.get(BindingContext.TYPE, typeReference);
3648            expressionToMatch.dupReceiver(v);
3649            generateInstanceOf(expressionToMatch, jetType, false);
3650            StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE);
3651            return negated ? StackValue.not(value) : value;
3652        }
3653    
3654        private void generateInstanceOf(StackValue expressionToGen, JetType jetType, boolean leaveExpressionOnStack) {
3655            expressionToGen.put(OBJECT_TYPE, v);
3656            if (leaveExpressionOnStack) {
3657                v.dup();
3658            }
3659            Type type = boxType(asmType(jetType));
3660            if (jetType.isNullable()) {
3661                Label nope = new Label();
3662                Label end = new Label();
3663    
3664                v.dup();
3665                v.ifnull(nope);
3666                v.instanceOf(type);
3667                v.goTo(end);
3668                v.mark(nope);
3669                v.pop();
3670                v.iconst(1);
3671                v.mark(end);
3672            }
3673            else {
3674                v.instanceOf(type);
3675            }
3676        }
3677    
3678        @Override
3679        public StackValue visitWhenExpression(@NotNull JetWhenExpression expression, StackValue receiver) {
3680            return generateWhenExpression(expression, false);
3681        }
3682    
3683        public StackValue generateWhenExpression(JetWhenExpression expression, boolean isStatement) {
3684            JetExpression expr = expression.getSubjectExpression();
3685            JetType subjectJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expr);
3686            Type subjectType = asmTypeOrVoid(subjectJetType);
3687            Type resultType = isStatement ? Type.VOID_TYPE : expressionType(expression);
3688            int subjectLocal = expr != null ? myFrameMap.enterTemp(subjectType) : -1;
3689            if (subjectLocal != -1) {
3690                gen(expr, subjectType);
3691                tempVariables.put(expr, StackValue.local(subjectLocal, subjectType));
3692                v.store(subjectLocal, subjectType);
3693            }
3694    
3695            Label end = new Label();
3696            boolean hasElse = JetPsiUtil.checkWhenExpressionHasSingleElse(expression);
3697    
3698            Label nextCondition = null;
3699            for (JetWhenEntry whenEntry : expression.getEntries()) {
3700                if (nextCondition != null) {
3701                    v.mark(nextCondition);
3702                }
3703                nextCondition = new Label();
3704                FrameMap.Mark mark = myFrameMap.mark();
3705                Label thisEntry = new Label();
3706                if (!whenEntry.isElse()) {
3707                    JetWhenCondition[] conditions = whenEntry.getConditions();
3708                    for (int i = 0; i < conditions.length; i++) {
3709                        StackValue conditionValue = generateWhenCondition(subjectType, subjectLocal, conditions[i]);
3710                        conditionValue.condJump(nextCondition, true, v);
3711                        if (i < conditions.length - 1) {
3712                            v.goTo(thisEntry);
3713                            v.mark(nextCondition);
3714                            nextCondition = new Label();
3715                        }
3716                    }
3717                }
3718    
3719                v.visitLabel(thisEntry);
3720                gen(whenEntry.getExpression(), resultType);
3721                mark.dropTo();
3722                if (!whenEntry.isElse()) {
3723                    v.goTo(end);
3724                }
3725            }
3726            if (!hasElse && nextCondition != null) {
3727                v.mark(nextCondition);
3728                throwNewException(CLASS_NO_PATTERN_MATCHED_EXCEPTION);
3729            }
3730    
3731            markLineNumber(expression);
3732            v.mark(end);
3733    
3734            myFrameMap.leaveTemp(subjectType);
3735            tempVariables.remove(expr);
3736            return StackValue.onStack(resultType);
3737        }
3738    
3739        private StackValue generateWhenCondition(Type subjectType, int subjectLocal, JetWhenCondition condition) {
3740            if (condition instanceof JetWhenConditionInRange) {
3741                JetWhenConditionInRange conditionInRange = (JetWhenConditionInRange) condition;
3742                JetExpression rangeExpression = conditionInRange.getRangeExpression();
3743                while (rangeExpression instanceof JetParenthesizedExpression) {
3744                    rangeExpression = ((JetParenthesizedExpression) rangeExpression).getExpression();
3745                }
3746                JetSimpleNameExpression operationReference = conditionInRange.getOperationReference();
3747                boolean inverted = operationReference.getReferencedNameElementType() == JetTokens.NOT_IN;
3748                if (isIntRangeExpr(rangeExpression)) {
3749                    getInIntRange(new StackValue.Local(subjectLocal, subjectType), (JetBinaryExpression) rangeExpression, inverted);
3750                }
3751                else {
3752                    //FunctionDescriptor op =
3753                    //        (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, conditionInRange.getOperationReference());
3754                    //genToJVMStack(rangeExpression);
3755                    //new StackValue.Local(subjectLocal, subjectType).put(OBJECT_TYPE, v);
3756                    //invokeFunctionNoParams(op, Type.BOOLEAN_TYPE, v);
3757                    invokeFunctionByReference(operationReference);
3758                    if (inverted) {
3759                        genInvertBoolean(v);
3760                    }
3761                }
3762                return StackValue.onStack(Type.BOOLEAN_TYPE);
3763            }
3764            StackValue.Local match = subjectLocal == -1 ? null : StackValue.local(subjectLocal, subjectType);
3765            if (condition instanceof JetWhenConditionIsPattern) {
3766                JetWhenConditionIsPattern patternCondition = (JetWhenConditionIsPattern) condition;
3767                return generateIsCheck(match, patternCondition.getTypeRef(), patternCondition.isNegated());
3768            }
3769            else if (condition instanceof JetWhenConditionWithExpression) {
3770                JetExpression patternExpression = ((JetWhenConditionWithExpression) condition).getExpression();
3771                return generateExpressionMatch(match, patternExpression);
3772            }
3773            else {
3774                throw new UnsupportedOperationException("unsupported kind of when condition");
3775            }
3776        }
3777    
3778        private void invokeFunctionByReference(JetSimpleNameExpression operationReference) {
3779            ResolvedCall<? extends CallableDescriptor> resolvedCall =
3780                    bindingContext.get(RESOLVED_CALL, operationReference);
3781            Call call = bindingContext.get(CALL, operationReference);
3782            invokeFunction(call, StackValue.none(), resolvedCall);
3783        }
3784    
3785        private boolean isIntRangeExpr(JetExpression rangeExpression) {
3786            if (rangeExpression instanceof JetBinaryExpression) {
3787                JetBinaryExpression binaryExpression = (JetBinaryExpression) rangeExpression;
3788                if (binaryExpression.getOperationReference().getReferencedNameElementType() == JetTokens.RANGE) {
3789                    JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, rangeExpression);
3790                    assert jetType != null;
3791                    DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
3792                    return INTEGRAL_RANGES.contains(descriptor);
3793                }
3794            }
3795            return false;
3796        }
3797    
3798        private void throwNewException(@NotNull String className) {
3799            throwNewException(className, null);
3800        }
3801    
3802        private void throwNewException(@NotNull String className, @Nullable String message) {
3803            v.anew(Type.getObjectType(className));
3804            v.dup();
3805            if (message != null) {
3806                v.visitLdcInsn(message);
3807                v.invokespecial(className, "<init>", "(Ljava/lang/String;)V");
3808            }
3809            else {
3810                v.invokespecial(className, "<init>", "()V");
3811            }
3812            v.athrow();
3813        }
3814    
3815        private Call makeFakeCall(ReceiverValue initializerAsReceiver) {
3816            JetSimpleNameExpression fake = JetPsiFactory.createSimpleName(state.getProject(), "fake");
3817            return CallMaker.makeCall(fake, initializerAsReceiver);
3818        }
3819    
3820        @Override
3821        public String toString() {
3822            return context.getContextDescriptor().toString();
3823        }
3824    }