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