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.ClassDescriptorFromJvmBytecode;
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                    ClassDescriptorFromJvmBytecode 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                    ClassifierDescriptor captureReceiver = closure.getCaptureReceiver();
1378                    if (captureReceiver != null) {
1379                        v.load(context.isStatic() ? 0 : 1, typeMapper.mapClass(captureReceiver));
1380                    }
1381                }
1382    
1383                for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closure.getCaptureVariables().entrySet()) {
1384                    //if (entry.getKey() instanceof VariableDescriptor && !(entry.getKey() instanceof PropertyDescriptor)) {
1385                    Type sharedVarType = typeMapper.getSharedVarType(entry.getKey());
1386                    if (sharedVarType == null) {
1387                        sharedVarType = typeMapper.mapType((VariableDescriptor) entry.getKey());
1388                    }
1389                    entry.getValue().getOuterValue(this).put(sharedVarType, v);
1390                    //}
1391                }
1392            }
1393        }
1394    
1395        private StackValue generateBlock(List<JetElement> statements, boolean lastStatementIsExpression) {
1396            Label blockEnd = new Label();
1397    
1398            List<Function<StackValue, Void>> leaveTasks = Lists.newArrayList();
1399    
1400            StackValue answer = StackValue.none();
1401    
1402            for (Iterator<JetElement> iterator = statements.iterator(); iterator.hasNext(); ) {
1403                JetElement statement = iterator.next();
1404    
1405                if (statement instanceof JetNamedDeclaration) {
1406                    JetNamedDeclaration declaration = (JetNamedDeclaration) statement;
1407                    if (JetPsiUtil.isScriptDeclaration(declaration)) {
1408                        continue;
1409                    }
1410                }
1411    
1412                if (statement instanceof JetMultiDeclaration) {
1413                    JetMultiDeclaration multiDeclaration = (JetMultiDeclaration) statement;
1414                    for (JetMultiDeclarationEntry entry : multiDeclaration.getEntries()) {
1415                        generateLocalVariableDeclaration(entry, blockEnd, leaveTasks);
1416                    }
1417                }
1418    
1419                if (statement instanceof JetVariableDeclaration) {
1420                    generateLocalVariableDeclaration((JetVariableDeclaration) statement, blockEnd, leaveTasks);
1421                }
1422    
1423                if (statement instanceof JetNamedFunction) {
1424                    generateLocalFunctionDeclaration((JetNamedFunction) statement, leaveTasks);
1425                }
1426    
1427                boolean isExpression = !iterator.hasNext() && lastStatementIsExpression;
1428    
1429                StackValue result = isExpression ? gen(statement) : genStatement(statement);
1430    
1431                if (!iterator.hasNext()) {
1432                    answer = result;
1433                }
1434                else {
1435                    result.put(Type.VOID_TYPE, v);
1436                }
1437            }
1438    
1439            v.mark(blockEnd);
1440    
1441            for (Function<StackValue, Void> task : Lists.reverse(leaveTasks)) {
1442                task.fun(answer);
1443            }
1444    
1445            return answer;
1446        }
1447    
1448        private void generateLocalVariableDeclaration(
1449                @NotNull JetVariableDeclaration variableDeclaration,
1450                final @NotNull Label blockEnd,
1451                @NotNull List<Function<StackValue, Void>> leaveTasks
1452        ) {
1453            final VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, variableDeclaration);
1454            assert variableDescriptor != null;
1455    
1456            final Label scopeStart = new Label();
1457            v.mark(scopeStart);
1458    
1459            final Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
1460            final Type type = sharedVarType != null ? sharedVarType : asmType(variableDescriptor.getType());
1461            int index = myFrameMap.enter(variableDescriptor, type);
1462    
1463            if (sharedVarType != null) {
1464                v.anew(sharedVarType);
1465                v.dup();
1466                v.invokespecial(sharedVarType.getInternalName(), "<init>", "()V");
1467                v.store(index, OBJECT_TYPE);
1468            }
1469    
1470            leaveTasks.add(new Function<StackValue, Void>() {
1471                @Override
1472                public Void fun(StackValue answer) {
1473                    int index = myFrameMap.leave(variableDescriptor);
1474    
1475                    if (sharedVarType != null) {
1476                        if (answer instanceof StackValue.Shared && index == ((StackValue.Shared) answer).getIndex()) {
1477                            ((StackValue.Shared) answer).releaseOnPut();
1478                        }
1479                        else {
1480                            v.aconst(null);
1481                            v.store(index, OBJECT_TYPE);
1482                        }
1483                    }
1484                    v.visitLocalVariable(variableDescriptor.getName().asString(), type.getDescriptor(), null, scopeStart, blockEnd,
1485                                         index);
1486                    return null;
1487                }
1488            });
1489        }
1490    
1491        private void generateLocalFunctionDeclaration(
1492                @NotNull JetNamedFunction namedFunction,
1493                @NotNull List<Function<StackValue, Void>> leaveTasks
1494        ) {
1495            final DeclarationDescriptor descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, namedFunction);
1496            myFrameMap.enter(descriptor, OBJECT_TYPE);
1497    
1498            leaveTasks.add(new Function<StackValue, Void>() {
1499                @Override
1500                public Void fun(StackValue value) {
1501                    myFrameMap.leave(descriptor);
1502                    return null;
1503                }
1504            });
1505        }
1506    
1507        private void markLineNumber(@NotNull JetElement statement) {
1508            Document document = statement.getContainingFile().getViewProvider().getDocument();
1509            if (document != null) {
1510                int lineNumber = document.getLineNumber(statement.getTextRange().getStartOffset());  // 0-based
1511                if (lineNumber == myLastLineNumber) {
1512                    return;
1513                }
1514                myLastLineNumber = lineNumber;
1515    
1516                Label label = new Label();
1517                v.visitLabel(label);
1518                v.visitLineNumber(lineNumber + 1, label);  // 1-based
1519            }
1520        }
1521    
1522        private void doFinallyOnReturn() {
1523            if(!blockStackElements.isEmpty()) {
1524                BlockStackElement stackElement = blockStackElements.peek();
1525                if (stackElement instanceof FinallyBlockStackElement) {
1526                    FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement;
1527                    genFinallyBlockOrGoto(finallyBlockStackElement, null);
1528                }
1529                else if (stackElement instanceof LoopBlockStackElement) {
1530    
1531                } else {
1532                    throw new UnsupportedOperationException("Wrong BlockStackElement in processing stack");
1533                }
1534    
1535                blockStackElements.pop();
1536                doFinallyOnReturn();
1537                blockStackElements.push(stackElement);
1538            }
1539        }
1540    
1541        private void genFinallyBlockOrGoto(
1542                @Nullable FinallyBlockStackElement finallyBlockStackElement,
1543                @Nullable Label tryCatchBlockEnd
1544        ) {
1545    
1546            if (finallyBlockStackElement != null) {
1547                assert finallyBlockStackElement.gaps.size() % 2 == 0 : "Finally block gaps are inconsistent";
1548    
1549                BlockStackElement topOfStack = blockStackElements.pop();
1550                assert topOfStack == finallyBlockStackElement : "Top element of stack doesn't equals processing finally block";
1551    
1552                JetTryExpression jetTryExpression = finallyBlockStackElement.expression;
1553                Label finallyStart = new Label();
1554                v.mark(finallyStart);
1555                finallyBlockStackElement.addGapLabel(finallyStart);
1556    
1557                //noinspection ConstantConditions
1558                gen(jetTryExpression.getFinallyBlock().getFinalExpression(), Type.VOID_TYPE);
1559            }
1560    
1561            if (tryCatchBlockEnd != null) {
1562                v.goTo(tryCatchBlockEnd);
1563            }
1564    
1565            if (finallyBlockStackElement != null) {
1566                Label finallyEnd = new Label();
1567                v.mark(finallyEnd);
1568                finallyBlockStackElement.addGapLabel(finallyEnd);
1569    
1570                blockStackElements.push(finallyBlockStackElement);
1571            }
1572        }
1573    
1574        @Override
1575        public StackValue visitReturnExpression(@NotNull JetReturnExpression expression, StackValue receiver) {
1576            JetExpression returnedExpression = expression.getReturnedExpression();
1577            if (returnedExpression != null) {
1578                gen(returnedExpression, returnType);
1579                doFinallyOnReturn();
1580                v.areturn(returnType);
1581            }
1582            else {
1583                doFinallyOnReturn();
1584                v.visitInsn(RETURN);
1585            }
1586            return StackValue.none();
1587        }
1588    
1589        public void returnExpression(JetExpression expr) {
1590            StackValue lastValue = gen(expr);
1591    
1592            if (lastValue.type != Type.VOID_TYPE) {
1593                lastValue.put(returnType, v);
1594                v.areturn(returnType);
1595            }
1596            else if (!endsWithReturn(expr)) {
1597                v.areturn(returnType);
1598            }
1599        }
1600    
1601        private static boolean endsWithReturn(JetElement bodyExpression) {
1602            if (bodyExpression instanceof JetBlockExpression) {
1603                List<JetElement> statements = ((JetBlockExpression) bodyExpression).getStatements();
1604                return statements.size() > 0 && statements.get(statements.size() - 1) instanceof JetReturnExpression;
1605            }
1606    
1607            return bodyExpression instanceof JetReturnExpression;
1608        }
1609    
1610        @Override
1611        public StackValue visitSimpleNameExpression(@NotNull JetSimpleNameExpression expression, StackValue receiver) {
1612            ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression);
1613    
1614            DeclarationDescriptor descriptor;
1615            if (resolvedCall == null) {
1616                descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression);
1617            }
1618            else {
1619                if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
1620                    VariableAsFunctionResolvedCall call = (VariableAsFunctionResolvedCall) resolvedCall;
1621                    resolvedCall = call.getVariableCall();
1622                }
1623                receiver = StackValue.receiver(resolvedCall, receiver, this, null);
1624                descriptor = resolvedCall.getResultingDescriptor();
1625            }
1626    
1627            //if (descriptor instanceof VariableAsFunctionDescriptor) {
1628            //    descriptor = ((VariableAsFunctionDescriptor) descriptor).getVariableDescriptor();
1629            //}
1630    
1631            assert descriptor != null : "Couldn't find descriptor for '" + expression.getText() + "'";
1632            descriptor = descriptor.getOriginal();
1633    
1634            if (descriptor instanceof CallableMemberDescriptor) {
1635                CallableMemberDescriptor memberDescriptor = (CallableMemberDescriptor) descriptor;
1636                memberDescriptor = unwrapFakeOverride(memberDescriptor);
1637    
1638                IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(memberDescriptor);
1639                if (intrinsic != null) {
1640                    Type expectedType = expressionType(expression);
1641                    return intrinsic.generate(this, v, expectedType, expression, Collections.<JetExpression>emptyList(), receiver, state);
1642                }
1643            }
1644    
1645            if (descriptor instanceof VariableDescriptorForObject) {
1646                VariableDescriptorForObject variableDescriptor = (VariableDescriptorForObject) descriptor;
1647                ClassDescriptor objectClassDescriptor = variableDescriptor.getObjectClass();
1648                return genObjectClassInstance(variableDescriptor, objectClassDescriptor);
1649            }
1650    
1651            int index = lookupLocalIndex(descriptor);
1652            if (index >= 0) {
1653                return stackValueForLocal(descriptor, index);
1654            }
1655    
1656            if (descriptor instanceof PropertyDescriptor) {
1657                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
1658    
1659                boolean directToField =
1660                        expression.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER && contextKind() != OwnerKind.TRAIT_IMPL;
1661                JetExpression r = getReceiverForSelector(expression);
1662                boolean isSuper = r instanceof JetSuperExpression;
1663                propertyDescriptor = accessiblePropertyDescriptor(propertyDescriptor);
1664                StackValue iValue =
1665                    intermediateValueForProperty(propertyDescriptor, directToField, isSuper ? (JetSuperExpression) r : null);
1666                if (directToField) {
1667                    receiver = StackValue.receiverWithoutReceiverArgument(receiver);
1668                }
1669                receiver.put(receiver.type, v);
1670    
1671                return iValue;
1672            }
1673    
1674            if (descriptor instanceof ClassDescriptor) {
1675                ClassDescriptor classObjectDescriptor = ((ClassDescriptor) descriptor).getClassObjectDescriptor();
1676                assert classObjectDescriptor != null : "Class object is not found for " + descriptor;
1677                return StackValue.singleton(classObjectDescriptor, typeMapper);
1678            }
1679    
1680            if (descriptor instanceof TypeParameterDescriptor) {
1681                TypeParameterDescriptor typeParameterDescriptor = (TypeParameterDescriptor) descriptor;
1682                v.invokevirtual("jet/TypeInfo", "getClassObject", "()Ljava/lang/Object;");
1683                JetType type = typeParameterDescriptor.getClassObjectType();
1684                assert type != null;
1685                v.checkcast(asmType(type));
1686    
1687                return StackValue.onStack(OBJECT_TYPE);
1688            }
1689    
1690            StackValue value = context.lookupInContext(descriptor, StackValue.local(0, OBJECT_TYPE), state, false);
1691            if (value != null) {
1692    
1693                if (value instanceof StackValue.Composed) {
1694                    StackValue.Composed composed = (StackValue.Composed) value;
1695                    composed.prefix.put(OBJECT_TYPE, v);
1696                    value = composed.suffix;
1697                }
1698    
1699                if (value instanceof StackValue.FieldForSharedVar) {
1700                    StackValue.FieldForSharedVar fieldForSharedVar = (StackValue.FieldForSharedVar) value;
1701                    Type sharedType = StackValue.sharedTypeForType(value.type);
1702                    v.visitFieldInsn(GETFIELD, fieldForSharedVar.owner.getInternalName(), fieldForSharedVar.name,
1703                                     sharedType.getDescriptor());
1704                }
1705    
1706                return value;
1707            }
1708    
1709            if (descriptor instanceof ValueParameterDescriptor && descriptor.getContainingDeclaration() instanceof ScriptDescriptor) {
1710                ScriptDescriptor scriptDescriptor = (ScriptDescriptor) descriptor.getContainingDeclaration();
1711                assert scriptDescriptor != null;
1712                Type scriptClassType = asmTypeForScriptDescriptor(bindingContext, scriptDescriptor);
1713                ValueParameterDescriptor valueParameterDescriptor = (ValueParameterDescriptor) descriptor;
1714                ClassDescriptor scriptClass = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor);
1715                StackValue script = StackValue.thisOrOuter(this, scriptClass, false);
1716                script.put(script.type, v);
1717                Type fieldType = typeMapper.mapType(valueParameterDescriptor);
1718                return StackValue.field(fieldType, scriptClassType, valueParameterDescriptor.getName().getIdentifier(), false);
1719            }
1720    
1721            throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
1722        }
1723    
1724        private StackValue genObjectClassInstance(VariableDescriptor variableDescriptor, ClassDescriptor objectClassDescriptor) {
1725            boolean isEnumEntry = DescriptorUtils.isEnumClassObject(variableDescriptor.getContainingDeclaration());
1726            if (isEnumEntry) {
1727                ClassDescriptor containing = (ClassDescriptor) variableDescriptor.getContainingDeclaration().getContainingDeclaration();
1728                assert containing != null;
1729                Type type = typeMapper.mapType(containing);
1730                return StackValue.field(type, type, variableDescriptor.getName().asString(), true);
1731            }
1732            else {
1733                return StackValue.singleton(objectClassDescriptor, typeMapper);
1734            }
1735        }
1736    
1737        private StackValue stackValueForLocal(DeclarationDescriptor descriptor, int index) {
1738            if (descriptor instanceof VariableDescriptor) {
1739                Type sharedVarType = typeMapper.getSharedVarType(descriptor);
1740                JetType outType = ((VariableDescriptor) descriptor).getType();
1741                if (sharedVarType != null) {
1742                    return StackValue.shared(index, asmType(outType));
1743                }
1744                else {
1745                    return StackValue.local(index, asmType(outType));
1746                }
1747            }
1748            else {
1749                return StackValue.local(index, OBJECT_TYPE);
1750            }
1751        }
1752    
1753        @Override
1754        public boolean lookupLocal(DeclarationDescriptor descriptor) {
1755            return lookupLocalIndex(descriptor) != -1;
1756        }
1757    
1758        public int lookupLocalIndex(DeclarationDescriptor descriptor) {
1759            return myFrameMap.getIndex(descriptor);
1760        }
1761    
1762        @Nullable
1763        private static JetType getPropertyDelegateType(@NotNull PropertyDescriptor descriptor, @NotNull BindingContext bindingContext) {
1764            PropertyGetterDescriptor getter = descriptor.getGetter();
1765            if (getter != null) {
1766                Call call = bindingContext.get(BindingContext.DELEGATED_PROPERTY_CALL, getter);
1767                return call != null ? call.getExplicitReceiver().getType() : null;
1768            }
1769            return null;
1770        }
1771    
1772        @NotNull
1773        public StackValue intermediateValueForProperty(
1774                @NotNull PropertyDescriptor propertyDescriptor,
1775                boolean forceField,
1776                @Nullable JetSuperExpression superExpression
1777        ) {
1778            return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, MethodKind.GENERAL);
1779        }
1780    
1781        public StackValue.StackValueWithSimpleReceiver intermediateValueForProperty(
1782                @NotNull PropertyDescriptor propertyDescriptor,
1783                boolean forceField,
1784                @Nullable JetSuperExpression superExpression,
1785                @NotNull MethodKind methodKind
1786        ) {
1787            JetTypeMapper typeMapper = state.getTypeMapper();
1788    
1789            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
1790    
1791            boolean isBackingFieldInAnotherClass = AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor);
1792            boolean isStatic = containingDeclaration instanceof NamespaceDescriptor || isBackingFieldInAnotherClass;
1793            boolean isSuper = superExpression != null;
1794            boolean isInsideClass = isCallInsideSameClassAsDeclared(propertyDescriptor, context);
1795            boolean isInsideModule = isCallInsideSameModuleAsDeclared(propertyDescriptor, context);
1796    
1797            JetType delegateType = getPropertyDelegateType(propertyDescriptor, state.getBindingContext());
1798            boolean isDelegatedProperty = delegateType != null;
1799    
1800    
1801            CallableMethod callableGetter = null;
1802            CallableMethod callableSetter = null;
1803    
1804            boolean skipPropertyAccessors = forceField && !isBackingFieldInAnotherClass;
1805    
1806            CodegenContext backingFieldContext = context.getParentContext();
1807    
1808            if (isBackingFieldInAnotherClass && forceField) {
1809                //delegate call to classObject owner : OWNER
1810                backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration());
1811                int flags = AsmUtil.getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegatedProperty);
1812                skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || methodKind == MethodKind.SYNTHETIC_ACCESSOR || methodKind == MethodKind.INITIALIZER;
1813                if (!skipPropertyAccessors) {
1814                    propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor);
1815                }
1816            }
1817    
1818            if (!skipPropertyAccessors) {
1819                if (couldUseDirectAccessToProperty(propertyDescriptor, true, isInsideClass, isDelegatedProperty)) {
1820                    callableGetter = null;
1821                }
1822                else {
1823                    if (isSuper && !isInterface(containingDeclaration)) {
1824                        ClassDescriptor owner = getSuperCallLabelTarget(superExpression, state.getBindingContext(), context);
1825                        CodegenContext c = context.findParentContextWithDescriptor(owner);
1826                        assert c != null : "Couldn't find a context for a super-call: " + propertyDescriptor;
1827                        if (c != context.getParentContext()) {
1828                            propertyDescriptor = (PropertyDescriptor) c.getAccessor(propertyDescriptor);
1829                        }
1830                    }
1831    
1832                    propertyDescriptor = accessiblePropertyDescriptor(propertyDescriptor);
1833    
1834                    PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
1835                    if (getter != null) {
1836                        callableGetter = typeMapper.mapToCallableMethod(
1837                                getter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, isInsideClass, isInsideModule,
1838                                OwnerKind.IMPLEMENTATION);
1839                    }
1840                }
1841    
1842                if (propertyDescriptor.isVar()) {
1843                    PropertySetterDescriptor setter = propertyDescriptor.getSetter();
1844                    if (setter != null) {
1845                        if (couldUseDirectAccessToProperty(propertyDescriptor, false, isInsideClass, isDelegatedProperty)) {
1846                            callableSetter = null;
1847                        }
1848                        else {
1849                            callableSetter = typeMapper.mapToCallableMethod(
1850                                    setter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, isInsideClass, isInsideModule,
1851                                    OwnerKind.IMPLEMENTATION);
1852                        }
1853                    }
1854                }
1855            }
1856    
1857            Type owner;
1858            CallableMethod callableMethod = callableGetter != null ? callableGetter : callableSetter;
1859    
1860            propertyDescriptor = unwrapFakeOverride(propertyDescriptor);
1861            if (callableMethod == null) {
1862                owner = typeMapper.getOwner(isBackingFieldInAnotherClass ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor,
1863                                            context.getContextKind(), isInsideModule);
1864            }
1865            else {
1866                owner = callableMethod.getOwner();
1867            }
1868    
1869            String name;
1870            if (propertyDescriptor.getContainingDeclaration() == backingFieldContext.getContextDescriptor()) {
1871                assert backingFieldContext instanceof FieldOwnerContext : "Actual context is " + backingFieldContext + " but should be instance of FieldOwnerContext" ;
1872                name = ((FieldOwnerContext) backingFieldContext).getFieldName(propertyDescriptor, isDelegatedProperty);
1873            } else {
1874                name = JvmAbi.getDefaultPropertyName(propertyDescriptor.getName(), isDelegatedProperty, propertyDescriptor.getReceiverParameter() != null);
1875            }
1876    
1877            return StackValue.property(propertyDescriptor, owner,
1878                                typeMapper.mapType(isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
1879                                isStatic, name, callableGetter, callableSetter, state);
1880    
1881        }
1882    
1883        @Override
1884        public StackValue visitCallExpression(@NotNull JetCallExpression expression, StackValue receiver) {
1885            JetExpression callee = expression.getCalleeExpression();
1886            assert callee != null;
1887    
1888            ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, callee);
1889            if (resolvedCall == null) {
1890                throw new CompilationException("Cannot resolve: " + callee.getText(), null, expression);
1891            }
1892    
1893            DeclarationDescriptor funDescriptor = resolvedCall.getResultingDescriptor();
1894    
1895            if (!(funDescriptor instanceof FunctionDescriptor)) {
1896                throw new UnsupportedOperationException("unknown type of callee descriptor: " + funDescriptor);
1897            }
1898    
1899            funDescriptor = accessibleFunctionDescriptor((FunctionDescriptor) funDescriptor);
1900    
1901            if (funDescriptor instanceof ConstructorDescriptor) {
1902                return generateNewCall(expression, resolvedCall, receiver);
1903            }
1904    
1905            Call call = bindingContext.get(CALL, expression.getCalleeExpression());
1906            if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
1907                VariableAsFunctionResolvedCall variableAsFunctionResolvedCall = (VariableAsFunctionResolvedCall) resolvedCall;
1908                ResolvedCallWithTrace<FunctionDescriptor> functionCall = variableAsFunctionResolvedCall.getFunctionCall();
1909                return invokeFunction(call, receiver, functionCall);
1910            }
1911    
1912            if (funDescriptor instanceof SimpleFunctionDescriptor) {
1913                SimpleFunctionDescriptor original = ((SimpleFunctionDescriptor) funDescriptor).getOriginal();
1914                if (original instanceof SamConstructorDescriptor) {
1915                    return invokeSamConstructor(expression, resolvedCall, ((SamConstructorDescriptor) original).getBaseForSynthesized());
1916                }
1917            }
1918    
1919            return invokeFunction(call, receiver, resolvedCall);
1920        }
1921    
1922        private StackValue invokeSamConstructor(
1923                JetCallExpression expression,
1924                ResolvedCall<? extends CallableDescriptor> resolvedCall,
1925                ClassDescriptorFromJvmBytecode samInterface
1926        ) {
1927            ResolvedValueArgument argument = resolvedCall.getValueArgumentsByIndex().get(0);
1928            if (!(argument instanceof ExpressionValueArgument)) {
1929                throw new IllegalStateException(
1930                        "argument of SAM constructor is " + argument.getClass().getName() + " " + expression.getText());
1931            }
1932            ValueArgument valueArgument = ((ExpressionValueArgument) argument).getValueArgument();
1933            assert valueArgument != null : "getValueArgument() is null for " + expression.getText();
1934            JetExpression argumentExpression = valueArgument.getArgumentExpression();
1935            assert argumentExpression != null : "getArgumentExpression() is null for " + expression.getText();
1936    
1937            return genSamInterfaceValue(argumentExpression, samInterface, this);
1938        }
1939    
1940        private StackValue genSamInterfaceValue(
1941                @NotNull JetExpression expression,
1942                @NotNull ClassDescriptorFromJvmBytecode samInterface,
1943                @NotNull JetVisitor<StackValue, StackValue> visitor
1944        ) {
1945            if (expression instanceof JetFunctionLiteralExpression) {
1946                return genClosure(((JetFunctionLiteralExpression) expression).getFunctionLiteral(), samInterface);
1947            }
1948            else {
1949                Type asmType = state.getSamWrapperClasses().getSamWrapperClass(samInterface, (JetFile) expression.getContainingFile());
1950    
1951                v.anew(asmType);
1952                v.dup();
1953    
1954                Type functionType = typeMapper.mapType(samInterface.getFunctionTypeForSamInterface());
1955                expression.accept(visitor, StackValue.none()).put(functionType, v);
1956    
1957                Label ifNonNull = new Label();
1958                Label afterAll = new Label();
1959    
1960                v.dup();
1961                v.ifnonnull(ifNonNull);
1962    
1963                // if null: pop function value and wrapper objects, put null
1964                v.pop();
1965                v.pop2();
1966                v.aconst(null);
1967                v.goTo(afterAll);
1968    
1969                v.mark(ifNonNull);
1970                v.invokespecial(asmType.getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, functionType));
1971    
1972                v.mark(afterAll);
1973                return StackValue.onStack(asmType);
1974            }
1975        }
1976    
1977        @NotNull
1978        private PropertyDescriptor accessiblePropertyDescriptor(PropertyDescriptor propertyDescriptor) {
1979            return context.accessiblePropertyDescriptor(propertyDescriptor);
1980        }
1981    
1982        @NotNull
1983        protected FunctionDescriptor accessibleFunctionDescriptor(FunctionDescriptor fd) {
1984            return context.accessibleFunctionDescriptor(fd);
1985        }
1986    
1987        @NotNull
1988        public StackValue invokeFunction(
1989                Call call,
1990                StackValue receiver,
1991                ResolvedCall<? extends CallableDescriptor> resolvedCall
1992        ) {
1993            FunctionDescriptor fd = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
1994            boolean superCall = isSuperCall(call);
1995    
1996            if (superCall && !isInterface(fd.getContainingDeclaration())) {
1997                JetSuperExpression expression = getSuperCallExpression(call);
1998                ClassDescriptor owner = getSuperCallLabelTarget(expression);
1999                CodegenContext c = context.findParentContextWithDescriptor(owner);
2000                assert c != null : "Couldn't find a context for a super-call: " + fd;
2001                if (c != context.getParentContext()) {
2002                    fd = (FunctionDescriptor) c.getAccessor(fd);
2003                }
2004            }
2005    
2006            fd = accessibleFunctionDescriptor(fd);
2007    
2008            Callable callable = resolveToCallable(fd, superCall);
2009            if (callable instanceof CallableMethod) {
2010                CallableMethod callableMethod = (CallableMethod) callable;
2011                invokeMethodWithArguments(callableMethod, resolvedCall, call, receiver);
2012    
2013                Type callReturnType = callableMethod.getSignature().getAsmMethod().getReturnType();
2014                return returnValueAsStackValue(fd, callReturnType);
2015            }
2016            else {
2017                receiver = StackValue.receiver(resolvedCall, receiver, this, null);
2018    
2019                IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
2020                List<JetExpression> args = new ArrayList<JetExpression>();
2021                for (ValueArgument argument : call.getValueArguments()) {
2022                    args.add(argument.getArgumentExpression());
2023                }
2024                JetType type = resolvedCall.getResultingDescriptor().getReturnType();
2025                assert type != null;
2026                Type callType = typeMapper.mapType(type);
2027    
2028                Type exprType = asmTypeOrVoid(type);
2029                StackValue stackValue = intrinsic.generate(this, v, callType, call.getCallElement(), args, receiver, state);
2030                stackValue.put(exprType, v);
2031                return StackValue.onStack(exprType);
2032            }
2033        }
2034    
2035        @Nullable
2036        private static JetSuperExpression getSuperCallExpression(@NotNull Call call) {
2037            ReceiverValue explicitReceiver = call.getExplicitReceiver();
2038            if (explicitReceiver instanceof ExpressionReceiver) {
2039                JetExpression receiverExpression = ((ExpressionReceiver) explicitReceiver).getExpression();
2040                if (receiverExpression instanceof JetSuperExpression) {
2041                    return (JetSuperExpression) receiverExpression;
2042                }
2043            }
2044            return null;
2045        }
2046    
2047        private static boolean isSuperCall(@NotNull Call call) {
2048            return getSuperCallExpression(call) != null;
2049        }
2050    
2051        // Find the first parent of the current context which corresponds to a subclass of a given class
2052        @NotNull
2053        private static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) {
2054            CodegenContext c = context;
2055            while (true) {
2056                if (c instanceof ClassContext && DescriptorUtils.isSubclass(c.getThisDescriptor(), descriptor)) {
2057                    return c;
2058                }
2059                c = c.getParentContext();
2060                assert c != null;
2061            }
2062        }
2063    
2064        @NotNull
2065        private StackValue returnValueAsStackValue(FunctionDescriptor fd, Type callReturnType) {
2066            if (callReturnType != Type.VOID_TYPE) {
2067                JetType type = fd.getReturnType();
2068                assert type != null;
2069                Type retType = typeMapper.mapReturnType(type);
2070                StackValue.coerce(callReturnType, retType, v);
2071                return StackValue.onStack(retType);
2072            }
2073            return StackValue.none();
2074        }
2075    
2076        @NotNull
2077        Callable resolveToCallable(@NotNull FunctionDescriptor fd, boolean superCall) {
2078            IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(fd);
2079            if (intrinsic != null) {
2080                return intrinsic;
2081            }
2082    
2083            return resolveToCallableMethod(fd, superCall, context);
2084        }
2085    
2086        @NotNull
2087        private CallableMethod resolveToCallableMethod(@NotNull FunctionDescriptor fd, boolean superCall, @NotNull CodegenContext context) {
2088            if (isCallAsFunctionObject(fd)) {
2089                return typeMapper.mapToFunctionInvokeCallableMethod(createInvoke(fd));
2090            }
2091            else {
2092                SimpleFunctionDescriptor originalOfSamAdapter = (SimpleFunctionDescriptor) SamCodegenUtil.getOriginalIfSamAdapter(fd);
2093                return typeMapper.mapToCallableMethod(originalOfSamAdapter != null ? originalOfSamAdapter : fd, superCall,
2094                                                      isCallInsideSameClassAsDeclared(fd, context),
2095                                                      isCallInsideSameModuleAsDeclared(fd, context),
2096                                                      OwnerKind.IMPLEMENTATION);
2097            }
2098        }
2099    
2100        private boolean isCallAsFunctionObject(FunctionDescriptor fd) {
2101            if (fd instanceof ExpressionAsFunctionDescriptor) {
2102                JetExpression deparenthesize = JetPsiUtil.deparenthesize(((ExpressionAsFunctionDescriptor) fd).getExpression());
2103                return !(deparenthesize instanceof JetCallableReferenceExpression || deparenthesize instanceof JetFunctionLiteralExpression);
2104            }
2105            return false;
2106        }
2107    
2108    
2109        public void invokeMethodWithArguments(
2110                @NotNull CallableMethod callableMethod,
2111                @NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
2112                @Nullable Call callToGenerateCallee,
2113                @NotNull StackValue receiver
2114        ) {
2115            Type calleeType = callableMethod.getGenerateCalleeType();
2116            if (calleeType != null) {
2117                assert !callableMethod.isNeedsThis();
2118                assert callToGenerateCallee != null : "Call can't be null when generating callee: " + resolvedCall.getResultingDescriptor();
2119                gen(callToGenerateCallee.getCalleeExpression(), calleeType);
2120            }
2121    
2122            if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
2123                resolvedCall = ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall();
2124            }
2125    
2126            if (!(resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor)) { // otherwise already
2127                receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
2128                receiver.put(receiver.type, v);
2129            }
2130    
2131            pushArgumentsAndInvoke(resolvedCall, callableMethod);
2132        }
2133    
2134        private void pushArgumentsAndInvoke(@NotNull ResolvedCall<?> resolvedCall, @NotNull CallableMethod callable) {
2135            int mask = pushMethodArguments(resolvedCall, callable.getValueParameterTypes());
2136            if (mask == 0) {
2137                callable.invokeWithNotNullAssertion(v, state, resolvedCall);
2138            }
2139            else {
2140                callable.invokeDefaultWithNotNullAssertion(v, state, resolvedCall, mask);
2141            }
2142        }
2143    
2144        private void genThisAndReceiverFromResolvedCall(
2145                StackValue receiver,
2146                ResolvedCall<? extends CallableDescriptor> resolvedCall,
2147                CallableMethod callableMethod
2148        ) {
2149            receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
2150            receiver.put(receiver.type, v);
2151        }
2152    
2153        public void generateFromResolvedCall(@NotNull ReceiverValue descriptor, @NotNull Type type) {
2154            if (descriptor instanceof ClassReceiver) {
2155                Type exprType = asmType(descriptor.getType());
2156                ClassReceiver classReceiver = (ClassReceiver) descriptor;
2157                ClassDescriptor classReceiverDeclarationDescriptor = classReceiver.getDeclarationDescriptor();
2158                if (DescriptorUtils.isClassObject(classReceiverDeclarationDescriptor)) {
2159                    if (context.getContextDescriptor() instanceof FunctionDescriptor &&
2160                        classReceiverDeclarationDescriptor == context.getContextDescriptor().getContainingDeclaration()) {
2161                        v.load(0, OBJECT_TYPE);
2162                    }
2163                    else {
2164                        FieldInfo info = FieldInfo.createForSingleton(classReceiverDeclarationDescriptor, typeMapper);
2165                        v.getstatic(info.getOwnerInternalName(), info.getFieldName(), info.getFieldType().getDescriptor());
2166                    }
2167                    StackValue.onStack(exprType).put(type, v);
2168                }
2169                else {
2170                    StackValue.thisOrOuter(this, classReceiverDeclarationDescriptor, false).put(type, v);
2171                }
2172            }
2173            else if (descriptor instanceof ScriptReceiver) {
2174                generateScript((ScriptReceiver) descriptor);
2175            }
2176            else if (descriptor instanceof ExtensionReceiver) {
2177                ExtensionReceiver extensionReceiver = (ExtensionReceiver) descriptor;
2178                generateReceiver(extensionReceiver.getDeclarationDescriptor()).put(type, v);
2179            }
2180            else if (descriptor instanceof ExpressionReceiver) {
2181                ExpressionReceiver expressionReceiver = (ExpressionReceiver) descriptor;
2182                JetExpression expr = expressionReceiver.getExpression();
2183                gen(expr, type);
2184            }
2185            else if (descriptor instanceof AutoCastReceiver) {
2186                AutoCastReceiver autoCastReceiver = (AutoCastReceiver) descriptor;
2187                Type originalType = asmType(autoCastReceiver.getOriginal().getType());
2188                generateFromResolvedCall(autoCastReceiver.getOriginal(), originalType);
2189                StackValue.onStack(originalType).put(type, v);
2190            }
2191            else {
2192                throw new UnsupportedOperationException("Unsupported receiver type: " + descriptor);
2193            }
2194        }
2195    
2196        @Nullable
2197        private static JetExpression getReceiverForSelector(PsiElement expression) {
2198            if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) {
2199                JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
2200                return parent.getReceiverExpression();
2201            }
2202            return null;
2203        }
2204    
2205        private StackValue generateReceiver(DeclarationDescriptor provided) {
2206            if (context.getCallableDescriptorWithReceiver() == provided) {
2207                StackValue result = context.getReceiverExpression(typeMapper);
2208                return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null);
2209            }
2210    
2211            StackValue result = context.lookupInContext(provided, StackValue.local(0, OBJECT_TYPE), state, false);
2212            return castToRequiredTypeOfInterfaceIfNeeded(result, provided, null);
2213        }
2214    
2215        private void generateScript(@NotNull ScriptReceiver receiver) {
2216            CodegenContext cur = context;
2217            StackValue result = StackValue.local(0, OBJECT_TYPE);
2218            while (cur != null) {
2219                if (cur instanceof MethodContext && !(cur instanceof ConstructorContext)) {
2220                    cur = cur.getParentContext();
2221                }
2222    
2223                if (cur instanceof ScriptContext) {
2224                    ScriptContext scriptContext = (ScriptContext) cur;
2225    
2226                    Type currentScriptType = asmTypeForScriptDescriptor(bindingContext, scriptContext.getScriptDescriptor());
2227                    if (scriptContext.getScriptDescriptor() == receiver.getDeclarationDescriptor()) {
2228                        result.put(currentScriptType, v);
2229                    }
2230                    else {
2231                        Type classType = asmTypeForScriptDescriptor(bindingContext, receiver.getDeclarationDescriptor());
2232                        String fieldName = getParentScriptCodegen().getScriptFieldName(receiver.getDeclarationDescriptor());
2233                        result.put(currentScriptType, v);
2234                        StackValue.field(classType, currentScriptType, fieldName, false).put(classType, v);
2235                    }
2236                    return;
2237                }
2238    
2239                assert cur != null;
2240                result = cur.getOuterExpression(result, false);
2241    
2242                if (cur instanceof ConstructorContext) {
2243                    cur = cur.getParentContext();
2244                }
2245                assert cur != null;
2246                cur = cur.getParentContext();
2247            }
2248    
2249            throw new UnsupportedOperationException();
2250        }
2251    
2252        public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) {
2253            boolean isSingleton = CodegenBinding.isSingleton(bindingContext, calleeContainingClass);
2254            if (isSingleton) {
2255                assert !isSuper;
2256    
2257                if (context.hasThisDescriptor() && context.getThisDescriptor().equals(calleeContainingClass)) {
2258                    return StackValue.local(0, typeMapper.mapType(calleeContainingClass));
2259                }
2260                else {
2261                    return StackValue.singleton(calleeContainingClass, typeMapper);
2262                }
2263            }
2264    
2265            CodegenContext cur = context;
2266            Type type = asmType(calleeContainingClass.getDefaultType());
2267            StackValue result = StackValue.local(0, type);
2268            while (cur != null) {
2269                if (cur instanceof MethodContext && !(cur instanceof ConstructorContext)) {
2270                    cur = cur.getParentContext();
2271                }
2272    
2273                assert cur != null;
2274                ClassDescriptor thisDescriptor = cur.getThisDescriptor();
2275                if (!isSuper && thisDescriptor.equals(calleeContainingClass)
2276                || isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) {
2277                    return castToRequiredTypeOfInterfaceIfNeeded(result, thisDescriptor, calleeContainingClass);
2278                }
2279    
2280                result = cur.getOuterExpression(result, false);
2281    
2282                if (cur instanceof ConstructorContext) {
2283                    cur = cur.getParentContext();
2284                }
2285                assert cur != null;
2286                cur = cur.getParentContext();
2287            }
2288    
2289            throw new UnsupportedOperationException();
2290        }
2291    
2292        private static boolean isReceiver(PsiElement expression) {
2293            PsiElement parent = expression.getParent();
2294            if (parent instanceof JetQualifiedExpression) {
2295                JetExpression receiverExpression = ((JetQualifiedExpression) parent).getReceiverExpression();
2296                return expression == receiverExpression;
2297            }
2298            return false;
2299        }
2300    
2301        private int pushMethodArguments(@NotNull ResolvedCall resolvedCall, List<Type> valueParameterTypes) {
2302            @SuppressWarnings("unchecked")
2303            List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
2304            CallableDescriptor fd = resolvedCall.getResultingDescriptor();
2305    
2306            if (fd.getValueParameters().size() != valueArguments.size()) {
2307                throw new IllegalStateException();
2308            }
2309    
2310            int mask = 0;
2311    
2312            for (ValueParameterDescriptor valueParameter : fd.getValueParameters()) {
2313                ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex());
2314                Type parameterType = valueParameterTypes.get(valueParameter.getIndex());
2315                if (resolvedValueArgument instanceof ExpressionValueArgument) {
2316                    ValueArgument valueArgument = ((ExpressionValueArgument) resolvedValueArgument).getValueArgument();
2317                    assert valueArgument != null;
2318                    JetExpression argumentExpression = valueArgument.getArgumentExpression();
2319                    assert argumentExpression != null : valueArgument.asElement().getText();
2320    
2321                    gen(argumentExpression, parameterType);
2322                }
2323                else if (resolvedValueArgument instanceof DefaultValueArgument) {
2324                    pushDefaultValueOnStack(parameterType, v);
2325                    mask |= (1 << valueParameter.getIndex());
2326                }
2327                else if (resolvedValueArgument instanceof VarargValueArgument) {
2328                    VarargValueArgument valueArgument = (VarargValueArgument) resolvedValueArgument;
2329                    genVarargs(valueParameter, valueArgument);
2330                }
2331                else {
2332                    throw new UnsupportedOperationException();
2333                }
2334            }
2335            return mask;
2336        }
2337    
2338        public void genVarargs(ValueParameterDescriptor valueParameterDescriptor, VarargValueArgument valueArgument) {
2339            JetType outType = valueParameterDescriptor.getType();
2340    
2341            Type type = asmType(outType);
2342            assert type.getSort() == Type.ARRAY;
2343            Type elementType = correctElementType(type);
2344            List<ValueArgument> arguments = valueArgument.getArguments();
2345            int size = arguments.size();
2346    
2347            boolean hasSpread = false;
2348            for (int i = 0; i != size; ++i) {
2349                if (arguments.get(i).getSpreadElement() != null) {
2350                    hasSpread = true;
2351                    break;
2352                }
2353            }
2354    
2355            if (hasSpread) {
2356                if (size == 1) {
2357                    gen(arguments.get(0).getArgumentExpression(), type);
2358                }
2359                else {
2360                    String owner = "jet/runtime/Intrinsics$SpreadBuilder";
2361                    v.anew(Type.getObjectType(owner));
2362                    v.dup();
2363                    v.invokespecial(owner, "<init>", "()V");
2364                    for (int i = 0; i != size; ++i) {
2365                        v.dup();
2366                        ValueArgument argument = arguments.get(i);
2367                        if (argument.getSpreadElement() != null) {
2368                            gen(argument.getArgumentExpression(), OBJECT_TYPE);
2369                            v.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V");
2370                        }
2371                        else {
2372                            gen(argument.getArgumentExpression(), elementType);
2373                            v.invokevirtual(owner, "add", "(Ljava/lang/Object;)Z");
2374                            v.pop();
2375                        }
2376                    }
2377                    v.dup();
2378                    v.invokevirtual(owner, "size", "()I");
2379                    v.newarray(elementType);
2380                    v.invokevirtual(owner, "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;");
2381                    v.checkcast(type);
2382                }
2383            }
2384            else {
2385                v.iconst(arguments.size());
2386                v.newarray(elementType);
2387                for (int i = 0; i != size; ++i) {
2388                    v.dup();
2389                    v.iconst(i);
2390                    gen(arguments.get(i).getArgumentExpression(), elementType);
2391                    StackValue.arrayElement(elementType, false).store(elementType, v);
2392                }
2393            }
2394        }
2395    
2396        public int pushMethodArguments(JetCallElement expression, List<Type> valueParameterTypes) {
2397            ResolvedCall<? extends CallableDescriptor> resolvedCall =
2398                    bindingContext.get(BindingContext.RESOLVED_CALL, expression.getCalleeExpression());
2399            if (resolvedCall != null) {
2400                return pushMethodArguments(resolvedCall, valueParameterTypes);
2401            }
2402            else {
2403                List<? extends ValueArgument> args = expression.getValueArguments();
2404                for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
2405                    ValueArgument arg = args.get(i);
2406                    gen(arg.getArgumentExpression(), valueParameterTypes.get(i));
2407                }
2408                return 0;
2409            }
2410        }
2411    
2412        @NotNull
2413        public Type expressionType(JetExpression expr) {
2414            return typeMapper.expressionType(expr);
2415        }
2416    
2417        public int indexOfLocal(JetReferenceExpression lhs) {
2418            DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, lhs);
2419            if (isVarCapturedInClosure(bindingContext, declarationDescriptor)) {
2420                return -1;
2421            }
2422            return lookupLocalIndex(declarationDescriptor);
2423        }
2424    
2425        @Override
2426        public StackValue visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, StackValue data) {
2427            // TODO: properties
2428            final FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
2429            assert functionDescriptor != null : "Callable reference is not resolved to descriptor: " + expression.getText();
2430    
2431            final ResolvedCall<? extends CallableDescriptor> resolvedCall = bindingContext.get(RESOLVED_CALL, expression.getCallableReference());
2432            assert resolvedCall != null : "Callable reference is not resolved: " + functionDescriptor + " " + expression.getText();
2433    
2434            JetType kFunctionType = bindingContext.get(EXPRESSION_TYPE, expression);
2435            assert kFunctionType != null : "Callable reference is not type checked: " + expression.getText();
2436            ClassDescriptor kFunctionImpl = functionTypeToImpl(kFunctionType);
2437            assert kFunctionImpl != null : "Impl type is not found for the function type: " + kFunctionType;
2438    
2439            Type closureSuperClass = typeMapper.mapType(kFunctionImpl);
2440    
2441            ClosureCodegen closureCodegen = new ClosureCodegen(state, expression, functionDescriptor, null, closureSuperClass, context, this,
2442                    new FunctionGenerationStrategy.CodegenBased<CallableDescriptor>(state, functionDescriptor) {
2443    
2444                        @NotNull
2445                        @Override
2446                        public ExpressionCodegen initializeExpressionCodegen(
2447                                JvmMethodSignature signature, MethodContext context, MethodVisitor mv,
2448                                Type returnType,
2449                                MemberCodegen parentCodegen
2450                        ) {
2451                            FunctionDescriptor referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
2452                            JetType returnJetType = referencedFunction.getReturnType();
2453                            assert returnJetType != null : "Return type can't be null: " + referencedFunction;
2454    
2455                            return super.initializeExpressionCodegen(signature, context,
2456                                                              mv, typeMapper.mapReturnType(returnJetType), parentCodegen);
2457                        }
2458    
2459                        @Override
2460                        public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
2461                            /*
2462                             Here we need to put the arguments from our locals to the stack and invoke the referenced method. Since invocation
2463                             of methods is highly dependent on expressions, we create a fake call expression. Then we create a new instance of
2464                             ExpressionCodegen and, in order for it to generate code correctly, we save to its 'tempVariables' field every
2465                             argument of our fake expression, pointing it to the corresponding index in our locals. This way generation of
2466                             every argument boils down to calling LOAD with the corresponding index
2467                             */
2468    
2469                            FunctionDescriptor referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
2470    
2471                            JetCallExpression fakeExpression = constructFakeFunctionCall(referencedFunction);
2472                            final List<? extends ValueArgument> fakeArguments = fakeExpression.getValueArguments();
2473    
2474                            final ReceiverValue receiverValue = computeAndSaveReceiver(signature, codegen);
2475                            computeAndSaveArguments(codegen.myFrameMap, fakeArguments, codegen);
2476    
2477                            ResolvedCall<CallableDescriptor> fakeResolvedCall = new DelegatingResolvedCall<CallableDescriptor>(resolvedCall) {
2478                                @NotNull
2479                                @Override
2480                                public ReceiverValue getReceiverArgument() {
2481                                    return resolvedCall.getExplicitReceiverKind() == RECEIVER_ARGUMENT ? receiverValue : NO_RECEIVER;
2482                                }
2483    
2484                                @NotNull
2485                                @Override
2486                                public ReceiverValue getThisObject() {
2487                                    return resolvedCall.getExplicitReceiverKind() == THIS_OBJECT ? receiverValue : NO_RECEIVER;
2488                                }
2489    
2490                                @NotNull
2491                                @Override
2492                                public List<ResolvedValueArgument> getValueArgumentsByIndex() {
2493                                    List<ResolvedValueArgument> result = new ArrayList<ResolvedValueArgument>(fakeArguments.size());
2494                                    for (ValueArgument argument : fakeArguments) {
2495                                        result.add(new ExpressionValueArgument(argument));
2496                                    }
2497                                    return result;
2498                                }
2499                            };
2500    
2501                            StackValue result;
2502                            Type returnType = codegen.returnType;
2503                            if (referencedFunction instanceof ConstructorDescriptor) {
2504                                if (returnType.getSort() == Type.ARRAY) {
2505                                    JetType returnJetType = referencedFunction.getReturnType();
2506                                    assert returnJetType != null;
2507                                    codegen.generateNewArray(fakeExpression, returnJetType);
2508                                    result = StackValue.onStack(returnType);
2509                                }
2510                                else {
2511                                    result = codegen.generateConstructorCall(fakeResolvedCall, StackValue.none(), returnType);
2512                                }
2513                            }
2514                            else {
2515                                Call call = CallMaker.makeCall(fakeExpression, NO_RECEIVER, null, fakeExpression, fakeArguments);
2516                                result = codegen.invokeFunction(call, StackValue.none(), fakeResolvedCall);
2517                            }
2518    
2519                            InstructionAdapter v = codegen.v;
2520                            result.put(returnType, v);
2521                            v.areturn(returnType);
2522                        }
2523    
2524                        @NotNull
2525                        private JetCallExpression constructFakeFunctionCall(@NotNull CallableDescriptor referencedFunction) {
2526                            StringBuilder fakeFunctionCall = new StringBuilder("callableReferenceFakeCall(");
2527                            for (Iterator<ValueParameterDescriptor> iterator = referencedFunction.getValueParameters().iterator();
2528                                 iterator.hasNext(); ) {
2529                                ValueParameterDescriptor descriptor = iterator.next();
2530                                fakeFunctionCall.append("p").append(descriptor.getIndex());
2531                                if (iterator.hasNext()) {
2532                                    fakeFunctionCall.append(", ");
2533                                }
2534                            }
2535                            fakeFunctionCall.append(")");
2536                            return (JetCallExpression) JetPsiFactory.createExpression(state.getProject(), fakeFunctionCall.toString());
2537                        }
2538    
2539                        private void computeAndSaveArguments(
2540                                @NotNull FrameMap frameMap,
2541                                @NotNull List<? extends ValueArgument> fakeArguments,
2542                                @NotNull ExpressionCodegen codegen
2543                        ) {
2544                            for (ValueParameterDescriptor parameter : functionDescriptor.getValueParameters()) {
2545                                ValueArgument fakeArgument = fakeArguments.get(parameter.getIndex());
2546                                Type type = typeMapper.mapType(parameter);
2547                                int localIndex = frameMap.getIndex(parameter);
2548                                codegen.tempVariables.put(fakeArgument.getArgumentExpression(), StackValue.local(localIndex, type));
2549                            }
2550                        }
2551    
2552                        @NotNull
2553                        private ReceiverValue computeAndSaveReceiver(
2554                                @NotNull JvmMethodSignature signature,
2555                                @NotNull ExpressionCodegen codegen
2556                        ) {
2557                            CallableDescriptor referencedFunction = resolvedCall.getCandidateDescriptor();
2558    
2559                            ReceiverParameterDescriptor receiverParameter = referencedFunction.getReceiverParameter();
2560                            ReceiverParameterDescriptor expectedThisObject = referencedFunction.getExpectedThisObject();
2561                            assert receiverParameter == null || expectedThisObject == null :
2562                                    "Extensions in classes can't be referenced via callable reference expressions: " + referencedFunction;
2563    
2564                            ReceiverParameterDescriptor receiver = receiverParameter != null ? receiverParameter : expectedThisObject;
2565    
2566                            if (receiver == null) {
2567                                return NO_RECEIVER;
2568                            }
2569    
2570                            JetExpression receiverExpression = JetPsiFactory.createExpression(state.getProject(),
2571                                                                                              "callableReferenceFakeReceiver");
2572    
2573                            Type firstParameterType = signature.getAsmMethod().getArgumentTypes()[0];
2574                            // 0 is this (the closure class), 1 is the method's first parameter
2575                            codegen.tempVariables.put(receiverExpression, StackValue.local(1, firstParameterType));
2576    
2577                            return new ExpressionReceiver(receiverExpression, receiver.getType());
2578                        }
2579                    },
2580                    getParentCodegen());
2581    
2582            closureCodegen.gen();
2583    
2584            return closureCodegen.putInstanceOnStack(v, this);
2585        }
2586    
2587        @Override
2588        public StackValue visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, StackValue receiver) {
2589            StackValue receiverValue = StackValue.none();
2590            return genQualified(receiverValue, expression.getSelectorExpression());
2591        }
2592    
2593        @Override
2594        public StackValue visitSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression, StackValue receiver) {
2595            JetExpression expr = expression.getReceiverExpression();
2596            Type receiverType = expressionType(expr);
2597            gen(expr, receiverType);
2598            if (isPrimitive(receiverType)) {
2599                StackValue propValue = genQualified(StackValue.onStack(receiverType), expression.getSelectorExpression());
2600                Type type = boxType(propValue.type);
2601                propValue.put(type, v);
2602    
2603                return StackValue.onStack(type);
2604            }
2605            else {
2606                Label ifnull = new Label();
2607                Label end = new Label();
2608                v.dup();
2609                v.ifnull(ifnull);
2610                StackValue propValue = genQualified(StackValue.onStack(receiverType), expression.getSelectorExpression());
2611                Type type = boxType(propValue.type);
2612                propValue.put(type, v);
2613                v.goTo(end);
2614    
2615                v.mark(ifnull);
2616                v.pop();
2617                if (!type.equals(Type.VOID_TYPE)) {
2618                    v.aconst(null);
2619                }
2620                v.mark(end);
2621    
2622                return StackValue.onStack(type);
2623            }
2624        }
2625    
2626        @Override
2627        public StackValue visitBinaryExpression(@NotNull JetBinaryExpression expression, StackValue receiver) {
2628            IElementType opToken = expression.getOperationReference().getReferencedNameElementType();
2629            if (opToken == JetTokens.EQ) {
2630                return generateAssignmentExpression(expression);
2631            }
2632            else if (JetTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) {
2633                return generateAugmentedAssignment(expression);
2634            }
2635            else if (opToken == JetTokens.ANDAND) {
2636                return generateBooleanAnd(expression);
2637            }
2638            else if (opToken == JetTokens.OROR) {
2639                return generateBooleanOr(expression);
2640            }
2641            else if (opToken == JetTokens.EQEQ || opToken == JetTokens.EXCLEQ ||
2642                     opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
2643                return generateEquals(expression.getLeft(), expression.getRight(), opToken);
2644            }
2645            else if (opToken == JetTokens.LT || opToken == JetTokens.LTEQ ||
2646                     opToken == JetTokens.GT || opToken == JetTokens.GTEQ) {
2647                return generateComparison(expression);
2648            }
2649            else if (opToken == JetTokens.ELVIS) {
2650                return generateElvis(expression);
2651            }
2652            else if (opToken == JetTokens.IN_KEYWORD || opToken == JetTokens.NOT_IN) {
2653                return generateIn(expression);
2654            }
2655            else {
2656                DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
2657                assert op instanceof FunctionDescriptor : String.valueOf(op);
2658                Callable callable = resolveToCallable((FunctionDescriptor) op, false);
2659                if (callable instanceof IntrinsicMethod) {
2660                    IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
2661                    return intrinsic.generate(this, v, expressionType(expression), expression,
2662                                              Arrays.asList(expression.getLeft(), expression.getRight()), receiver, state);
2663                }
2664                else {
2665                    return invokeOperation(expression, (FunctionDescriptor) op, (CallableMethod) callable);
2666                }
2667            }
2668        }
2669    
2670        private StackValue generateIn(JetBinaryExpression expression) {
2671            boolean inverted = expression.getOperationReference().getReferencedNameElementType() == JetTokens.NOT_IN;
2672            if (isIntRangeExpr(expression.getRight())) {
2673                StackValue leftValue = StackValue.expression(Type.INT_TYPE, expression.getLeft(), this);
2674                JetBinaryExpression rangeExpression = (JetBinaryExpression) expression.getRight();
2675                getInIntRange(leftValue, rangeExpression, inverted);
2676            }
2677            else {
2678                invokeFunctionByReference(expression.getOperationReference());
2679                if (inverted) {
2680                    genInvertBoolean(v);
2681                }
2682            }
2683            return StackValue.onStack(Type.BOOLEAN_TYPE);
2684        }
2685    
2686        private void getInIntRange(StackValue leftValue, JetBinaryExpression rangeExpression, boolean inverted) {
2687            v.iconst(1);
2688            // 1
2689            leftValue.put(Type.INT_TYPE, v);
2690            // 1 l
2691            v.dup2();
2692            // 1 l 1 l
2693    
2694            //noinspection ConstantConditions
2695            gen(rangeExpression.getLeft(), Type.INT_TYPE);
2696            // 1 l 1 l r
2697            Label lok = new Label();
2698            v.ificmpge(lok);
2699            // 1 l 1
2700            v.pop();
2701            v.iconst(0);
2702            v.mark(lok);
2703            // 1 l c
2704            v.dupX2();
2705            // c 1 l c
2706            v.pop();
2707            // c 1 l
2708    
2709            gen(rangeExpression.getRight(), Type.INT_TYPE);
2710            // c 1 l r
2711            Label rok = new Label();
2712            v.ificmple(rok);
2713            // c 1
2714            v.pop();
2715            v.iconst(0);
2716            v.mark(rok);
2717            // c c
2718    
2719            v.and(Type.INT_TYPE);
2720            if (inverted) {
2721                genInvertBoolean(v);
2722            }
2723        }
2724    
2725        private StackValue generateBooleanAnd(JetBinaryExpression expression) {
2726            gen(expression.getLeft(), Type.BOOLEAN_TYPE);
2727            Label ifFalse = new Label();
2728            v.ifeq(ifFalse);
2729            gen(expression.getRight(), Type.BOOLEAN_TYPE);
2730            Label end = new Label();
2731            v.goTo(end);
2732            v.mark(ifFalse);
2733            v.iconst(0);
2734            v.mark(end);
2735            return StackValue.onStack(Type.BOOLEAN_TYPE);
2736        }
2737    
2738        private StackValue generateBooleanOr(JetBinaryExpression expression) {
2739            gen(expression.getLeft(), Type.BOOLEAN_TYPE);
2740            Label ifTrue = new Label();
2741            v.ifne(ifTrue);
2742            gen(expression.getRight(), Type.BOOLEAN_TYPE);
2743            Label end = new Label();
2744            v.goTo(end);
2745            v.mark(ifTrue);
2746            v.iconst(1);
2747            v.mark(end);
2748            return StackValue.onStack(Type.BOOLEAN_TYPE);
2749        }
2750    
2751        private StackValue generateEquals(JetExpression left, JetExpression right, IElementType opToken) {
2752            Type leftType = expressionType(left);
2753            Type rightType = expressionType(right);
2754    
2755            if (JetPsiUtil.isNullConstant(left)) {
2756                return genCmpWithNull(right, rightType, opToken);
2757            }
2758    
2759            if (JetPsiUtil.isNullConstant(right)) {
2760                return genCmpWithNull(left, leftType, opToken);
2761            }
2762    
2763            if (isIntZero(left, leftType) && isIntPrimitive(rightType)) {
2764                return genCmpWithZero(right, rightType, opToken);
2765            }
2766    
2767            if (isIntZero(right, rightType) && isIntPrimitive(leftType)) {
2768                return genCmpWithZero(left, leftType, opToken);
2769            }
2770    
2771            if (isPrimitive(leftType) != isPrimitive(rightType)) {
2772                leftType = boxType(leftType);
2773                gen(left, leftType);
2774                rightType = boxType(rightType);
2775                gen(right, rightType);
2776            }
2777            else {
2778                gen(left, leftType);
2779                gen(right, rightType);
2780            }
2781    
2782            return genEqualsForExpressionsOnStack(v, opToken, leftType, rightType);
2783        }
2784    
2785        private boolean isIntZero(JetExpression expr, Type exprType) {
2786            CompileTimeConstant<?> exprValue = bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expr);
2787            return isIntPrimitive(exprType) && exprValue != null && exprValue.getValue().equals(0);
2788        }
2789    
2790        private StackValue genCmpWithZero(JetExpression exp, Type expType, IElementType opToken) {
2791            v.iconst(1);
2792            gen(exp, expType);
2793            Label ok = new Label();
2794            if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) {
2795                v.ifeq(ok);
2796            }
2797            else {
2798                v.ifne(ok);
2799            }
2800            v.pop();
2801            v.iconst(0);
2802            v.mark(ok);
2803            return StackValue.onStack(Type.BOOLEAN_TYPE);
2804        }
2805    
2806        private StackValue genCmpWithNull(JetExpression exp, Type expType, IElementType opToken) {
2807            v.iconst(1);
2808            gen(exp, boxType(expType));
2809            Label ok = new Label();
2810            if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) {
2811                v.ifnull(ok);
2812            }
2813            else {
2814                v.ifnonnull(ok);
2815            }
2816            v.pop();
2817            v.iconst(0);
2818            v.mark(ok);
2819            return StackValue.onStack(Type.BOOLEAN_TYPE);
2820        }
2821    
2822        private StackValue generateElvis(JetBinaryExpression expression) {
2823            Type exprType = expressionType(expression);
2824            Type leftType = expressionType(expression.getLeft());
2825    
2826            gen(expression.getLeft(), leftType);
2827    
2828            if (isPrimitive(leftType)) {
2829                return StackValue.onStack(leftType);
2830            }
2831    
2832            v.dup();
2833            Label ifNull = new Label();
2834            v.ifnull(ifNull);
2835            StackValue.onStack(leftType).put(exprType, v);
2836            Label end = new Label();
2837            v.goTo(end);
2838            v.mark(ifNull);
2839            v.pop();
2840            gen(expression.getRight(), exprType);
2841            v.mark(end);
2842    
2843            return StackValue.onStack(exprType);
2844        }
2845    
2846        private StackValue generateComparison(JetBinaryExpression expression) {
2847            DeclarationDescriptor target = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
2848            assert target instanceof FunctionDescriptor : "compareTo target should be a function: " + target;
2849            FunctionDescriptor descriptor = (FunctionDescriptor) target;
2850    
2851            JetExpression left = expression.getLeft();
2852            JetExpression right = expression.getRight();
2853            Callable callable = resolveToCallable(descriptor, false);
2854    
2855            Type type;
2856            if (callable instanceof IntrinsicMethod) {
2857                // Compare two primitive values
2858                type = comparisonOperandType(expressionType(left), expressionType(right));
2859                StackValue receiver = gen(left);
2860                receiver.put(type, v);
2861                gen(right, type);
2862            }
2863            else {
2864                type = Type.INT_TYPE;
2865                StackValue result = invokeOperation(expression, descriptor, (CallableMethod) callable);
2866                result.put(type, v);
2867                v.iconst(0);
2868            }
2869            return StackValue.cmp(expression.getOperationToken(), type);
2870        }
2871    
2872        private StackValue generateAssignmentExpression(JetBinaryExpression expression) {
2873            StackValue stackValue = gen(expression.getLeft());
2874            JetExpression right = expression.getRight();
2875            assert right != null : expression.getText();
2876            gen(right, stackValue.type);
2877            stackValue.store(stackValue.type, v);
2878            return StackValue.none();
2879        }
2880    
2881        private StackValue generateAugmentedAssignment(JetBinaryExpression expression) {
2882            DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
2883            assert op instanceof FunctionDescriptor : String.valueOf(op);
2884            Callable callable = resolveToCallable((FunctionDescriptor) op, false);
2885            JetExpression lhs = expression.getLeft();
2886    
2887            //        if (lhs instanceof JetArrayAccessExpression) {
2888            //            JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) lhs;
2889            //            if (arrayAccessExpression.getIndexExpressions().size() != 1) {
2890            //                throw new UnsupportedOperationException("Augmented assignment with multi-index");
2891            //            }
2892            //        }
2893    
2894            Type lhsType = expressionType(lhs);
2895            //noinspection ConstantConditions
2896            if (bindingContext.get(BindingContext.VARIABLE_REASSIGNMENT, expression)) {
2897                if (callable instanceof IntrinsicMethod) {
2898                    StackValue value = gen(lhs);              // receiver
2899                    value.dupReceiver(v);                                        // receiver receiver
2900                    value.put(lhsType, v);                                          // receiver lhs
2901                    IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
2902                    //noinspection NullableProblems
2903                    JetExpression right = expression.getRight();
2904                    assert right != null;
2905                    StackValue stackValue = intrinsic.generate(this, v, lhsType, expression,
2906                                                               Arrays.asList(right),
2907                                                               StackValue.onStack(lhsType), state);
2908                    value.store(stackValue.type, v);
2909                }
2910                else {
2911                    callAugAssignMethod(expression, (CallableMethod) callable, lhsType, true);
2912                }
2913            }
2914            else {
2915                JetType type = ((FunctionDescriptor) op).getReturnType();
2916                assert type != null;
2917                boolean keepReturnValue = !type.equals(KotlinBuiltIns.getInstance().getUnitType());
2918                callAugAssignMethod(expression, (CallableMethod) callable, lhsType, keepReturnValue);
2919            }
2920    
2921            return StackValue.none();
2922        }
2923    
2924        private void callAugAssignMethod(JetBinaryExpression expression, CallableMethod callable, Type lhsType, boolean keepReturnValue) {
2925            ResolvedCall<? extends CallableDescriptor> resolvedCall =
2926                    bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
2927            assert resolvedCall != null;
2928    
2929            StackValue value = gen(expression.getLeft());
2930            if (keepReturnValue) {
2931                value.dupReceiver(v);
2932            }
2933            value.put(lhsType, v);
2934            StackValue receiver = StackValue.onStack(lhsType);
2935    
2936            if (!(resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor)) { // otherwise already
2937                receiver = StackValue.receiver(resolvedCall, receiver, this, callable);
2938                receiver.put(receiver.type, v);
2939            }
2940    
2941            pushArgumentsAndInvoke(resolvedCall, callable);
2942    
2943            if (keepReturnValue) {
2944                value.store(callable.getReturnType(), v);
2945            }
2946        }
2947    
2948        public void invokeAppend(JetExpression expr) {
2949            if (expr instanceof JetBinaryExpression) {
2950                JetBinaryExpression binaryExpression = (JetBinaryExpression) expr;
2951                if (binaryExpression.getOperationToken() == JetTokens.PLUS) {
2952                    JetExpression left = binaryExpression.getLeft();
2953                    JetExpression right = binaryExpression.getRight();
2954                    Type leftType = expressionType(left);
2955                    Type rightType = expressionType(right);
2956    
2957                    if (leftType.equals(JAVA_STRING_TYPE) && rightType.equals(JAVA_STRING_TYPE)) {
2958                        invokeAppend(left);
2959                        invokeAppend(right);
2960                        return;
2961                    }
2962                }
2963            }
2964            Type exprType = expressionType(expr);
2965            gen(expr, exprType);
2966            genInvokeAppendMethod(v, exprType.getSort() == Type.ARRAY ? OBJECT_TYPE : exprType);
2967        }
2968    
2969        @Nullable
2970        private static JetSimpleNameExpression targetLabel(JetExpression expression) {
2971            if (expression.getParent() instanceof JetPrefixExpression) {
2972                JetPrefixExpression parent = (JetPrefixExpression) expression.getParent();
2973                JetSimpleNameExpression operationSign = parent.getOperationReference();
2974                if (JetTokens.LABELS.contains(operationSign.getReferencedNameElementType())) {
2975                    return operationSign;
2976                }
2977            }
2978            return null;
2979        }
2980    
2981        @Override
2982        public StackValue visitPrefixExpression(@NotNull JetPrefixExpression expression, StackValue receiver) {
2983            JetSimpleNameExpression operationSign = expression.getOperationReference();
2984            if (JetTokens.LABELS.contains(operationSign.getReferencedNameElementType())) {
2985                return genQualified(receiver, expression.getBaseExpression());
2986            }
2987    
2988            DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
2989            assert op instanceof FunctionDescriptor : String.valueOf(op);
2990            Callable callable = resolveToCallable((FunctionDescriptor) op, false);
2991            if (callable instanceof IntrinsicMethod) {
2992                IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
2993                //noinspection ConstantConditions
2994                return intrinsic.generate(this, v, expressionType(expression), expression,
2995                                          Arrays.asList(expression.getBaseExpression()), receiver, state);
2996            }
2997            else {
2998                DeclarationDescriptor cls = op.getContainingDeclaration();
2999                CallableMethod callableMethod = (CallableMethod) callable;
3000                if (isPrimitiveNumberClassDescriptor(cls) || !(op.getName().asString().equals("inc") || op.getName().asString().equals("dec"))) {
3001                    return invokeOperation(expression, (FunctionDescriptor) op, callableMethod);
3002                }
3003                else {
3004                    ResolvedCall<? extends CallableDescriptor> resolvedCall =
3005                            bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
3006                    assert resolvedCall != null;
3007    
3008                    StackValue value = gen(expression.getBaseExpression());
3009                    value.dupReceiver(v);
3010                    value.dupReceiver(v);
3011    
3012                    Type type = expressionType(expression.getBaseExpression());
3013                    value.put(type, v);
3014                    callableMethod.invokeWithNotNullAssertion(v, state, resolvedCall);
3015    
3016                    value.store(callableMethod.getReturnType(), v);
3017                    value.put(type, v);
3018                    return StackValue.onStack(type);
3019                }
3020            }
3021        }
3022    
3023        private StackValue invokeOperation(JetOperationExpression expression, FunctionDescriptor op, CallableMethod callable) {
3024            int functionLocalIndex = lookupLocalIndex(op);
3025            if (functionLocalIndex >= 0) {
3026                stackValueForLocal(op, functionLocalIndex).put(callable.getOwner(), v);
3027            }
3028            ResolvedCall<? extends CallableDescriptor> resolvedCall =
3029                    bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
3030            assert resolvedCall != null;
3031            genThisAndReceiverFromResolvedCall(StackValue.none(), resolvedCall, callable);
3032            pushArgumentsAndInvoke(resolvedCall, callable);
3033    
3034            return returnValueAsStackValue(op, callable.getSignature().getAsmMethod().getReturnType());
3035        }
3036    
3037        @Override
3038        public StackValue visitPostfixExpression(@NotNull JetPostfixExpression expression, StackValue receiver) {
3039            if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL) {
3040                StackValue base = genQualified(receiver, expression.getBaseExpression());
3041                if (isPrimitive(base.type)) {
3042                    return base;
3043                }
3044                base.put(base.type, v);
3045                v.dup();
3046                Label ok = new Label();
3047                v.ifnonnull(ok);
3048                v.invokestatic("jet/runtime/Intrinsics", "throwNpe", "()V");
3049                v.mark(ok);
3050                return StackValue.onStack(base.type);
3051            }
3052    
3053            DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
3054            if (!(op instanceof FunctionDescriptor)) {
3055                throw new UnsupportedOperationException("Don't know how to generate this postfix expression: " + op);
3056            }
3057    
3058            Type asmType = expressionType(expression);
3059            DeclarationDescriptor cls = op.getContainingDeclaration();
3060    
3061            int increment;
3062            if (op.getName().asString().equals("inc")) {
3063                increment = 1;
3064            }
3065            else if (op.getName().asString().equals("dec")) {
3066                increment = -1;
3067            }
3068            else {
3069                throw new UnsupportedOperationException("Unsupported postfix operation: " + op);
3070            }
3071    
3072            if (isPrimitiveNumberClassDescriptor(cls)) {
3073                receiver.put(receiver.type, v);
3074                JetExpression operand = expression.getBaseExpression();
3075                if (operand instanceof JetReferenceExpression && asmType == Type.INT_TYPE) {
3076                    int index = indexOfLocal((JetReferenceExpression) operand);
3077                    if (index >= 0) {
3078                        return StackValue.postIncrement(index, increment);
3079                    }
3080                }
3081                gen(operand, asmType);                               // old value
3082                generateIncrement(increment, asmType, operand, receiver);   // increment in-place
3083                return StackValue.onStack(asmType);                                         // old value
3084            }
3085            else {
3086                ResolvedCall<? extends CallableDescriptor> resolvedCall =
3087                        bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
3088                assert resolvedCall != null;
3089    
3090                Callable callable = resolveToCallable((FunctionDescriptor) op, false);
3091    
3092                StackValue value = gen(expression.getBaseExpression());
3093                value.dupReceiver(v);
3094    
3095                Type type = expressionType(expression.getBaseExpression());
3096                value.put(type, v);
3097    
3098                switch (value.receiverSize()) {
3099                    case 0:
3100                        dup(v, type);
3101                        break;
3102    
3103                    case 1:
3104                        if (type.getSize() == 2) {
3105                            v.dup2X1();
3106                        }
3107                        else {
3108                            v.dupX1();
3109                        }
3110                        break;
3111    
3112                    case 2:
3113                        if (type.getSize() == 2) {
3114                            v.dup2X2();
3115                        }
3116                        else {
3117                            v.dupX2();
3118                        }
3119                        break;
3120    
3121                    case -1:
3122                        throw new UnsupportedOperationException();
3123                }
3124    
3125                CallableMethod callableMethod = (CallableMethod) callable;
3126                callableMethod.invokeWithNotNullAssertion(v, state, resolvedCall);
3127    
3128                value.store(callableMethod.getReturnType(), v);
3129                return StackValue.onStack(type);
3130            }
3131        }
3132    
3133        private void generateIncrement(int increment, Type asmType, JetExpression operand, StackValue receiver) {
3134            StackValue value = genQualified(receiver, operand);
3135            value.dupReceiver(v);
3136            value.put(asmType, v);
3137            genIncrement(asmType, increment, v);
3138            value.store(asmType, v);
3139        }
3140    
3141        @Override
3142        public StackValue visitProperty(@NotNull JetProperty property, StackValue receiver) {
3143            final JetExpression initializer = property.getInitializer();
3144            if (initializer == null) {
3145                return StackValue.none();
3146            }
3147            initializeLocalVariable(property, new Function<VariableDescriptor, Void>() {
3148                @Override
3149                public Void fun(VariableDescriptor descriptor) {
3150                    Type varType = asmType(descriptor.getType());
3151                    gen(initializer, varType);
3152                    return null;
3153                }
3154            });
3155            return StackValue.none();
3156        }
3157    
3158        @Override
3159        public StackValue visitMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration, StackValue receiver) {
3160            JetExpression initializer = multiDeclaration.getInitializer();
3161            if (initializer == null) return StackValue.none();
3162    
3163            JetType initializerType = bindingContext.get(EXPRESSION_TYPE, initializer);
3164            assert initializerType != null;
3165    
3166            Type initializerAsmType = asmType(initializerType);
3167    
3168            final TransientReceiver initializerAsReceiver = new TransientReceiver(initializerType);
3169    
3170            int tempVarIndex = myFrameMap.enterTemp(initializerAsmType);
3171    
3172            gen(initializer, initializerAsmType);
3173            v.store(tempVarIndex, initializerAsmType);
3174            final StackValue.Local local = StackValue.local(tempVarIndex, initializerAsmType);
3175    
3176            for (final JetMultiDeclarationEntry variableDeclaration : multiDeclaration.getEntries()) {
3177                initializeLocalVariable(variableDeclaration, new Function<VariableDescriptor, Void>() {
3178                    @Override
3179                    public Void fun(VariableDescriptor descriptor) {
3180                        ResolvedCall<FunctionDescriptor> resolvedCall =
3181                                bindingContext.get(BindingContext.COMPONENT_RESOLVED_CALL, variableDeclaration);
3182                        assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText();
3183                        Call call = makeFakeCall(initializerAsReceiver);
3184                        invokeFunction(call, local, resolvedCall);
3185                        return null;
3186                    }
3187                });
3188            }
3189    
3190            if(initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) {
3191                v.aconst(null);
3192                v.store(tempVarIndex, initializerAsmType);
3193            }
3194            myFrameMap.leaveTemp(initializerAsmType);
3195    
3196            return StackValue.none();
3197        }
3198    
3199        private void initializeLocalVariable(
3200                @NotNull JetVariableDeclaration variableDeclaration,
3201                @NotNull Function<VariableDescriptor, Void> generateInitializer
3202        ) {
3203    
3204            VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, variableDeclaration);
3205    
3206            if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) {
3207                return;
3208            }
3209            int index = lookupLocalIndex(variableDescriptor);
3210    
3211            if (index < 0) {
3212                throw new IllegalStateException("Local variable not found for " + variableDescriptor);
3213            }
3214    
3215            Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
3216            assert variableDescriptor != null;
3217    
3218            Type varType = asmType(variableDescriptor.getType());
3219    
3220            if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) {
3221                generateInitializer.fun(variableDescriptor);
3222                JetScript scriptPsi = JetPsiUtil.getScript(variableDeclaration);
3223                assert scriptPsi != null;
3224                Type scriptClassType = asmTypeForScriptPsi(bindingContext, scriptPsi);
3225                v.putfield(scriptClassType.getInternalName(), variableDeclaration.getName(), varType.getDescriptor());
3226            }
3227            else if (sharedVarType == null) {
3228                generateInitializer.fun(variableDescriptor);
3229                v.store(index, varType);
3230            }
3231            else {
3232                v.load(index, OBJECT_TYPE);
3233                generateInitializer.fun(variableDescriptor);
3234                v.putfield(sharedVarType.getInternalName(), "ref",
3235                           sharedVarType == JET_SHARED_VAR_TYPE ? "Ljava/lang/Object;" : varType.getDescriptor());
3236            }
3237        }
3238    
3239        @NotNull
3240        private StackValue generateNewCall(
3241                @NotNull JetCallExpression expression,
3242                @NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
3243                @NotNull StackValue receiver
3244        ) {
3245            Type type = expressionType(expression);
3246            if (type.getSort() == Type.ARRAY) {
3247                generateNewArray(expression);
3248                return StackValue.onStack(type);
3249            }
3250    
3251            return generateConstructorCall(resolvedCall, receiver, type);
3252        }
3253    
3254        @NotNull
3255        private StackValue generateConstructorCall(
3256                @NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall,
3257                @NotNull StackValue receiver,
3258                @NotNull Type type
3259        ) {
3260            v.anew(type);
3261            v.dup();
3262    
3263            receiver = StackValue.receiver(resolvedCall, receiver, this, null);
3264            receiver.put(receiver.type, v);
3265    
3266            ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
3267            MutableClosure closure = bindingContext.get(CLOSURE, constructorDescriptor.getContainingDeclaration());
3268    
3269            ClassDescriptor descriptor = getExpectedThisObjectForConstructorCall(constructorDescriptor, closure);
3270            if (receiver.type.getSort() != Type.VOID && descriptor == null) {
3271                v.pop();
3272            }
3273    
3274            //Resolved call to local class constructor doesn't have resolvedCall.getThisObject() and resolvedCall.getReceiverArgument()
3275            //so we need generate closure on stack
3276            //See StackValue.receiver for more info
3277            pushClosureOnStack(closure, resolvedCall.getThisObject().exists() || resolvedCall.getReceiverArgument().exists());
3278    
3279            ConstructorDescriptor originalOfSamAdapter = (ConstructorDescriptor) SamCodegenUtil.getOriginalIfSamAdapter(constructorDescriptor);
3280            CallableMethod method = typeMapper.mapToCallableMethod(originalOfSamAdapter == null ? constructorDescriptor : originalOfSamAdapter);
3281            invokeMethodWithArguments(method, resolvedCall, null, StackValue.none());
3282    
3283            return StackValue.onStack(type);
3284        }
3285    
3286        public void generateNewArray(@NotNull JetCallExpression expression) {
3287            JetType arrayType = bindingContext.get(EXPRESSION_TYPE, expression);
3288            assert arrayType != null : "Array instantiation isn't type checked: " + expression.getText();
3289    
3290            generateNewArray(expression, arrayType);
3291        }
3292    
3293        private void generateNewArray(@NotNull JetCallExpression expression, @NotNull JetType arrayType) {
3294            List<JetExpression> args = new ArrayList<JetExpression>();
3295            for (ValueArgument va : expression.getValueArguments()) {
3296                args.add(va.getArgumentExpression());
3297            }
3298            args.addAll(expression.getFunctionLiteralArguments());
3299    
3300            boolean isArray = KotlinBuiltIns.getInstance().isArray(arrayType);
3301            if (!isArray && args.size() != 1) {
3302                throw new CompilationException("primitive array constructor requires one argument", null, expression);
3303            }
3304    
3305            if (isArray) {
3306                gen(args.get(0), Type.INT_TYPE);
3307                v.newarray(boxType(asmType(arrayType.getArguments().get(0).getType())));
3308            }
3309            else {
3310                Type type = typeMapper.mapType(arrayType);
3311                gen(args.get(0), Type.INT_TYPE);
3312                v.newarray(correctElementType(type));
3313            }
3314    
3315            if (args.size() == 2) {
3316                int sizeIndex = myFrameMap.enterTemp(Type.INT_TYPE);
3317                int indexIndex = myFrameMap.enterTemp(Type.INT_TYPE);
3318    
3319                v.dup();
3320                v.arraylength();
3321                v.store(sizeIndex, Type.INT_TYPE);
3322    
3323                v.iconst(0);
3324                v.store(indexIndex, Type.INT_TYPE);
3325    
3326                gen(args.get(1), JET_FUNCTION1_TYPE);
3327    
3328                Label begin = new Label();
3329                Label end = new Label();
3330                v.visitLabel(begin);
3331                v.load(indexIndex, Type.INT_TYPE);
3332                v.load(sizeIndex, Type.INT_TYPE);
3333                v.ificmpge(end);
3334    
3335                v.dup2();
3336                v.load(indexIndex, Type.INT_TYPE);
3337                v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
3338                v.invokeinterface("jet/Function1", "invoke", "(Ljava/lang/Object;)Ljava/lang/Object;");
3339                v.load(indexIndex, Type.INT_TYPE);
3340                v.iinc(indexIndex, 1);
3341                v.swap();
3342                v.astore(OBJECT_TYPE);
3343    
3344                v.goTo(begin);
3345                v.visitLabel(end);
3346                v.pop();
3347    
3348                myFrameMap.leaveTemp(Type.INT_TYPE);
3349                myFrameMap.leaveTemp(Type.INT_TYPE);
3350            }
3351        }
3352    
3353        @Override
3354        public StackValue visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, StackValue receiver) {
3355            JetExpression array = expression.getArrayExpression();
3356            JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, array);
3357            Type arrayType = asmTypeOrVoid(type);
3358            List<JetExpression> indices = expression.getIndexExpressions();
3359            FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, expression);
3360            assert operationDescriptor != null;
3361            if (arrayType.getSort() == Type.ARRAY &&
3362                indices.size() == 1 &&
3363                operationDescriptor.getValueParameters().get(0).getType().equals(KotlinBuiltIns.getInstance().getIntType())) {
3364                gen(array, arrayType);
3365                for (JetExpression index : indices) {
3366                    gen(index, Type.INT_TYPE);
3367                }
3368                assert type != null;
3369                if (KotlinBuiltIns.getInstance().isArray(type)) {
3370                    JetType elementType = type.getArguments().get(0).getType();
3371                    Type notBoxed = asmType(elementType);
3372                    return StackValue.arrayElement(notBoxed, true);
3373                }
3374                else {
3375                    return StackValue.arrayElement(correctElementType(arrayType), false);
3376                }
3377            }
3378            else {
3379                ResolvedCall<FunctionDescriptor> resolvedSetCall = bindingContext.get(BindingContext.INDEXED_LVALUE_SET, expression);
3380                ResolvedCall<FunctionDescriptor> resolvedGetCall = bindingContext.get(BindingContext.INDEXED_LVALUE_GET, expression);
3381    
3382                boolean isGetter = "get".equals(operationDescriptor.getName().asString());
3383    
3384                ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall;
3385                assert resolvedCall != null : "couldn't find resolved call: " + expression.getText();
3386    
3387                Callable callable = resolveToCallable(operationDescriptor, false);
3388                if (callable instanceof CallableMethod) {
3389                    genThisAndReceiverFromResolvedCall(receiver, resolvedCall, (CallableMethod) callable);
3390                }
3391                else {
3392                    gen(array, arrayType); // intrinsic method
3393                }
3394    
3395                int index = operationDescriptor.getReceiverParameter() != null ? 1 : 0;
3396    
3397                Method asmMethod = resolveToCallableMethod(operationDescriptor, false, context).getSignature().getAsmMethod();
3398                Type[] argumentTypes = asmMethod.getArgumentTypes();
3399                for (JetExpression jetExpression : expression.getIndexExpressions()) {
3400                    gen(jetExpression, argumentTypes[index]);
3401                    index++;
3402                }
3403    
3404                Type elementType = isGetter ? asmMethod.getReturnType() : ArrayUtil.getLastElement(argumentTypes);
3405                return StackValue.collectionElement(elementType, resolvedGetCall, resolvedSetCall, this, state);
3406            }
3407        }
3408    
3409        @Override
3410        public StackValue visitThrowExpression(@NotNull JetThrowExpression expression, StackValue receiver) {
3411            gen(expression.getThrownExpression(), JAVA_THROWABLE_TYPE);
3412            v.athrow();
3413            return StackValue.none();
3414        }
3415    
3416        @Override
3417        public StackValue visitThisExpression(@NotNull JetThisExpression expression, StackValue receiver) {
3418            DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
3419            if (descriptor instanceof ClassDescriptor) {
3420                return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor, false);
3421            }
3422            else {
3423                if (descriptor instanceof CallableDescriptor) {
3424                    return generateReceiver(descriptor);
3425                }
3426                throw new UnsupportedOperationException("neither this nor receiver");
3427            }
3428        }
3429    
3430        @Override
3431        public StackValue visitTryExpression(@NotNull JetTryExpression expression, StackValue receiver) {
3432            return generateTryExpression(expression, false);
3433        }
3434    
3435        public StackValue generateTryExpression(JetTryExpression expression, boolean isStatement) {
3436            /*
3437    The "returned" value of try expression with no finally is either the last expression in the try block or the last expression in the catch block
3438    (or blocks).
3439             */
3440            JetFinallySection finallyBlock = expression.getFinallyBlock();
3441            FinallyBlockStackElement finallyBlockStackElement = null;
3442            if (finallyBlock != null) {
3443                finallyBlockStackElement = new FinallyBlockStackElement(expression);
3444                blockStackElements.push(finallyBlockStackElement);
3445            }
3446    
3447            JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
3448            assert jetType != null;
3449            Type expectedAsmType = isStatement ? Type.VOID_TYPE : asmType(jetType);
3450    
3451            Label tryStart = new Label();
3452            v.mark(tryStart);
3453            v.nop(); // prevent verify error on empty try
3454    
3455            gen(expression.getTryBlock(), expectedAsmType);
3456    
3457            int savedValue = -1;
3458            if (!isStatement) {
3459                savedValue = myFrameMap.enterTemp(expectedAsmType);
3460                v.store(savedValue, expectedAsmType);
3461            }
3462    
3463            Label tryEnd = new Label();
3464            v.mark(tryEnd);
3465    
3466            //do it before finally block generation
3467            List<Label> tryBlockRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, tryEnd);
3468    
3469            Label end = new Label();
3470    
3471            genFinallyBlockOrGoto(finallyBlockStackElement, end);
3472    
3473            List<JetCatchClause> clauses = expression.getCatchClauses();
3474            for (int i = 0, size = clauses.size(); i < size; i++) {
3475                JetCatchClause clause = clauses.get(i);
3476    
3477                Label clauseStart = new Label();
3478                v.mark(clauseStart);
3479    
3480                VariableDescriptor descriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, clause.getCatchParameter());
3481                assert descriptor != null;
3482                Type descriptorType = asmType(descriptor.getType());
3483                myFrameMap.enter(descriptor, descriptorType);
3484                int index = lookupLocalIndex(descriptor);
3485                v.store(index, descriptorType);
3486    
3487                gen(clause.getCatchBody(), expectedAsmType);
3488    
3489                if (!isStatement) {
3490                    v.store(savedValue, expectedAsmType);
3491                }
3492    
3493                myFrameMap.leave(descriptor);
3494    
3495                genFinallyBlockOrGoto(finallyBlockStackElement, i != size - 1 || finallyBlock != null ? end : null);
3496    
3497                generateExceptionTable(clauseStart, tryBlockRegions, descriptorType.getInternalName());
3498            }
3499    
3500    
3501            //for default catch clause
3502            if (finallyBlock != null) {
3503                Label defaultCatchStart = new Label();
3504                v.mark(defaultCatchStart);
3505                int savedException = myFrameMap.enterTemp(JAVA_THROWABLE_TYPE);
3506                v.store(savedException, JAVA_THROWABLE_TYPE);
3507                Label defaultCatchEnd = new Label();
3508                v.mark(defaultCatchEnd);
3509    
3510                //do it before finally block generation
3511                //javac also generates entry in exception table for default catch clause too!!!! so defaultCatchEnd as end parameter
3512                List<Label> defaultCatchRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, defaultCatchEnd);
3513    
3514    
3515                genFinallyBlockOrGoto(finallyBlockStackElement, null);
3516    
3517                v.load(savedException, JAVA_THROWABLE_TYPE);
3518                myFrameMap.leaveTemp(JAVA_THROWABLE_TYPE);
3519    
3520                v.athrow();
3521    
3522                generateExceptionTable(defaultCatchStart, defaultCatchRegions, null);
3523            }
3524    
3525            markLineNumber(expression);
3526            v.mark(end);
3527    
3528            if (!isStatement) {
3529                v.load(savedValue, expectedAsmType);
3530                myFrameMap.leaveTemp(expectedAsmType);
3531            }
3532    
3533            if (finallyBlock != null) {
3534                blockStackElements.pop();
3535            }
3536    
3537            return StackValue.onStack(expectedAsmType);
3538        }
3539    
3540        private void generateExceptionTable(@NotNull Label catchStart, @NotNull List<Label> catchedRegions, @Nullable String exception) {
3541            for (int i = 0; i < catchedRegions.size(); i += 2) {
3542                Label startRegion = catchedRegions.get(i);
3543                Label endRegion = catchedRegions.get(i+1);
3544                v.visitTryCatchBlock(startRegion, endRegion, catchStart, exception);
3545            }
3546        }
3547    
3548    
3549        private List<Label> getCurrentCatchIntervals(
3550                @Nullable FinallyBlockStackElement finallyBlockStackElement,
3551                @NotNull Label blockStart,
3552                @NotNull Label blockEnd
3553        ) {
3554            List<Label> gapsInBlock =
3555                    finallyBlockStackElement != null ? new ArrayList<Label>(finallyBlockStackElement.gaps) : Collections.<Label>emptyList();
3556            assert gapsInBlock.size() % 2 == 0;
3557            List<Label> blockRegions = new ArrayList<Label>(gapsInBlock.size() + 2);
3558            blockRegions.add(blockStart);
3559            blockRegions.addAll(gapsInBlock);
3560            blockRegions.add(blockEnd);
3561            return blockRegions;
3562        }
3563    
3564        @Override
3565        public StackValue visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression, StackValue receiver) {
3566            JetSimpleNameExpression operationSign = expression.getOperationReference();
3567            IElementType opToken = operationSign.getReferencedNameElementType();
3568            if (opToken == JetTokens.COLON) {
3569                return gen(expression.getLeft());
3570            }
3571            else {
3572                JetTypeReference typeReference = expression.getRight();
3573                JetType rightType = bindingContext.get(BindingContext.TYPE, typeReference);
3574                assert rightType != null;
3575                Type rightTypeAsm = boxType(asmType(rightType));
3576                JetExpression left = expression.getLeft();
3577                DeclarationDescriptor descriptor = rightType.getConstructor().getDeclarationDescriptor();
3578                if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) {
3579                    StackValue value = genQualified(receiver, left);
3580                    value.put(boxType(value.type), v);
3581    
3582                    if (opToken != JetTokens.AS_SAFE) {
3583                        if (!CodegenUtil.isNullableType(rightType)) {
3584                            v.dup();
3585                            Label nonnull = new Label();
3586                            v.ifnonnull(nonnull);
3587                            JetType leftType = bindingContext.get(BindingContext.EXPRESSION_TYPE, left);
3588                            assert leftType != null;
3589                            throwNewException(CLASS_TYPE_CAST_EXCEPTION, DescriptorRenderer.TEXT.renderType(leftType) +
3590                                                                         " cannot be cast to " +
3591                                                                         DescriptorRenderer.TEXT.renderType(rightType));
3592                            v.mark(nonnull);
3593                        }
3594                    }
3595                    else {
3596                        v.dup();
3597                        v.instanceOf(rightTypeAsm);
3598                        Label ok = new Label();
3599                        v.ifne(ok);
3600                        v.pop();
3601                        v.aconst(null);
3602                        v.mark(ok);
3603                    }
3604    
3605                    v.checkcast(rightTypeAsm);
3606                    return StackValue.onStack(rightTypeAsm);
3607                }
3608                else {
3609                    throw new UnsupportedOperationException("Don't know how to handle non-class types in as/as? : " + descriptor);
3610                }
3611            }
3612        }
3613    
3614        @Override
3615        public StackValue visitIsExpression(@NotNull JetIsExpression expression, StackValue receiver) {
3616            StackValue match = StackValue.expression(OBJECT_TYPE, expression.getLeftHandSide(), this);
3617            return generateIsCheck(match, expression.getTypeRef(), expression.isNegated());
3618        }
3619    
3620        private StackValue generateExpressionMatch(StackValue expressionToMatch, JetExpression patternExpression) {
3621            if (expressionToMatch != null) {
3622                Type subjectType = expressionToMatch.type;
3623                expressionToMatch.dupReceiver(v);
3624                expressionToMatch.put(subjectType, v);
3625                JetType condJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, patternExpression);
3626                Type condType;
3627                if (isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) {
3628                    assert condJetType != null;
3629                    condType = asmType(condJetType);
3630                    if (!(isNumberPrimitive(condType) || condType.getSort() == Type.BOOLEAN)) {
3631                        subjectType = boxType(subjectType);
3632                        expressionToMatch.coerceTo(subjectType, v);
3633                    }
3634                }
3635                else {
3636                    condType = OBJECT_TYPE;
3637                }
3638                gen(patternExpression, condType);
3639                return genEqualsForExpressionsOnStack(v, JetTokens.EQEQ, subjectType, condType);
3640            }
3641            else {
3642                return gen(patternExpression);
3643            }
3644        }
3645    
3646        private StackValue generateIsCheck(StackValue expressionToMatch, JetTypeReference typeReference, boolean negated) {
3647            JetType jetType = bindingContext.get(BindingContext.TYPE, typeReference);
3648            expressionToMatch.dupReceiver(v);
3649            generateInstanceOf(expressionToMatch, jetType, false);
3650            StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE);
3651            return negated ? StackValue.not(value) : value;
3652        }
3653    
3654        private void generateInstanceOf(StackValue expressionToGen, JetType jetType, boolean leaveExpressionOnStack) {
3655            expressionToGen.put(OBJECT_TYPE, v);
3656            if (leaveExpressionOnStack) {
3657                v.dup();
3658            }
3659            Type type = boxType(asmType(jetType));
3660            if (jetType.isNullable()) {
3661                Label nope = new Label();
3662                Label end = new Label();
3663    
3664                v.dup();
3665                v.ifnull(nope);
3666                v.instanceOf(type);
3667                v.goTo(end);
3668                v.mark(nope);
3669                v.pop();
3670                v.iconst(1);
3671                v.mark(end);
3672            }
3673            else {
3674                v.instanceOf(type);
3675            }
3676        }
3677    
3678        @Override
3679        public StackValue visitWhenExpression(@NotNull JetWhenExpression expression, StackValue receiver) {
3680            return generateWhenExpression(expression, false);
3681        }
3682    
3683        public StackValue generateWhenExpression(JetWhenExpression expression, boolean isStatement) {
3684            JetExpression expr = expression.getSubjectExpression();
3685            JetType subjectJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expr);
3686            Type subjectType = asmTypeOrVoid(subjectJetType);
3687            Type resultType = isStatement ? Type.VOID_TYPE : expressionType(expression);
3688            int subjectLocal = expr != null ? myFrameMap.enterTemp(subjectType) : -1;
3689            if (subjectLocal != -1) {
3690                gen(expr, subjectType);
3691                tempVariables.put(expr, StackValue.local(subjectLocal, subjectType));
3692                v.store(subjectLocal, subjectType);
3693            }
3694    
3695            Label end = new Label();
3696            boolean hasElse = JetPsiUtil.checkWhenExpressionHasSingleElse(expression);
3697    
3698            Label nextCondition = null;
3699            for (JetWhenEntry whenEntry : expression.getEntries()) {
3700                if (nextCondition != null) {
3701                    v.mark(nextCondition);
3702                }
3703                nextCondition = new Label();
3704                FrameMap.Mark mark = myFrameMap.mark();
3705                Label thisEntry = new Label();
3706                if (!whenEntry.isElse()) {
3707                    JetWhenCondition[] conditions = whenEntry.getConditions();
3708                    for (int i = 0; i < conditions.length; i++) {
3709                        StackValue conditionValue = generateWhenCondition(subjectType, subjectLocal, conditions[i]);
3710                        conditionValue.condJump(nextCondition, true, v);
3711                        if (i < conditions.length - 1) {
3712                            v.goTo(thisEntry);
3713                            v.mark(nextCondition);
3714                            nextCondition = new Label();
3715                        }
3716                    }
3717                }
3718    
3719                v.visitLabel(thisEntry);
3720                gen(whenEntry.getExpression(), resultType);
3721                mark.dropTo();
3722                if (!whenEntry.isElse()) {
3723                    v.goTo(end);
3724                }
3725            }
3726            if (!hasElse && nextCondition != null) {
3727                v.mark(nextCondition);
3728                throwNewException(CLASS_NO_PATTERN_MATCHED_EXCEPTION);
3729            }
3730    
3731            markLineNumber(expression);
3732            v.mark(end);
3733    
3734            myFrameMap.leaveTemp(subjectType);
3735            tempVariables.remove(expr);
3736            return StackValue.onStack(resultType);
3737        }
3738    
3739        private StackValue generateWhenCondition(Type subjectType, int subjectLocal, JetWhenCondition condition) {
3740            if (condition instanceof JetWhenConditionInRange) {
3741                JetWhenConditionInRange conditionInRange = (JetWhenConditionInRange) condition;
3742                JetExpression rangeExpression = conditionInRange.getRangeExpression();
3743                while (rangeExpression instanceof JetParenthesizedExpression) {
3744                    rangeExpression = ((JetParenthesizedExpression) rangeExpression).getExpression();
3745                }
3746                JetSimpleNameExpression operationReference = conditionInRange.getOperationReference();
3747                boolean inverted = operationReference.getReferencedNameElementType() == JetTokens.NOT_IN;
3748                if (isIntRangeExpr(rangeExpression)) {
3749                    getInIntRange(new StackValue.Local(subjectLocal, subjectType), (JetBinaryExpression) rangeExpression, inverted);
3750                }
3751                else {
3752                    //FunctionDescriptor op =
3753                    //        (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, conditionInRange.getOperationReference());
3754                    //genToJVMStack(rangeExpression);
3755                    //new StackValue.Local(subjectLocal, subjectType).put(OBJECT_TYPE, v);
3756                    //invokeFunctionNoParams(op, Type.BOOLEAN_TYPE, v);
3757                    invokeFunctionByReference(operationReference);
3758                    if (inverted) {
3759                        genInvertBoolean(v);
3760                    }
3761                }
3762                return StackValue.onStack(Type.BOOLEAN_TYPE);
3763            }
3764            StackValue.Local match = subjectLocal == -1 ? null : StackValue.local(subjectLocal, subjectType);
3765            if (condition instanceof JetWhenConditionIsPattern) {
3766                JetWhenConditionIsPattern patternCondition = (JetWhenConditionIsPattern) condition;
3767                return generateIsCheck(match, patternCondition.getTypeRef(), patternCondition.isNegated());
3768            }
3769            else if (condition instanceof JetWhenConditionWithExpression) {
3770                JetExpression patternExpression = ((JetWhenConditionWithExpression) condition).getExpression();
3771                return generateExpressionMatch(match, patternExpression);
3772            }
3773            else {
3774                throw new UnsupportedOperationException("unsupported kind of when condition");
3775            }
3776        }
3777    
3778        private void invokeFunctionByReference(JetSimpleNameExpression operationReference) {
3779            ResolvedCall<? extends CallableDescriptor> resolvedCall =
3780                    bindingContext.get(RESOLVED_CALL, operationReference);
3781            Call call = bindingContext.get(CALL, operationReference);
3782            invokeFunction(call, StackValue.none(), resolvedCall);
3783        }
3784    
3785        private boolean isIntRangeExpr(JetExpression rangeExpression) {
3786            if (rangeExpression instanceof JetBinaryExpression) {
3787                JetBinaryExpression binaryExpression = (JetBinaryExpression) rangeExpression;
3788                if (binaryExpression.getOperationReference().getReferencedNameElementType() == JetTokens.RANGE) {
3789                    JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, rangeExpression);
3790                    assert jetType != null;
3791                    DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
3792                    return INTEGRAL_RANGES.contains(descriptor);
3793                }
3794            }
3795            return false;
3796        }
3797    
3798        private void throwNewException(@NotNull String className) {
3799            throwNewException(className, null);
3800        }
3801    
3802        private void throwNewException(@NotNull String className, @Nullable String message) {
3803            v.anew(Type.getObjectType(className));
3804            v.dup();
3805            if (message != null) {
3806                v.visitLdcInsn(message);
3807                v.invokespecial(className, "<init>", "(Ljava/lang/String;)V");
3808            }
3809            else {
3810                v.invokespecial(className, "<init>", "()V");
3811            }
3812            v.athrow();
3813        }
3814    
3815        private Call makeFakeCall(ReceiverValue initializerAsReceiver) {
3816            JetSimpleNameExpression fake = JetPsiFactory.createSimpleName(state.getProject(), "fake");
3817            return CallMaker.makeCall(fake, initializerAsReceiver);
3818        }
3819    
3820        @Override
3821        public String toString() {
3822            return context.getContextDescriptor().toString();
3823        }
3824    
3825        @NotNull
3826        private ScriptCodegen getParentScriptCodegen() {
3827            MemberCodegen codegen = parentCodegen;
3828            while (codegen != null) {
3829                if (codegen instanceof ScriptCodegen) {
3830                    return (ScriptCodegen) codegen;
3831                }
3832                codegen = codegen.getParentCodegen();
3833            }
3834            throw new IllegalStateException("Script codegen should be present in codegen tree");
3835        }
3836    }