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