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