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