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