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.constants.CompileTimeConstant;
054    import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstant;
055    import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
056    import org.jetbrains.jet.lang.resolve.java.JvmAbi;
057    import org.jetbrains.jet.lang.resolve.java.descriptor.JavaClassDescriptor;
058    import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor;
059    import org.jetbrains.jet.lang.resolve.name.Name;
060    import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
061    import org.jetbrains.jet.lang.types.JetType;
062    import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
063    import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
064    import org.jetbrains.jet.lexer.JetTokens;
065    import org.jetbrains.jet.renderer.DescriptorRenderer;
066    
067    import java.util.*;
068    
069    import static org.jetbrains.asm4.Opcodes.*;
070    import static org.jetbrains.jet.codegen.AsmUtil.*;
071    import static org.jetbrains.jet.codegen.CodegenUtil.*;
072    import static org.jetbrains.jet.codegen.FunctionTypesUtil.functionTypeToImpl;
073    import static org.jetbrains.jet.codegen.FunctionTypesUtil.getFunctionImplType;
074    import static org.jetbrains.jet.codegen.binding.CodegenBinding.*;
075    import static org.jetbrains.jet.lang.resolve.BindingContext.*;
076    import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getNotNull;
077    import static org.jetbrains.jet.lang.resolve.BindingContextUtils.isVarCapturedInClosure;
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<?> 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<?> 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                Type scriptClassType = asmTypeForScriptDescriptor(bindingContext, scriptDescriptor);
1736                ValueParameterDescriptor valueParameterDescriptor = (ValueParameterDescriptor) descriptor;
1737                ClassDescriptor scriptClass = bindingContext.get(CLASS_FOR_SCRIPT, scriptDescriptor);
1738                StackValue script = StackValue.thisOrOuter(this, scriptClass, false, false);
1739                script.put(script.type, v);
1740                Type fieldType = typeMapper.mapType(valueParameterDescriptor);
1741                return StackValue.field(fieldType, scriptClassType, valueParameterDescriptor.getName().getIdentifier(), false);
1742            }
1743    
1744            throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
1745        }
1746    
1747        private StackValue stackValueForLocal(DeclarationDescriptor descriptor, int index) {
1748            if (descriptor instanceof VariableDescriptor) {
1749                Type sharedVarType = typeMapper.getSharedVarType(descriptor);
1750                JetType outType = ((VariableDescriptor) descriptor).getType();
1751                if (sharedVarType != null) {
1752                    return StackValue.shared(index, asmType(outType));
1753                }
1754                else {
1755                    return StackValue.local(index, asmType(outType));
1756                }
1757            }
1758            else {
1759                return StackValue.local(index, OBJECT_TYPE);
1760            }
1761        }
1762    
1763        @Override
1764        public boolean lookupLocal(DeclarationDescriptor descriptor) {
1765            return lookupLocalIndex(descriptor) != -1;
1766        }
1767    
1768        public int lookupLocalIndex(DeclarationDescriptor descriptor) {
1769            return myFrameMap.getIndex(descriptor);
1770        }
1771    
1772        @Nullable
1773        private static JetType getPropertyDelegateType(@NotNull PropertyDescriptor descriptor, @NotNull BindingContext bindingContext) {
1774            PropertyGetterDescriptor getter = descriptor.getGetter();
1775            if (getter != null) {
1776                Call call = bindingContext.get(BindingContext.DELEGATED_PROPERTY_CALL, getter);
1777                return call != null ? call.getExplicitReceiver().getType() : null;
1778            }
1779            return null;
1780        }
1781    
1782        @NotNull
1783        public StackValue.Property intermediateValueForProperty(
1784                @NotNull PropertyDescriptor propertyDescriptor,
1785                boolean forceField,
1786                @Nullable JetSuperExpression superExpression
1787        ) {
1788            return intermediateValueForProperty(propertyDescriptor, forceField, superExpression, MethodKind.GENERAL);
1789        }
1790    
1791        public StackValue.Property intermediateValueForProperty(
1792                @NotNull PropertyDescriptor propertyDescriptor,
1793                boolean forceField,
1794                @Nullable JetSuperExpression superExpression,
1795                @NotNull MethodKind methodKind
1796        ) {
1797            JetTypeMapper typeMapper = state.getTypeMapper();
1798    
1799            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
1800    
1801            boolean isBackingFieldInAnotherClass = AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor);
1802            boolean isStatic = containingDeclaration instanceof PackageFragmentDescriptor;
1803            boolean isSuper = superExpression != null;
1804            boolean isInsideClass = isCallInsideSameClassAsDeclared(propertyDescriptor, context);
1805    
1806            JetType delegateType = getPropertyDelegateType(propertyDescriptor, state.getBindingContext());
1807            boolean isDelegatedProperty = delegateType != null;
1808    
1809    
1810            CallableMethod callableGetter = null;
1811            CallableMethod callableSetter = null;
1812    
1813            boolean skipPropertyAccessors = forceField && !isBackingFieldInAnotherClass;
1814    
1815            CodegenContext backingFieldContext = context.getParentContext();
1816    
1817            if (isBackingFieldInAnotherClass && forceField) {
1818                //delegate call to classObject owner : OWNER
1819                backingFieldContext = context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration());
1820                int flags = AsmUtil.getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegatedProperty);
1821                skipPropertyAccessors = (flags & ACC_PRIVATE) == 0 || methodKind == MethodKind.SYNTHETIC_ACCESSOR || methodKind == MethodKind.INITIALIZER;
1822                if (!skipPropertyAccessors) {
1823                    //noinspection ConstantConditions
1824                    propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(propertyDescriptor, true, delegateType);
1825                }
1826                isStatic = true;
1827            }
1828    
1829            if (!skipPropertyAccessors) {
1830                if (couldUseDirectAccessToProperty(propertyDescriptor, true, isInsideClass, isDelegatedProperty, context)) {
1831                    callableGetter = null;
1832                }
1833                else {
1834                    if (isSuper && !isInterface(containingDeclaration)) {
1835                        ClassDescriptor owner = getSuperCallLabelTarget(superExpression, state.getBindingContext(), context);
1836                        CodegenContext c = context.findParentContextWithDescriptor(owner);
1837                        assert c != null : "Couldn't find a context for a super-call: " + propertyDescriptor;
1838                        if (c != context.getParentContext()) {
1839                            propertyDescriptor = (PropertyDescriptor) c.getAccessor(propertyDescriptor);
1840                        }
1841                    }
1842    
1843                    propertyDescriptor = accessiblePropertyDescriptor(propertyDescriptor);
1844    
1845                    PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
1846                    if (getter != null) {
1847                        callableGetter = typeMapper.mapToCallableMethod(getter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
1848                    }
1849                }
1850    
1851                if (propertyDescriptor.isVar()) {
1852                    PropertySetterDescriptor setter = propertyDescriptor.getSetter();
1853                    if (setter != null) {
1854                        if (couldUseDirectAccessToProperty(propertyDescriptor, false, isInsideClass, isDelegatedProperty, context)) {
1855                            callableSetter = null;
1856                        }
1857                        else {
1858                            callableSetter = typeMapper.mapToCallableMethod(setter, isSuper || MethodKind.SYNTHETIC_ACCESSOR == methodKind, context);
1859                        }
1860                    }
1861                }
1862            }
1863    
1864            Type owner;
1865            CallableMethod callableMethod = callableGetter != null ? callableGetter : callableSetter;
1866    
1867            propertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
1868            if (callableMethod == null) {
1869                owner = typeMapper.getOwner(isBackingFieldInAnotherClass ? propertyDescriptor.getContainingDeclaration() : propertyDescriptor,
1870                                            context.getContextKind(), isCallInsideSameModuleAsDeclared(propertyDescriptor, context));
1871            }
1872            else {
1873                owner = callableMethod.getOwner();
1874            }
1875    
1876            String name;
1877            //noinspection ConstantConditions
1878            if (propertyDescriptor.getContainingDeclaration() == backingFieldContext.getContextDescriptor()) {
1879                assert backingFieldContext instanceof FieldOwnerContext : "Actual context is " + backingFieldContext + " but should be instance of FieldOwnerContext" ;
1880                name = ((FieldOwnerContext) backingFieldContext).getFieldName(propertyDescriptor, isDelegatedProperty);
1881            } else {
1882                name = JvmAbi.getDefaultPropertyName(propertyDescriptor.getName(), isDelegatedProperty, propertyDescriptor.getReceiverParameter() != null);
1883            }
1884    
1885            return StackValue.property(propertyDescriptor, owner,
1886                                typeMapper.mapType(isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
1887                                isStatic, name, callableGetter, callableSetter, state);
1888    
1889        }
1890    
1891        @Override
1892        public StackValue visitCallExpression(@NotNull JetCallExpression expression, StackValue receiver) {
1893            JetExpression callee = expression.getCalleeExpression();
1894            assert callee != null;
1895    
1896            ResolvedCall<?> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, callee);
1897            if (resolvedCall == null) {
1898                throw new CompilationException("Cannot resolve: " + callee.getText(), null, expression);
1899            }
1900    
1901            DeclarationDescriptor funDescriptor = resolvedCall.getResultingDescriptor();
1902    
1903            if (!(funDescriptor instanceof FunctionDescriptor)) {
1904                throw new UnsupportedOperationException("unknown type of callee descriptor: " + funDescriptor);
1905            }
1906    
1907            funDescriptor = accessibleFunctionDescriptor((FunctionDescriptor) funDescriptor);
1908    
1909            if (funDescriptor instanceof ConstructorDescriptor) {
1910                return generateNewCall(expression, resolvedCall, receiver);
1911            }
1912    
1913            Call call = bindingContext.get(CALL, expression.getCalleeExpression());
1914            if (funDescriptor instanceof SimpleFunctionDescriptor) {
1915                SimpleFunctionDescriptor original = ((SimpleFunctionDescriptor) funDescriptor).getOriginal();
1916                if (original instanceof SamConstructorDescriptor) {
1917                    return invokeSamConstructor(expression, resolvedCall, ((SamConstructorDescriptor) original).getBaseForSynthesized());
1918                }
1919            }
1920    
1921            return invokeFunction(call, receiver, resolvedCall);
1922        }
1923    
1924        @NotNull
1925        private StackValue invokeSamConstructor(JetCallExpression expression, ResolvedCall<?> resolvedCall, JavaClassDescriptor samInterface) {
1926            List<ResolvedValueArgument> arguments = resolvedCall.getValueArgumentsByIndex();
1927            if (arguments == null) {
1928                throw new IllegalStateException("Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor());
1929            }
1930            ResolvedValueArgument argument = arguments.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(Call call, StackValue receiver, ResolvedCall<?> resolvedCall) {
1994            if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
1995                return invokeFunction(call, receiver, ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall());
1996            }
1997    
1998            FunctionDescriptor fd = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
1999            JetSuperExpression superCallExpression = getSuperCallExpression(call);
2000            boolean superCall = superCallExpression != null;
2001    
2002            if (superCall && !isInterface(fd.getContainingDeclaration())) {
2003                ClassDescriptor owner = getSuperCallLabelTarget(superCallExpression);
2004                CodegenContext c = context.findParentContextWithDescriptor(owner);
2005                assert c != null : "Couldn't find a context for a super-call: " + fd;
2006                if (c != context.getParentContext()) {
2007                    fd = (FunctionDescriptor) c.getAccessor(fd);
2008                }
2009            }
2010    
2011            Callable callable = resolveToCallable(accessibleFunctionDescriptor(fd), superCall);
2012    
2013            if (callable instanceof CallableMethod) {
2014                CallableMethod callableMethod = (CallableMethod) callable;
2015                Type calleeType = callableMethod.getGenerateCalleeType();
2016                if (calleeType != null) {
2017                    assert !callableMethod.isNeedsThis() : "Method should have a receiver: " + resolvedCall.getResultingDescriptor();
2018                    gen(call.getCalleeExpression(), calleeType);
2019                }
2020            }
2021    
2022            return invokeFunctionWithCalleeOnStack(call, receiver, resolvedCall, callable);
2023        }
2024    
2025        @NotNull
2026        private StackValue invokeFunctionWithCalleeOnStack(
2027                @NotNull Call call,
2028                @NotNull StackValue receiver,
2029                @NotNull ResolvedCall<?> resolvedCall,
2030                @NotNull Callable callable
2031        ) {
2032            if (callable instanceof CallableMethod) {
2033                CallableMethod callableMethod = (CallableMethod) callable;
2034                invokeMethodWithArguments(call, callableMethod, resolvedCall, receiver);
2035                //noinspection ConstantConditions
2036                Type returnType = typeMapper.mapReturnType(resolvedCall.getResultingDescriptor());
2037                StackValue.coerce(callableMethod.getReturnType(), returnType, v);
2038                return StackValue.onStack(returnType);
2039            }
2040            else {
2041                receiver = StackValue.receiver(resolvedCall, receiver, this, null);
2042    
2043                List<JetExpression> args = new ArrayList<JetExpression>();
2044                for (ValueArgument argument : call.getValueArguments()) {
2045                    args.add(argument.getArgumentExpression());
2046                }
2047    
2048                Type returnType = typeMapper.mapType(resolvedCall.getResultingDescriptor());
2049    
2050                ((IntrinsicMethod) callable).generate(this, v, returnType, call.getCallElement(), args, receiver);
2051                return StackValue.onStack(returnType);
2052            }
2053        }
2054    
2055        @Nullable
2056        private static JetSuperExpression getSuperCallExpression(@NotNull Call call) {
2057            ReceiverValue explicitReceiver = call.getExplicitReceiver();
2058            if (explicitReceiver instanceof ExpressionReceiver) {
2059                JetExpression receiverExpression = ((ExpressionReceiver) explicitReceiver).getExpression();
2060                if (receiverExpression instanceof JetSuperExpression) {
2061                    return (JetSuperExpression) receiverExpression;
2062                }
2063            }
2064            return null;
2065        }
2066    
2067        // Find the first parent of the current context which corresponds to a subclass of a given class
2068        @NotNull
2069        private static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) {
2070            CodegenContext c = context;
2071            while (true) {
2072                if (c instanceof ClassContext && DescriptorUtils.isSubclass(c.getThisDescriptor(), descriptor)) {
2073                    return c;
2074                }
2075                c = c.getParentContext();
2076                assert c != null;
2077            }
2078        }
2079    
2080        @NotNull
2081        Callable resolveToCallable(@NotNull FunctionDescriptor fd, boolean superCall) {
2082            IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(fd);
2083            if (intrinsic != null) {
2084                return intrinsic;
2085            }
2086    
2087            return resolveToCallableMethod(fd, superCall, context);
2088        }
2089    
2090        @NotNull
2091        private CallableMethod resolveToCallableMethod(@NotNull FunctionDescriptor fd, boolean superCall, @NotNull CodegenContext context) {
2092            SimpleFunctionDescriptor originalOfSamAdapter = (SimpleFunctionDescriptor) SamCodegenUtil.getOriginalIfSamAdapter(fd);
2093            return typeMapper.mapToCallableMethod(originalOfSamAdapter != null ? originalOfSamAdapter : fd, superCall, context);
2094        }
2095    
2096        public void invokeMethodWithArguments(
2097                @Nullable Call call,
2098                @NotNull CallableMethod callableMethod,
2099                @NotNull ResolvedCall<?> resolvedCall,
2100                @NotNull StackValue receiver
2101        ) {
2102            CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
2103            boolean isInline = state.isInlineEnabled() &&
2104                               call != null &&
2105                               descriptor instanceof SimpleFunctionDescriptor &&
2106                               ((SimpleFunctionDescriptor) descriptor).getInlineStrategy().isInline();
2107    
2108            CallGenerator callGenerator = !isInline ? defaulCallGenerator :
2109                              new InlineCodegen(this, state, (SimpleFunctionDescriptor) DescriptorUtils.unwrapFakeOverride(
2110                                      (CallableMemberDescriptor) descriptor.getOriginal()), call);
2111    
2112            if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
2113                resolvedCall = ((VariableAsFunctionResolvedCall) resolvedCall).getFunctionCall();
2114            }
2115    
2116            if (!(descriptor instanceof ConstructorDescriptor)) { // otherwise already
2117                receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
2118                receiver.put(receiver.type, v);
2119            }
2120    
2121            assert callGenerator == defaulCallGenerator || !hasDefaultArguments(resolvedCall) && !tailRecursionCodegen.isTailRecursion(resolvedCall) :
2122                    "Method with defaults or tail recursive couldn't be inlined " + descriptor;
2123    
2124            pushArgumentsAndInvoke(resolvedCall, callableMethod, callGenerator);
2125        }
2126    
2127        private void pushArgumentsAndInvoke(@NotNull ResolvedCall<?> resolvedCall, @NotNull CallableMethod callable, @NotNull CallGenerator callGenerator) {
2128            callGenerator.putHiddenParams();
2129    
2130            int mask = pushMethodArguments(resolvedCall, callable.getValueParameterTypes(), callGenerator);
2131    
2132            if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
2133                tailRecursionCodegen.generateTailRecursion(resolvedCall);
2134                return;
2135            }
2136    
2137            callGenerator.genCall(callable, resolvedCall, mask, this);
2138        }
2139    
2140        private void genThisAndReceiverFromResolvedCall(StackValue receiver, ResolvedCall<?> resolvedCall, CallableMethod callableMethod) {
2141            receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
2142            receiver.put(receiver.type, v);
2143        }
2144    
2145        public void generateFromResolvedCall(@NotNull ReceiverValue descriptor, @NotNull Type type) {
2146            if (descriptor instanceof ClassReceiver) {
2147                Type exprType = asmType(descriptor.getType());
2148                ClassReceiver classReceiver = (ClassReceiver) descriptor;
2149                ClassDescriptor classReceiverDeclarationDescriptor = classReceiver.getDeclarationDescriptor();
2150                if (DescriptorUtils.isClassObject(classReceiverDeclarationDescriptor)) {
2151                    if (context.getContextDescriptor() instanceof FunctionDescriptor &&
2152                        classReceiverDeclarationDescriptor == context.getContextDescriptor().getContainingDeclaration()) {
2153                        v.load(0, OBJECT_TYPE);
2154                    }
2155                    else {
2156                        FieldInfo info = FieldInfo.createForSingleton(classReceiverDeclarationDescriptor, typeMapper);
2157                        v.getstatic(info.getOwnerInternalName(), info.getFieldName(), info.getFieldType().getDescriptor());
2158                    }
2159                    StackValue.onStack(exprType).put(type, v);
2160                }
2161                else {
2162                    StackValue.thisOrOuter(this, classReceiverDeclarationDescriptor, false, false).put(type, v);
2163                }
2164            }
2165            else if (descriptor instanceof ScriptReceiver) {
2166                generateScript((ScriptReceiver) descriptor);
2167            }
2168            else if (descriptor instanceof ExtensionReceiver) {
2169                ExtensionReceiver extensionReceiver = (ExtensionReceiver) descriptor;
2170                generateReceiver(extensionReceiver.getDeclarationDescriptor()).put(type, v);
2171            }
2172            else if (descriptor instanceof ExpressionReceiver) {
2173                ExpressionReceiver expressionReceiver = (ExpressionReceiver) descriptor;
2174                JetExpression expr = expressionReceiver.getExpression();
2175                gen(expr, type);
2176            }
2177            else {
2178                throw new UnsupportedOperationException("Unsupported receiver type: " + descriptor);
2179            }
2180        }
2181    
2182        @Nullable
2183        private static JetExpression getReceiverForSelector(PsiElement expression) {
2184            if (expression.getParent() instanceof JetDotQualifiedExpression && !isReceiver(expression)) {
2185                JetDotQualifiedExpression parent = (JetDotQualifiedExpression) expression.getParent();
2186                return parent.getReceiverExpression();
2187            }
2188            return null;
2189        }
2190    
2191        private StackValue generateReceiver(DeclarationDescriptor provided) {
2192            if (context.getCallableDescriptorWithReceiver() == provided) {
2193                return context.getReceiverExpression(typeMapper);
2194            }
2195    
2196            return context.lookupInContext(provided, StackValue.local(0, OBJECT_TYPE), state, false);
2197        }
2198    
2199        private void generateScript(@NotNull ScriptReceiver receiver) {
2200            CodegenContext cur = context;
2201            StackValue result = StackValue.local(0, OBJECT_TYPE);
2202            boolean inStartConstructorContext = cur instanceof ConstructorContext;
2203            while (cur != null) {
2204                if (!inStartConstructorContext) {
2205                    cur = getNotNullParentContextForMethod(cur);
2206                }
2207    
2208                if (cur instanceof ScriptContext) {
2209                    ScriptContext scriptContext = (ScriptContext) cur;
2210    
2211                    Type currentScriptType = asmTypeForScriptDescriptor(bindingContext, scriptContext.getScriptDescriptor());
2212                    if (scriptContext.getScriptDescriptor() == receiver.getDeclarationDescriptor()) {
2213                        result.put(currentScriptType, v);
2214                    }
2215                    else {
2216                        Type classType = asmTypeForScriptDescriptor(bindingContext, receiver.getDeclarationDescriptor());
2217                        String fieldName = getParentScriptCodegen().getScriptFieldName(receiver.getDeclarationDescriptor());
2218                        result.put(currentScriptType, v);
2219                        StackValue.field(classType, currentScriptType, fieldName, false).put(classType, v);
2220                    }
2221                    return;
2222                }
2223    
2224                result = cur.getOuterExpression(result, false);
2225    
2226                if (inStartConstructorContext) {
2227                    cur = getNotNullParentContextForMethod(cur);
2228                    inStartConstructorContext = false;
2229                }
2230    
2231                cur = cur.getParentContext();
2232            }
2233    
2234            throw new UnsupportedOperationException();
2235        }
2236    
2237        public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) {
2238            boolean isSingleton = calleeContainingClass.getKind().isSingleton();
2239            if (isSingleton) {
2240                if (context.hasThisDescriptor() && context.getThisDescriptor().equals(calleeContainingClass)) {
2241                    return StackValue.local(0, typeMapper.mapType(calleeContainingClass));
2242                }
2243                else {
2244                    return StackValue.singleton(calleeContainingClass, typeMapper);
2245                }
2246            }
2247    
2248            CodegenContext cur = context;
2249            Type type = asmType(calleeContainingClass.getDefaultType());
2250            StackValue result = StackValue.local(0, type);
2251            boolean inStartConstructorContext = cur instanceof ConstructorContext;
2252            while (cur != null) {
2253                ClassDescriptor thisDescriptor = cur.getThisDescriptor();
2254                if (!isSuper && thisDescriptor.equals(calleeContainingClass)
2255                    || isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) {
2256                    return castToRequiredTypeOfInterfaceIfNeeded(result, thisDescriptor, calleeContainingClass);
2257                }
2258    
2259                //for constructor super call we should access to outer instance through parameter in locals, in other cases through field for captured outer
2260                if (inStartConstructorContext) {
2261                    result = cur.getOuterExpression(result, false);
2262                    cur = getNotNullParentContextForMethod(cur);
2263                    inStartConstructorContext = false;
2264                }
2265                else {
2266                    cur = getNotNullParentContextForMethod(cur);
2267                    result = cur.getOuterExpression(result, false);
2268                }
2269    
2270                cur = cur.getParentContext();
2271            }
2272    
2273            throw new UnsupportedOperationException();
2274        }
2275    
2276        @NotNull
2277        private static CodegenContext getNotNullParentContextForMethod(CodegenContext cur) {
2278            if (cur instanceof MethodContext) {
2279                cur = cur.getParentContext();
2280            }
2281            assert cur != null;
2282            return cur;
2283        }
2284    
2285    
2286        private static boolean isReceiver(PsiElement expression) {
2287            PsiElement parent = expression.getParent();
2288            if (parent instanceof JetQualifiedExpression) {
2289                JetExpression receiverExpression = ((JetQualifiedExpression) parent).getReceiverExpression();
2290                return expression == receiverExpression;
2291            }
2292            return false;
2293        }
2294    
2295        public int pushMethodArguments(@NotNull ResolvedCall<?> resolvedCall, List<Type> valueParameterTypes, @NotNull CallGenerator callGenerator) {
2296            return pushMethodArguments(resolvedCall, valueParameterTypes, false, callGenerator);
2297        }
2298    
2299        private int pushMethodArguments(@NotNull ResolvedCall<?> resolvedCall, List<Type> valueParameterTypes, boolean skipLast, @NotNull CallGenerator callGenerator) {
2300            List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
2301            CallableDescriptor fd = resolvedCall.getResultingDescriptor();
2302            if (valueArguments == null) {
2303                throw new IllegalStateException("Failed to arrange value arguments by index: " + fd);
2304            }
2305            List<ValueParameterDescriptor> valueParameters = fd.getValueParameters();
2306    
2307            if (valueParameters.size() != valueArguments.size()) {
2308                throw new IllegalStateException("Parameters and arguments size mismatch: " + valueParameters.size() + " != " + valueArguments.size());
2309            }
2310    
2311            int mask = 0;
2312    
2313            for (Iterator<ValueParameterDescriptor> iterator = valueParameters.iterator(); iterator.hasNext(); ) {
2314                ValueParameterDescriptor valueParameter = iterator.next();
2315                if (skipLast && !iterator.hasNext()) {
2316                    continue;
2317                }
2318    
2319                ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex());
2320                Type parameterType = valueParameterTypes.get(valueParameter.getIndex());
2321                if (resolvedValueArgument instanceof ExpressionValueArgument) {
2322                    ValueArgument valueArgument = ((ExpressionValueArgument) resolvedValueArgument).getValueArgument();
2323                    assert valueArgument != null;
2324                    JetExpression argumentExpression = valueArgument.getArgumentExpression();
2325                    assert argumentExpression != null : valueArgument.asElement().getText();
2326    
2327                    callGenerator.genValueAndPut(valueParameter, argumentExpression, parameterType);
2328                } else if (resolvedValueArgument instanceof DefaultValueArgument) {
2329                    pushDefaultValueOnStack(parameterType, v);
2330                    mask |= (1 << valueParameter.getIndex());
2331                    callGenerator.afterParameterPut(parameterType, null, valueParameter);
2332                }
2333                else if (resolvedValueArgument instanceof VarargValueArgument) {
2334                    VarargValueArgument valueArgument = (VarargValueArgument) resolvedValueArgument;
2335                    genVarargs(valueParameter, valueArgument);
2336                    callGenerator.afterParameterPut(parameterType, null, valueParameter);
2337                }
2338                else {
2339                    throw new UnsupportedOperationException();
2340                }
2341            }
2342            return mask;
2343        }
2344    
2345        private static boolean hasDefaultArguments(@NotNull ResolvedCall<?> resolvedCall) {
2346            List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
2347            CallableDescriptor fd = resolvedCall.getResultingDescriptor();
2348            if (valueArguments == null) {
2349                throw new IllegalStateException("Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor());
2350            }
2351    
2352            for (ValueParameterDescriptor valueParameter : fd.getValueParameters()) {
2353                ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex());
2354                if (resolvedValueArgument instanceof DefaultValueArgument) {
2355                    return true;
2356                }
2357            }
2358            return false;
2359        }
2360    
2361        public void genVarargs(ValueParameterDescriptor valueParameterDescriptor, VarargValueArgument valueArgument) {
2362            JetType outType = valueParameterDescriptor.getType();
2363    
2364            Type type = asmType(outType);
2365            assert type.getSort() == Type.ARRAY;
2366            Type elementType = correctElementType(type);
2367            List<ValueArgument> arguments = valueArgument.getArguments();
2368            int size = arguments.size();
2369    
2370            boolean hasSpread = false;
2371            for (int i = 0; i != size; ++i) {
2372                if (arguments.get(i).getSpreadElement() != null) {
2373                    hasSpread = true;
2374                    break;
2375                }
2376            }
2377    
2378            if (hasSpread) {
2379                if (size == 1) {
2380                    gen(arguments.get(0).getArgumentExpression(), type);
2381                }
2382                else {
2383                    String owner = "kotlin/jvm/internal/SpreadBuilder";
2384                    v.anew(Type.getObjectType(owner));
2385                    v.dup();
2386                    v.invokespecial(owner, "<init>", "()V");
2387                    for (int i = 0; i != size; ++i) {
2388                        v.dup();
2389                        ValueArgument argument = arguments.get(i);
2390                        if (argument.getSpreadElement() != null) {
2391                            gen(argument.getArgumentExpression(), OBJECT_TYPE);
2392                            v.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V");
2393                        }
2394                        else {
2395                            gen(argument.getArgumentExpression(), elementType);
2396                            v.invokevirtual(owner, "add", "(Ljava/lang/Object;)Z");
2397                            v.pop();
2398                        }
2399                    }
2400                    v.dup();
2401                    v.invokevirtual(owner, "size", "()I");
2402                    v.newarray(elementType);
2403                    v.invokevirtual(owner, "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;");
2404                    v.checkcast(type);
2405                }
2406            }
2407            else {
2408                v.iconst(arguments.size());
2409                v.newarray(elementType);
2410                for (int i = 0; i != size; ++i) {
2411                    v.dup();
2412                    v.iconst(i);
2413                    gen(arguments.get(i).getArgumentExpression(), elementType);
2414                    StackValue.arrayElement(elementType, false).store(elementType, v);
2415                }
2416            }
2417        }
2418    
2419        @NotNull
2420        public Type expressionType(JetExpression expr) {
2421            return asmTypeOrVoid(bindingContext.get(EXPRESSION_TYPE, expr));
2422        }
2423    
2424        public int indexOfLocal(JetReferenceExpression lhs) {
2425            DeclarationDescriptor declarationDescriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, lhs);
2426            if (isVarCapturedInClosure(bindingContext, declarationDescriptor)) {
2427                return -1;
2428            }
2429            return lookupLocalIndex(declarationDescriptor);
2430        }
2431    
2432        @Override
2433        public StackValue visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, StackValue data) {
2434            // TODO: properties
2435            FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
2436            assert functionDescriptor != null : "Callable reference is not resolved to descriptor: " + expression.getText();
2437    
2438            ResolvedCall<?> resolvedCall = bindingContext.get(RESOLVED_CALL, expression.getCallableReference());
2439            assert resolvedCall != null : "Callable reference is not resolved: " + functionDescriptor + " " + expression.getText();
2440    
2441            JetType kFunctionType = bindingContext.get(EXPRESSION_TYPE, expression);
2442            assert kFunctionType != null : "Callable reference is not type checked: " + expression.getText();
2443            ClassDescriptor kFunctionImpl = functionTypeToImpl(kFunctionType);
2444            assert kFunctionImpl != null : "Impl type is not found for the function type: " + kFunctionType;
2445    
2446            Type closureSuperClass = typeMapper.mapType(kFunctionImpl);
2447    
2448            CallableReferenceGenerationStrategy strategy = new CallableReferenceGenerationStrategy(state, functionDescriptor, resolvedCall);
2449            ClosureCodegen closureCodegen = new ClosureCodegen(state, expression, functionDescriptor, null, closureSuperClass, context,
2450                                                               KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER,
2451                                                               this, strategy, getParentCodegen());
2452    
2453            closureCodegen.gen();
2454    
2455            return closureCodegen.putInstanceOnStack(v, this);
2456        }
2457    
2458        private static class CallableReferenceGenerationStrategy extends FunctionGenerationStrategy.CodegenBased<FunctionDescriptor> {
2459            private final ResolvedCall<?> resolvedCall;
2460            private final FunctionDescriptor referencedFunction;
2461    
2462            public CallableReferenceGenerationStrategy(
2463                    @NotNull GenerationState state,
2464                    @NotNull FunctionDescriptor functionDescriptor,
2465                    @NotNull ResolvedCall<?> resolvedCall
2466            ) {
2467                super(state, functionDescriptor);
2468                this.resolvedCall = resolvedCall;
2469                this.referencedFunction = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
2470            }
2471    
2472            @Override
2473            public void doGenerateBody(@NotNull ExpressionCodegen codegen, @NotNull JvmMethodSignature signature) {
2474                /*
2475                 Here we need to put the arguments from our locals to the stack and invoke the referenced method. Since invocation
2476                 of methods is highly dependent on expressions, we create a fake call expression. Then we create a new instance of
2477                 ExpressionCodegen and, in order for it to generate code correctly, we save to its 'tempVariables' field every
2478                 argument of our fake expression, pointing it to the corresponding index in our locals. This way generation of
2479                 every argument boils down to calling LOAD with the corresponding index
2480                 */
2481    
2482                JetCallExpression fakeExpression = constructFakeFunctionCall();
2483                final List<? extends ValueArgument> fakeArguments = fakeExpression.getValueArguments();
2484    
2485                final ReceiverValue thisObject = computeAndSaveReceiver(signature, codegen, referencedFunction.getExpectedThisObject());
2486                final ReceiverValue extensionReceiver = computeAndSaveReceiver(signature, codegen, referencedFunction.getReceiverParameter());
2487                computeAndSaveArguments(fakeArguments, codegen);
2488    
2489                ResolvedCall<CallableDescriptor> fakeResolvedCall = new DelegatingResolvedCall<CallableDescriptor>(resolvedCall) {
2490                    @NotNull
2491                    @Override
2492                    public ReceiverValue getReceiverArgument() {
2493                        return extensionReceiver;
2494                    }
2495    
2496                    @NotNull
2497                    @Override
2498                    public ReceiverValue getThisObject() {
2499                        return thisObject;
2500                    }
2501    
2502                    @NotNull
2503                    @Override
2504                    public List<ResolvedValueArgument> getValueArgumentsByIndex() {
2505                        List<ResolvedValueArgument> result = new ArrayList<ResolvedValueArgument>(fakeArguments.size());
2506                        for (ValueArgument argument : fakeArguments) {
2507                            result.add(new ExpressionValueArgument(argument));
2508                        }
2509                        return result;
2510                    }
2511                };
2512    
2513                StackValue result;
2514                Type returnType = codegen.returnType;
2515                if (referencedFunction instanceof ConstructorDescriptor) {
2516                    if (returnType.getSort() == Type.ARRAY) {
2517                        //noinspection ConstantConditions
2518                        codegen.generateNewArray(fakeExpression, referencedFunction.getReturnType());
2519                        result = StackValue.onStack(returnType);
2520                    }
2521                    else {
2522                        result = codegen.generateConstructorCall(fakeResolvedCall, StackValue.none(), returnType);
2523                    }
2524                }
2525                else {
2526                    Call call = CallMaker.makeCall(fakeExpression, NO_RECEIVER, null, fakeExpression, fakeArguments);
2527                    Callable callable = codegen.resolveToCallable(codegen.accessibleFunctionDescriptor(referencedFunction), false);
2528                    StackValue receiver = generateCallee(codegen, callable);
2529                    if (extensionReceiver.exists()) {
2530                        receiver = StackValue.composed(receiver, receiverParameterStackValue(signature));
2531                    }
2532                    result = codegen.invokeFunctionWithCalleeOnStack(call, receiver, fakeResolvedCall, callable);
2533                }
2534    
2535                InstructionAdapter v = codegen.v;
2536                result.put(returnType, v);
2537                v.areturn(returnType);
2538            }
2539    
2540            @NotNull
2541            private StackValue generateCallee(@NotNull ExpressionCodegen codegen, @NotNull Callable callable) {
2542                if (!(callable instanceof CallableMethod) || ((CallableMethod) callable).getGenerateCalleeType() == null) {
2543                    return StackValue.none();
2544                }
2545    
2546                // If referenced method is a CallableMethod with generateCalleeType != null, this means it's some kind of a closure
2547                // (e.g. a local named function) and a non-trivial callee should be generated before calling invoke()
2548    
2549                BindingContext bindingContext = codegen.bindingContext;
2550                ClassDescriptor closureClassOfReferenced = bindingContext.get(CLASS_FOR_FUNCTION, referencedFunction);
2551                MutableClosure closureOfReferenced = bindingContext.get(CLOSURE, closureClassOfReferenced);
2552                assert closureOfReferenced != null :
2553                        "Function mapped to CallableMethod with generateCalleeType != null must be a closure: " + referencedFunction;
2554                if (isConst(closureOfReferenced)) {
2555                    // This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance
2556                    // (instead of passing this instance to the constructor and storing as a field)
2557                    Type asmType = asmTypeForAnonymousClass(bindingContext, referencedFunction);
2558                    codegen.v.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
2559                    return StackValue.onStack(asmType);
2560                }
2561                else {
2562                    Type asmCallRefType = asmTypeForAnonymousClass(bindingContext, callableDescriptor);
2563                    return codegen.context.lookupInContext(referencedFunction, StackValue.local(0, asmCallRefType), state, false);
2564                }
2565            }
2566    
2567            @NotNull
2568            private JetCallExpression constructFakeFunctionCall() {
2569                StringBuilder fakeFunctionCall = new StringBuilder("callableReferenceFakeCall(");
2570                for (Iterator<ValueParameterDescriptor> iterator = referencedFunction.getValueParameters().iterator(); iterator.hasNext(); ) {
2571                    ValueParameterDescriptor descriptor = iterator.next();
2572                    fakeFunctionCall.append("p").append(descriptor.getIndex());
2573                    if (iterator.hasNext()) {
2574                        fakeFunctionCall.append(", ");
2575                    }
2576                }
2577                fakeFunctionCall.append(")");
2578                return (JetCallExpression) JetPsiFactory.createExpression(state.getProject(), fakeFunctionCall.toString());
2579            }
2580    
2581            private void computeAndSaveArguments(@NotNull List<? extends ValueArgument> fakeArguments, @NotNull ExpressionCodegen codegen) {
2582                for (ValueParameterDescriptor parameter : callableDescriptor.getValueParameters()) {
2583                    ValueArgument fakeArgument = fakeArguments.get(parameter.getIndex());
2584                    Type type = state.getTypeMapper().mapType(parameter);
2585                    int localIndex = codegen.myFrameMap.getIndex(parameter);
2586                    codegen.tempVariables.put(fakeArgument.getArgumentExpression(), StackValue.local(localIndex, type));
2587                }
2588            }
2589    
2590            @NotNull
2591            private ReceiverValue computeAndSaveReceiver(
2592                    @NotNull JvmMethodSignature signature,
2593                    @NotNull ExpressionCodegen codegen,
2594                    @Nullable ReceiverParameterDescriptor receiver
2595            ) {
2596                if (receiver == null) return NO_RECEIVER;
2597    
2598                JetExpression receiverExpression = JetPsiFactory.createExpression(state.getProject(), "callableReferenceFakeReceiver");
2599                codegen.tempVariables.put(receiverExpression, receiverParameterStackValue(signature));
2600                return new ExpressionReceiver(receiverExpression, receiver.getType());
2601            }
2602    
2603            @NotNull
2604            private static StackValue.Local receiverParameterStackValue(@NotNull JvmMethodSignature signature) {
2605                // 0 is this (the callable reference class), 1 is the invoke() method's first parameter
2606                return StackValue.local(1, signature.getAsmMethod().getArgumentTypes()[0]);
2607            }
2608        }
2609    
2610        @Override
2611        public StackValue visitDotQualifiedExpression(@NotNull JetDotQualifiedExpression expression, StackValue receiver) {
2612            StackValue receiverValue = StackValue.none();
2613            return genQualified(receiverValue, expression.getSelectorExpression());
2614        }
2615    
2616        @Override
2617        public StackValue visitSafeQualifiedExpression(@NotNull JetSafeQualifiedExpression expression, StackValue unused) {
2618            JetExpression receiver = expression.getReceiverExpression();
2619            JetExpression selector = expression.getSelectorExpression();
2620            Type type = boxType(expressionType(expression));
2621            Type receiverType = expressionType(receiver);
2622    
2623            gen(receiver, receiverType);
2624    
2625            if (isPrimitive(receiverType)) {
2626                StackValue propValue = genQualified(StackValue.onStack(receiverType), selector);
2627                propValue.put(type, v);
2628    
2629                return StackValue.onStack(type);
2630            }
2631    
2632            Label ifnull = new Label();
2633            Label end = new Label();
2634            v.dup();
2635            v.ifnull(ifnull);
2636            StackValue propValue = genQualified(StackValue.onStack(receiverType), selector);
2637            propValue.put(type, v);
2638            v.goTo(end);
2639    
2640            v.mark(ifnull);
2641            v.pop();
2642            if (!type.equals(Type.VOID_TYPE)) {
2643                v.aconst(null);
2644            }
2645            v.mark(end);
2646    
2647            return StackValue.onStack(type);
2648        }
2649    
2650        @Override
2651        public StackValue visitBinaryExpression(@NotNull JetBinaryExpression expression, StackValue receiver) {
2652            JetSimpleNameExpression reference = expression.getOperationReference();
2653            IElementType opToken = reference.getReferencedNameElementType();
2654            if (opToken == JetTokens.EQ) {
2655                return generateAssignmentExpression(expression);
2656            }
2657            else if (JetTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) {
2658                return generateAugmentedAssignment(expression);
2659            }
2660            else if (opToken == JetTokens.ANDAND) {
2661                return generateBooleanAnd(expression);
2662            }
2663            else if (opToken == JetTokens.OROR) {
2664                return generateBooleanOr(expression);
2665            }
2666            else if (opToken == JetTokens.EQEQ || opToken == JetTokens.EXCLEQ ||
2667                     opToken == JetTokens.EQEQEQ || opToken == JetTokens.EXCLEQEQEQ) {
2668                return generateEquals(expression.getLeft(), expression.getRight(), opToken);
2669            }
2670            else if (opToken == JetTokens.LT || opToken == JetTokens.LTEQ ||
2671                     opToken == JetTokens.GT || opToken == JetTokens.GTEQ) {
2672                return generateComparison(expression, receiver);
2673            }
2674            else if (opToken == JetTokens.ELVIS) {
2675                return generateElvis(expression);
2676            }
2677            else if (opToken == JetTokens.IN_KEYWORD || opToken == JetTokens.NOT_IN) {
2678                return generateIn(StackValue.expression(Type.INT_TYPE, expression.getLeft(), this), expression.getRight(), reference);
2679            }
2680            else {
2681                ResolvedCall<?> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, reference);
2682                Call call = bindingContext.get(BindingContext.CALL, reference);
2683    
2684                DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, reference);
2685                assert op instanceof FunctionDescriptor : String.valueOf(op);
2686                Callable callable = resolveToCallable((FunctionDescriptor) op, false);
2687                if (callable instanceof IntrinsicMethod) {
2688                    //noinspection ConstantConditions
2689                    Type returnType = typeMapper.mapType(resolvedCall.getResultingDescriptor());
2690                    ((IntrinsicMethod) callable).generate(this, v, returnType, expression,
2691                                                          Arrays.asList(expression.getLeft(), expression.getRight()), receiver);
2692                    return StackValue.onStack(returnType);
2693                }
2694                else {
2695                    return invokeFunction(call, receiver, resolvedCall);
2696                }
2697            }
2698        }
2699    
2700        private StackValue generateIn(StackValue leftValue, JetExpression rangeExpression, JetSimpleNameExpression operationReference) {
2701            JetExpression deparenthesized = JetPsiUtil.deparenthesize(rangeExpression);
2702            if (isIntRangeExpr(deparenthesized)) {
2703                genInIntRange(leftValue, (JetBinaryExpression) deparenthesized);
2704            }
2705            else {
2706                invokeFunctionByReference(operationReference);
2707            }
2708            if (operationReference.getReferencedNameElementType() == JetTokens.NOT_IN) {
2709                genInvertBoolean(v);
2710            }
2711            return StackValue.onStack(Type.BOOLEAN_TYPE);
2712        }
2713    
2714        private void genInIntRange(StackValue leftValue, JetBinaryExpression rangeExpression) {
2715            v.iconst(1);
2716            // 1
2717            leftValue.put(Type.INT_TYPE, v);
2718            // 1 l
2719            v.dup2();
2720            // 1 l 1 l
2721    
2722            //noinspection ConstantConditions
2723            gen(rangeExpression.getLeft(), Type.INT_TYPE);
2724            // 1 l 1 l r
2725            Label lok = new Label();
2726            v.ificmpge(lok);
2727            // 1 l 1
2728            v.pop();
2729            v.iconst(0);
2730            v.mark(lok);
2731            // 1 l c
2732            v.dupX2();
2733            // c 1 l c
2734            v.pop();
2735            // c 1 l
2736    
2737            gen(rangeExpression.getRight(), Type.INT_TYPE);
2738            // c 1 l r
2739            Label rok = new Label();
2740            v.ificmple(rok);
2741            // c 1
2742            v.pop();
2743            v.iconst(0);
2744            v.mark(rok);
2745            // c c
2746    
2747            v.and(Type.INT_TYPE);
2748        }
2749    
2750        private StackValue generateBooleanAnd(JetBinaryExpression expression) {
2751            gen(expression.getLeft(), Type.BOOLEAN_TYPE);
2752            Label ifFalse = new Label();
2753            v.ifeq(ifFalse);
2754            gen(expression.getRight(), Type.BOOLEAN_TYPE);
2755            Label end = new Label();
2756            v.goTo(end);
2757            v.mark(ifFalse);
2758            v.iconst(0);
2759            v.mark(end);
2760            return StackValue.onStack(Type.BOOLEAN_TYPE);
2761        }
2762    
2763        private StackValue generateBooleanOr(JetBinaryExpression expression) {
2764            gen(expression.getLeft(), Type.BOOLEAN_TYPE);
2765            Label ifTrue = new Label();
2766            v.ifne(ifTrue);
2767            gen(expression.getRight(), Type.BOOLEAN_TYPE);
2768            Label end = new Label();
2769            v.goTo(end);
2770            v.mark(ifTrue);
2771            v.iconst(1);
2772            v.mark(end);
2773            return StackValue.onStack(Type.BOOLEAN_TYPE);
2774        }
2775    
2776        private StackValue generateEquals(JetExpression left, JetExpression right, IElementType opToken) {
2777            Type leftType = expressionType(left);
2778            Type rightType = expressionType(right);
2779    
2780            if (JetPsiUtil.isNullConstant(left)) {
2781                return genCmpWithNull(right, rightType, opToken);
2782            }
2783    
2784            if (JetPsiUtil.isNullConstant(right)) {
2785                return genCmpWithNull(left, leftType, opToken);
2786            }
2787    
2788            if (isIntZero(left, leftType) && isIntPrimitive(rightType)) {
2789                return genCmpWithZero(right, rightType, opToken);
2790            }
2791    
2792            if (isIntZero(right, rightType) && isIntPrimitive(leftType)) {
2793                return genCmpWithZero(left, leftType, opToken);
2794            }
2795    
2796            if (isPrimitive(leftType) != isPrimitive(rightType)) {
2797                leftType = boxType(leftType);
2798                gen(left, leftType);
2799                rightType = boxType(rightType);
2800                gen(right, rightType);
2801            }
2802            else {
2803                gen(left, leftType);
2804                gen(right, rightType);
2805            }
2806    
2807            return genEqualsForExpressionsOnStack(v, opToken, leftType, rightType);
2808        }
2809    
2810        private boolean isIntZero(JetExpression expr, Type exprType) {
2811            CompileTimeConstant<?> exprValue = getCompileTimeConstant(expr, bindingContext);
2812            return isIntPrimitive(exprType) && exprValue != null && Integer.valueOf(0).equals(exprValue.getValue());
2813        }
2814    
2815        private StackValue genCmpWithZero(JetExpression exp, Type expType, IElementType opToken) {
2816            v.iconst(1);
2817            gen(exp, expType);
2818            Label ok = new Label();
2819            if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) {
2820                v.ifeq(ok);
2821            }
2822            else {
2823                v.ifne(ok);
2824            }
2825            v.pop();
2826            v.iconst(0);
2827            v.mark(ok);
2828            return StackValue.onStack(Type.BOOLEAN_TYPE);
2829        }
2830    
2831        private StackValue genCmpWithNull(JetExpression exp, Type expType, IElementType opToken) {
2832            v.iconst(1);
2833            gen(exp, boxType(expType));
2834            Label ok = new Label();
2835            if (JetTokens.EQEQ == opToken || JetTokens.EQEQEQ == opToken) {
2836                v.ifnull(ok);
2837            }
2838            else {
2839                v.ifnonnull(ok);
2840            }
2841            v.pop();
2842            v.iconst(0);
2843            v.mark(ok);
2844            return StackValue.onStack(Type.BOOLEAN_TYPE);
2845        }
2846    
2847        private StackValue generateElvis(JetBinaryExpression expression) {
2848            Type exprType = expressionType(expression);
2849            Type leftType = expressionType(expression.getLeft());
2850    
2851            gen(expression.getLeft(), leftType);
2852    
2853            if (isPrimitive(leftType)) {
2854                return StackValue.onStack(leftType);
2855            }
2856    
2857            v.dup();
2858            Label ifNull = new Label();
2859            v.ifnull(ifNull);
2860            StackValue.onStack(leftType).put(exprType, v);
2861            Label end = new Label();
2862            v.goTo(end);
2863            v.mark(ifNull);
2864            v.pop();
2865            gen(expression.getRight(), exprType);
2866            v.mark(end);
2867    
2868            return StackValue.onStack(exprType);
2869        }
2870    
2871        private StackValue generateComparison(JetBinaryExpression expression, StackValue receiver) {
2872            DeclarationDescriptor target = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
2873            assert target instanceof FunctionDescriptor : "compareTo target should be a function: " + target;
2874            FunctionDescriptor descriptor = (FunctionDescriptor) target;
2875    
2876            JetExpression left = expression.getLeft();
2877            JetExpression right = expression.getRight();
2878            Callable callable = resolveToCallable(descriptor, false);
2879    
2880            Type type;
2881            if (callable instanceof IntrinsicMethod) {
2882                // Compare two primitive values
2883                type = comparisonOperandType(expressionType(left), expressionType(right));
2884                StackValue recv = gen(left);
2885                recv.put(type, v);
2886                gen(right, type);
2887            }
2888            else {
2889                ResolvedCall<?> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
2890                Call call = bindingContext.get(BindingContext.CALL, expression.getOperationReference());
2891                StackValue result = invokeFunction(call, receiver, resolvedCall);
2892                type = Type.INT_TYPE;
2893                result.put(type, v);
2894                v.iconst(0);
2895            }
2896            return StackValue.cmp(expression.getOperationToken(), type);
2897        }
2898    
2899        private StackValue generateAssignmentExpression(JetBinaryExpression expression) {
2900            StackValue stackValue = gen(expression.getLeft());
2901            JetExpression right = expression.getRight();
2902            assert right != null : expression.getText();
2903            gen(right, stackValue.type);
2904            stackValue.store(stackValue.type, v);
2905            return StackValue.none();
2906        }
2907    
2908        private StackValue generateAugmentedAssignment(JetBinaryExpression expression) {
2909            DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
2910            assert op instanceof FunctionDescriptor : String.valueOf(op);
2911            Callable callable = resolveToCallable((FunctionDescriptor) op, false);
2912            JetExpression lhs = expression.getLeft();
2913    
2914            //        if (lhs instanceof JetArrayAccessExpression) {
2915            //            JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) lhs;
2916            //            if (arrayAccessExpression.getIndexExpressions().size() != 1) {
2917            //                throw new UnsupportedOperationException("Augmented assignment with multi-index");
2918            //            }
2919            //        }
2920    
2921            Type lhsType = expressionType(lhs);
2922            //noinspection ConstantConditions
2923            if (bindingContext.get(BindingContext.VARIABLE_REASSIGNMENT, expression)) {
2924                if (callable instanceof IntrinsicMethod) {
2925                    StackValue value = gen(lhs);              // receiver
2926                    value.dupReceiver(v);                                        // receiver receiver
2927                    value.put(lhsType, v);                                          // receiver lhs
2928                    IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
2929                    JetExpression right = expression.getRight();
2930                    assert right != null;
2931                    Type returnType = typeMapper.mapType((FunctionDescriptor) op);
2932                    intrinsic.generate(this, v, returnType, expression, Collections.singletonList(right), StackValue.onStack(lhsType));
2933                    value.store(lhsType, v);
2934                }
2935                else {
2936                    callAugAssignMethod(expression, (CallableMethod) callable, lhsType, true);
2937                }
2938            }
2939            else {
2940                JetType type = ((FunctionDescriptor) op).getReturnType();
2941                assert type != null;
2942                boolean keepReturnValue = !type.equals(KotlinBuiltIns.getInstance().getUnitType());
2943                callAugAssignMethod(expression, (CallableMethod) callable, lhsType, keepReturnValue);
2944            }
2945    
2946            return StackValue.none();
2947        }
2948    
2949        private void callAugAssignMethod(JetBinaryExpression expression, CallableMethod callable, Type lhsType, boolean keepReturnValue) {
2950            JetSimpleNameExpression reference = expression.getOperationReference();
2951            ResolvedCall<?> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, reference);
2952            Call call = bindingContext.get(BindingContext.CALL, reference);
2953    
2954            assert resolvedCall != null : "Resolved call should be not null for operation reference in " + expression.getText();
2955            assert call != null : "Call should be not null for operation reference in " + expression.getText();
2956    
2957            StackValue value = gen(expression.getLeft());
2958            if (keepReturnValue) {
2959                value.dupReceiver(v);
2960            }
2961            value.put(lhsType, v);
2962            StackValue receiver = StackValue.onStack(lhsType);
2963    
2964            invokeMethodWithArguments(call, callable, resolvedCall, receiver);
2965    
2966            if (keepReturnValue) {
2967                value.store(callable.getReturnType(), v);
2968            }
2969        }
2970    
2971        public void invokeAppend(JetExpression expr) {
2972            if (expr instanceof JetBinaryExpression) {
2973                JetBinaryExpression binaryExpression = (JetBinaryExpression) expr;
2974                if (binaryExpression.getOperationToken() == JetTokens.PLUS) {
2975                    JetExpression left = binaryExpression.getLeft();
2976                    JetExpression right = binaryExpression.getRight();
2977                    Type leftType = expressionType(left);
2978                    Type rightType = expressionType(right);
2979    
2980                    if (leftType.equals(JAVA_STRING_TYPE) && rightType.equals(JAVA_STRING_TYPE)) {
2981                        invokeAppend(left);
2982                        invokeAppend(right);
2983                        return;
2984                    }
2985                }
2986            }
2987            Type exprType = expressionType(expr);
2988            gen(expr, exprType);
2989            genInvokeAppendMethod(v, exprType.getSort() == Type.ARRAY ? OBJECT_TYPE : exprType);
2990        }
2991    
2992        @Nullable
2993        private static JetSimpleNameExpression targetLabel(JetExpression expression) {
2994            if (expression.getParent() instanceof JetPrefixExpression) {
2995                JetPrefixExpression parent = (JetPrefixExpression) expression.getParent();
2996                JetSimpleNameExpression operationSign = parent.getOperationReference();
2997                if (JetTokens.LABELS.contains(operationSign.getReferencedNameElementType())) {
2998                    return operationSign;
2999                }
3000            }
3001            return null;
3002        }
3003    
3004        @Override
3005        public StackValue visitPrefixExpression(@NotNull JetPrefixExpression expression, StackValue receiver) {
3006            JetSimpleNameExpression operationSign = expression.getOperationReference();
3007            if (JetTokens.LABELS.contains(operationSign.getReferencedNameElementType())) {
3008                return genQualified(receiver, expression.getBaseExpression());
3009            }
3010    
3011            DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
3012            assert op instanceof FunctionDescriptor : String.valueOf(op);
3013            Callable callable = resolveToCallable((FunctionDescriptor) op, false);
3014            if (callable instanceof IntrinsicMethod) {
3015                Type returnType = typeMapper.mapType((FunctionDescriptor) op);
3016                ((IntrinsicMethod) callable).generate(this, v, returnType, expression,
3017                                                      Collections.singletonList(expression.getBaseExpression()), receiver);
3018                return StackValue.onStack(returnType);
3019            }
3020    
3021            DeclarationDescriptor cls = op.getContainingDeclaration();
3022            ResolvedCall<?> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
3023            assert resolvedCall != null;
3024    
3025            if (isPrimitiveNumberClassDescriptor(cls) || !(op.getName().asString().equals("inc") || op.getName().asString().equals("dec"))) {
3026                Call call = bindingContext.get(BindingContext.CALL, expression.getOperationReference());
3027                return invokeFunction(call, receiver, resolvedCall);
3028            }
3029    
3030            CallableMethod callableMethod = (CallableMethod) callable;
3031    
3032            StackValue value = gen(expression.getBaseExpression());
3033            value.dupReceiver(v);
3034            value.dupReceiver(v);
3035    
3036            Type type = expressionType(expression.getBaseExpression());
3037            value.put(type, v);
3038            callableMethod.invokeWithNotNullAssertion(v, state, resolvedCall);
3039    
3040            value.store(callableMethod.getReturnType(), v);
3041            value.put(type, v);
3042            return StackValue.onStack(type);
3043        }
3044    
3045        @Override
3046        public StackValue visitPostfixExpression(@NotNull JetPostfixExpression expression, StackValue receiver) {
3047            if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL) {
3048                StackValue base = genQualified(receiver, expression.getBaseExpression());
3049                if (isPrimitive(base.type)) {
3050                    return base;
3051                }
3052                base.put(base.type, v);
3053                v.dup();
3054                Label ok = new Label();
3055                v.ifnonnull(ok);
3056                v.invokestatic("kotlin/jvm/internal/Intrinsics", "throwNpe", "()V");
3057                v.mark(ok);
3058                return StackValue.onStack(base.type);
3059            }
3060    
3061            DeclarationDescriptor op = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getOperationReference());
3062            if (!(op instanceof FunctionDescriptor)) {
3063                throw new UnsupportedOperationException("Don't know how to generate this postfix expression: " + op);
3064            }
3065    
3066            Type asmType = expressionType(expression);
3067            DeclarationDescriptor cls = op.getContainingDeclaration();
3068    
3069            int increment;
3070            if (op.getName().asString().equals("inc")) {
3071                increment = 1;
3072            }
3073            else if (op.getName().asString().equals("dec")) {
3074                increment = -1;
3075            }
3076            else {
3077                throw new UnsupportedOperationException("Unsupported postfix operation: " + op);
3078            }
3079    
3080            boolean isPrimitiveNumberClassDescriptor = isPrimitiveNumberClassDescriptor(cls);
3081            if (isPrimitiveNumberClassDescriptor) {
3082                JetExpression operand = expression.getBaseExpression();
3083                if (operand instanceof JetReferenceExpression && asmType == Type.INT_TYPE) {
3084                    int index = indexOfLocal((JetReferenceExpression) operand);
3085                    if (index >= 0) {
3086                        return StackValue.postIncrement(index, increment);
3087                    }
3088                }
3089            }
3090    
3091            StackValue value = gen(expression.getBaseExpression());
3092            value.dupReceiver(v);
3093    
3094            Type type = expressionType(expression.getBaseExpression());
3095            value.put(type, v); // old value
3096    
3097            pushReceiverAndValueViaDup(value, type); // receiver and new value
3098    
3099            Type storeType;
3100            if (isPrimitiveNumberClassDescriptor) {
3101                genIncrement(asmType, increment, v);
3102                storeType = type;
3103            }
3104            else {
3105                ResolvedCall<?> resolvedCall = bindingContext.get(BindingContext.RESOLVED_CALL, expression.getOperationReference());
3106                assert resolvedCall != null;
3107                Callable callable = resolveToCallable((FunctionDescriptor) op, false);
3108                CallableMethod callableMethod = (CallableMethod) callable;
3109                callableMethod.invokeWithNotNullAssertion(v, state, resolvedCall);
3110                storeType = callableMethod.getReturnType();
3111            }
3112    
3113            value.store(storeType, v);
3114            return StackValue.onStack(asmType);  // old value
3115        }
3116    
3117        private void pushReceiverAndValueViaDup(StackValue value, Type type) {
3118            switch (value.receiverSize()) {
3119                case 0:
3120                    dup(v, type);
3121                    break;
3122    
3123                case 1:
3124                    if (type.getSize() == 2) {
3125                        v.dup2X1();
3126                    }
3127                    else {
3128                        v.dupX1();
3129                    }
3130                    break;
3131    
3132                case 2:
3133                    if (type.getSize() == 2) {
3134                        v.dup2X2();
3135                    }
3136                    else {
3137                        v.dupX2();
3138                    }
3139                    break;
3140    
3141                case -1:
3142                    throw new UnsupportedOperationException();
3143            }
3144        }
3145    
3146        @Override
3147        public StackValue visitProperty(@NotNull JetProperty property, StackValue receiver) {
3148            final JetExpression initializer = property.getInitializer();
3149            if (initializer == null) {
3150                return StackValue.none();
3151            }
3152            initializeLocalVariable(property, new Function<VariableDescriptor, Void>() {
3153                @Override
3154                public Void fun(VariableDescriptor descriptor) {
3155                    Type varType = asmType(descriptor.getType());
3156                    gen(initializer, varType);
3157                    return null;
3158                }
3159            });
3160            return StackValue.none();
3161        }
3162    
3163        @Override
3164        public StackValue visitMultiDeclaration(@NotNull JetMultiDeclaration multiDeclaration, StackValue receiver) {
3165            JetExpression initializer = multiDeclaration.getInitializer();
3166            if (initializer == null) return StackValue.none();
3167    
3168            JetType initializerType = bindingContext.get(EXPRESSION_TYPE, initializer);
3169            assert initializerType != null;
3170    
3171            Type initializerAsmType = asmType(initializerType);
3172    
3173            final TransientReceiver initializerAsReceiver = new TransientReceiver(initializerType);
3174    
3175            int tempVarIndex = myFrameMap.enterTemp(initializerAsmType);
3176    
3177            gen(initializer, initializerAsmType);
3178            v.store(tempVarIndex, initializerAsmType);
3179            final StackValue.Local local = StackValue.local(tempVarIndex, initializerAsmType);
3180    
3181            for (final JetMultiDeclarationEntry variableDeclaration : multiDeclaration.getEntries()) {
3182                initializeLocalVariable(variableDeclaration, new Function<VariableDescriptor, Void>() {
3183                    @Override
3184                    public Void fun(VariableDescriptor descriptor) {
3185                        ResolvedCall<FunctionDescriptor> resolvedCall =
3186                                bindingContext.get(BindingContext.COMPONENT_RESOLVED_CALL, variableDeclaration);
3187                        assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText();
3188                        Call call = makeFakeCall(initializerAsReceiver);
3189                        invokeFunction(call, local, resolvedCall);
3190                        return null;
3191                    }
3192                });
3193            }
3194    
3195            if(initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) {
3196                v.aconst(null);
3197                v.store(tempVarIndex, initializerAsmType);
3198            }
3199            myFrameMap.leaveTemp(initializerAsmType);
3200    
3201            return StackValue.none();
3202        }
3203    
3204        private void initializeLocalVariable(
3205                @NotNull JetVariableDeclaration variableDeclaration,
3206                @NotNull Function<VariableDescriptor, Void> generateInitializer
3207        ) {
3208    
3209            VariableDescriptor variableDescriptor = bindingContext.get(BindingContext.VARIABLE, variableDeclaration);
3210    
3211            if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) {
3212                return;
3213            }
3214            int index = lookupLocalIndex(variableDescriptor);
3215    
3216            if (index < 0) {
3217                throw new IllegalStateException("Local variable not found for " + variableDescriptor);
3218            }
3219    
3220            Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
3221            assert variableDescriptor != null;
3222    
3223            Type varType = asmType(variableDescriptor.getType());
3224    
3225            if (JetPsiUtil.isScriptDeclaration(variableDeclaration)) {
3226                generateInitializer.fun(variableDescriptor);
3227                JetScript scriptPsi = JetPsiUtil.getScript(variableDeclaration);
3228                assert scriptPsi != null;
3229                Type scriptClassType = asmTypeForScriptPsi(bindingContext, scriptPsi);
3230                v.putfield(scriptClassType.getInternalName(), variableDeclaration.getName(), varType.getDescriptor());
3231            }
3232            else if (sharedVarType == null) {
3233                generateInitializer.fun(variableDescriptor);
3234                v.store(index, varType);
3235            }
3236            else {
3237                v.load(index, OBJECT_TYPE);
3238                generateInitializer.fun(variableDescriptor);
3239                v.putfield(sharedVarType.getInternalName(), "element",
3240                           sharedVarType.equals(OBJECT_REF_TYPE) ? "Ljava/lang/Object;" : varType.getDescriptor());
3241            }
3242        }
3243    
3244        @NotNull
3245        private StackValue generateNewCall(
3246                @NotNull JetCallExpression expression,
3247                @NotNull ResolvedCall<?> resolvedCall,
3248                @NotNull StackValue receiver
3249        ) {
3250            Type type = expressionType(expression);
3251            if (type.getSort() == Type.ARRAY) {
3252                generateNewArray(expression);
3253                return StackValue.onStack(type);
3254            }
3255    
3256            return generateConstructorCall(resolvedCall, receiver, type);
3257        }
3258    
3259        @NotNull
3260        private StackValue generateConstructorCall(@NotNull ResolvedCall<?> resolvedCall, @NotNull StackValue receiver, @NotNull Type type) {
3261            v.anew(type);
3262            v.dup();
3263    
3264            receiver = StackValue.receiver(resolvedCall, receiver, this, null);
3265            receiver.put(receiver.type, v);
3266    
3267            ConstructorDescriptor constructorDescriptor = (ConstructorDescriptor) resolvedCall.getResultingDescriptor();
3268            MutableClosure closure = bindingContext.get(CLOSURE, constructorDescriptor.getContainingDeclaration());
3269    
3270            ClassDescriptor descriptor = getExpectedThisObjectForConstructorCall(constructorDescriptor, closure);
3271            if (receiver.type.getSort() != Type.VOID && descriptor == null) {
3272                v.pop();
3273            }
3274    
3275            //Resolved call to local class constructor doesn't have resolvedCall.getThisObject() and resolvedCall.getReceiverArgument()
3276            //so we need generate closure on stack
3277            //See StackValue.receiver for more info
3278            pushClosureOnStack(closure, resolvedCall.getThisObject().exists() || resolvedCall.getReceiverArgument().exists(), defaulCallGenerator);
3279    
3280            ConstructorDescriptor originalOfSamAdapter = (ConstructorDescriptor) SamCodegenUtil.getOriginalIfSamAdapter(constructorDescriptor);
3281            CallableMethod method = typeMapper.mapToCallableMethod(originalOfSamAdapter == null ? constructorDescriptor : originalOfSamAdapter);
3282            invokeMethodWithArguments(null, method, resolvedCall, StackValue.none());
3283    
3284            return StackValue.onStack(type);
3285        }
3286    
3287        public void generateNewArray(@NotNull JetCallExpression expression) {
3288            JetType arrayType = bindingContext.get(EXPRESSION_TYPE, expression);
3289            assert arrayType != null : "Array instantiation isn't type checked: " + expression.getText();
3290    
3291            generateNewArray(expression, arrayType);
3292        }
3293    
3294        private void generateNewArray(@NotNull JetCallExpression expression, @NotNull JetType arrayType) {
3295            List<JetExpression> args = new ArrayList<JetExpression>();
3296            for (ValueArgument va : expression.getValueArguments()) {
3297                args.add(va.getArgumentExpression());
3298            }
3299            args.addAll(expression.getFunctionLiteralArguments());
3300    
3301            boolean isArray = KotlinBuiltIns.getInstance().isArray(arrayType);
3302            if (!isArray && args.size() != 1) {
3303                throw new CompilationException("primitive array constructor requires one argument", null, expression);
3304            }
3305    
3306            if (isArray) {
3307                gen(args.get(0), Type.INT_TYPE);
3308                v.newarray(boxType(asmType(arrayType.getArguments().get(0).getType())));
3309            }
3310            else {
3311                Type type = typeMapper.mapType(arrayType);
3312                gen(args.get(0), Type.INT_TYPE);
3313                v.newarray(correctElementType(type));
3314            }
3315    
3316            if (args.size() == 2) {
3317                int sizeIndex = myFrameMap.enterTemp(Type.INT_TYPE);
3318                int indexIndex = myFrameMap.enterTemp(Type.INT_TYPE);
3319    
3320                v.dup();
3321                v.arraylength();
3322                v.store(sizeIndex, Type.INT_TYPE);
3323    
3324                v.iconst(0);
3325                v.store(indexIndex, Type.INT_TYPE);
3326    
3327                gen(args.get(1), FUNCTION1_TYPE);
3328    
3329                Label begin = new Label();
3330                Label end = new Label();
3331                v.visitLabel(begin);
3332                v.load(indexIndex, Type.INT_TYPE);
3333                v.load(sizeIndex, Type.INT_TYPE);
3334                v.ificmpge(end);
3335    
3336                v.dup2();
3337                v.load(indexIndex, Type.INT_TYPE);
3338                v.invokestatic("java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
3339                v.invokeinterface(FUNCTION1_TYPE.getInternalName(), "invoke", "(Ljava/lang/Object;)Ljava/lang/Object;");
3340                v.load(indexIndex, Type.INT_TYPE);
3341                v.iinc(indexIndex, 1);
3342                v.swap();
3343                v.astore(OBJECT_TYPE);
3344    
3345                v.goTo(begin);
3346                v.visitLabel(end);
3347                v.pop();
3348    
3349                myFrameMap.leaveTemp(Type.INT_TYPE);
3350                myFrameMap.leaveTemp(Type.INT_TYPE);
3351            }
3352        }
3353    
3354        @Override
3355        public StackValue visitArrayAccessExpression(@NotNull JetArrayAccessExpression expression, StackValue receiver) {
3356            JetExpression array = expression.getArrayExpression();
3357            JetType type = bindingContext.get(BindingContext.EXPRESSION_TYPE, array);
3358            Type arrayType = asmTypeOrVoid(type);
3359            List<JetExpression> indices = expression.getIndexExpressions();
3360            FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(BindingContext.REFERENCE_TARGET, expression);
3361            assert operationDescriptor != null;
3362            if (arrayType.getSort() == Type.ARRAY &&
3363                indices.size() == 1 &&
3364                operationDescriptor.getValueParameters().get(0).getType().equals(KotlinBuiltIns.getInstance().getIntType())) {
3365                gen(array, arrayType);
3366                for (JetExpression index : indices) {
3367                    gen(index, Type.INT_TYPE);
3368                }
3369                assert type != null;
3370                if (KotlinBuiltIns.getInstance().isArray(type)) {
3371                    JetType elementType = type.getArguments().get(0).getType();
3372                    Type notBoxed = asmType(elementType);
3373                    return StackValue.arrayElement(notBoxed, true);
3374                }
3375                else {
3376                    return StackValue.arrayElement(correctElementType(arrayType), false);
3377                }
3378            }
3379            else {
3380                ResolvedCall<FunctionDescriptor> resolvedSetCall = bindingContext.get(BindingContext.INDEXED_LVALUE_SET, expression);
3381                ResolvedCall<FunctionDescriptor> resolvedGetCall = bindingContext.get(BindingContext.INDEXED_LVALUE_GET, expression);
3382    
3383                boolean isGetter = "get".equals(operationDescriptor.getName().asString());
3384    
3385                ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall;
3386                assert resolvedCall != null : "couldn't find resolved call: " + expression.getText();
3387    
3388                Callable callable = resolveToCallable(operationDescriptor, false);
3389                Method asmMethod = resolveToCallableMethod(operationDescriptor, false, context).getAsmMethod();
3390                Type[] argumentTypes = asmMethod.getArgumentTypes();
3391    
3392                if (callable instanceof CallableMethod) {
3393                    genThisAndReceiverFromResolvedCall(receiver, resolvedCall, (CallableMethod) callable);
3394                    boolean skipLast = !isGetter;
3395                    pushMethodArguments(resolvedCall, ((CallableMethod) callable).getValueParameterTypes(), skipLast, defaulCallGenerator);
3396                }
3397                else {
3398                    gen(array, arrayType); // intrinsic method
3399    
3400                    int index = operationDescriptor.getReceiverParameter() != null ? 1 : 0;
3401    
3402                    for (JetExpression jetExpression : expression.getIndexExpressions()) {
3403                        gen(jetExpression, argumentTypes[index]);
3404                        index++;
3405                    }
3406                }
3407    
3408                Type elementType = isGetter ? asmMethod.getReturnType() : ArrayUtil.getLastElement(argumentTypes);
3409                return StackValue.collectionElement(elementType, resolvedGetCall, resolvedSetCall, this, state);
3410            }
3411        }
3412    
3413        @Override
3414        public StackValue visitThrowExpression(@NotNull JetThrowExpression expression, StackValue receiver) {
3415            gen(expression.getThrownExpression(), JAVA_THROWABLE_TYPE);
3416            v.athrow();
3417            return StackValue.none();
3418        }
3419    
3420        @Override
3421        public StackValue visitThisExpression(@NotNull JetThisExpression expression, StackValue receiver) {
3422            DeclarationDescriptor descriptor = bindingContext.get(BindingContext.REFERENCE_TARGET, expression.getInstanceReference());
3423            if (descriptor instanceof ClassDescriptor) {
3424                return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor, false, true);
3425            }
3426            else {
3427                if (descriptor instanceof CallableDescriptor) {
3428                    return generateReceiver(descriptor);
3429                }
3430                throw new UnsupportedOperationException("neither this nor receiver");
3431            }
3432        }
3433    
3434        @Override
3435        public StackValue visitTryExpression(@NotNull JetTryExpression expression, StackValue receiver) {
3436            return generateTryExpression(expression, false);
3437        }
3438    
3439        public StackValue generateTryExpression(JetTryExpression expression, boolean isStatement) {
3440            /*
3441    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
3442    (or blocks).
3443             */
3444            JetFinallySection finallyBlock = expression.getFinallyBlock();
3445            FinallyBlockStackElement finallyBlockStackElement = null;
3446            if (finallyBlock != null) {
3447                finallyBlockStackElement = new FinallyBlockStackElement(expression);
3448                blockStackElements.push(finallyBlockStackElement);
3449            }
3450    
3451            JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expression);
3452            assert jetType != null;
3453            Type expectedAsmType = isStatement ? Type.VOID_TYPE : asmType(jetType);
3454    
3455            Label tryStart = new Label();
3456            v.mark(tryStart);
3457            v.nop(); // prevent verify error on empty try
3458    
3459            gen(expression.getTryBlock(), expectedAsmType);
3460    
3461            int savedValue = -1;
3462            if (!isStatement) {
3463                savedValue = myFrameMap.enterTemp(expectedAsmType);
3464                v.store(savedValue, expectedAsmType);
3465            }
3466    
3467            Label tryEnd = new Label();
3468            v.mark(tryEnd);
3469    
3470            //do it before finally block generation
3471            List<Label> tryBlockRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, tryEnd);
3472    
3473            Label end = new Label();
3474    
3475            genFinallyBlockOrGoto(finallyBlockStackElement, end);
3476    
3477            List<JetCatchClause> clauses = expression.getCatchClauses();
3478            for (int i = 0, size = clauses.size(); i < size; i++) {
3479                JetCatchClause clause = clauses.get(i);
3480    
3481                Label clauseStart = new Label();
3482                v.mark(clauseStart);
3483    
3484                VariableDescriptor descriptor = bindingContext.get(BindingContext.VALUE_PARAMETER, clause.getCatchParameter());
3485                assert descriptor != null;
3486                Type descriptorType = asmType(descriptor.getType());
3487                myFrameMap.enter(descriptor, descriptorType);
3488                int index = lookupLocalIndex(descriptor);
3489                v.store(index, descriptorType);
3490    
3491                gen(clause.getCatchBody(), expectedAsmType);
3492    
3493                if (!isStatement) {
3494                    v.store(savedValue, expectedAsmType);
3495                }
3496    
3497                myFrameMap.leave(descriptor);
3498    
3499                genFinallyBlockOrGoto(finallyBlockStackElement, i != size - 1 || finallyBlock != null ? end : null);
3500    
3501                generateExceptionTable(clauseStart, tryBlockRegions, descriptorType.getInternalName());
3502            }
3503    
3504    
3505            //for default catch clause
3506            if (finallyBlock != null) {
3507                Label defaultCatchStart = new Label();
3508                v.mark(defaultCatchStart);
3509                int savedException = myFrameMap.enterTemp(JAVA_THROWABLE_TYPE);
3510                v.store(savedException, JAVA_THROWABLE_TYPE);
3511                Label defaultCatchEnd = new Label();
3512                v.mark(defaultCatchEnd);
3513    
3514                //do it before finally block generation
3515                //javac also generates entry in exception table for default catch clause too!!!! so defaultCatchEnd as end parameter
3516                List<Label> defaultCatchRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, defaultCatchEnd);
3517    
3518    
3519                genFinallyBlockOrGoto(finallyBlockStackElement, null);
3520    
3521                v.load(savedException, JAVA_THROWABLE_TYPE);
3522                myFrameMap.leaveTemp(JAVA_THROWABLE_TYPE);
3523    
3524                v.athrow();
3525    
3526                generateExceptionTable(defaultCatchStart, defaultCatchRegions, null);
3527            }
3528    
3529            markLineNumber(expression);
3530            v.mark(end);
3531    
3532            if (!isStatement) {
3533                v.load(savedValue, expectedAsmType);
3534                myFrameMap.leaveTemp(expectedAsmType);
3535            }
3536    
3537            if (finallyBlock != null) {
3538                blockStackElements.pop();
3539            }
3540    
3541            return StackValue.onStack(expectedAsmType);
3542        }
3543    
3544        private void generateExceptionTable(@NotNull Label catchStart, @NotNull List<Label> catchedRegions, @Nullable String exception) {
3545            for (int i = 0; i < catchedRegions.size(); i += 2) {
3546                Label startRegion = catchedRegions.get(i);
3547                Label endRegion = catchedRegions.get(i+1);
3548                v.visitTryCatchBlock(startRegion, endRegion, catchStart, exception);
3549            }
3550        }
3551    
3552        @NotNull
3553        private static List<Label> getCurrentCatchIntervals(
3554                @Nullable FinallyBlockStackElement finallyBlockStackElement,
3555                @NotNull Label blockStart,
3556                @NotNull Label blockEnd
3557        ) {
3558            List<Label> gapsInBlock =
3559                    finallyBlockStackElement != null ? new ArrayList<Label>(finallyBlockStackElement.gaps) : Collections.<Label>emptyList();
3560            assert gapsInBlock.size() % 2 == 0;
3561            List<Label> blockRegions = new ArrayList<Label>(gapsInBlock.size() + 2);
3562            blockRegions.add(blockStart);
3563            blockRegions.addAll(gapsInBlock);
3564            blockRegions.add(blockEnd);
3565            return blockRegions;
3566        }
3567    
3568        @Override
3569        public StackValue visitBinaryWithTypeRHSExpression(@NotNull JetBinaryExpressionWithTypeRHS expression, StackValue receiver) {
3570            JetSimpleNameExpression operationSign = expression.getOperationReference();
3571            IElementType opToken = operationSign.getReferencedNameElementType();
3572            if (opToken == JetTokens.COLON) {
3573                return gen(expression.getLeft());
3574            }
3575            else {
3576                JetTypeReference typeReference = expression.getRight();
3577                JetType rightType = bindingContext.get(BindingContext.TYPE, typeReference);
3578                assert rightType != null;
3579                Type rightTypeAsm = boxType(asmType(rightType));
3580                JetExpression left = expression.getLeft();
3581                DeclarationDescriptor descriptor = rightType.getConstructor().getDeclarationDescriptor();
3582                if (descriptor instanceof ClassDescriptor || descriptor instanceof TypeParameterDescriptor) {
3583                    StackValue value = genQualified(receiver, left);
3584                    value.put(boxType(value.type), v);
3585    
3586                    if (opToken != JetTokens.AS_SAFE) {
3587                        if (!CodegenUtil.isNullableType(rightType)) {
3588                            v.dup();
3589                            Label nonnull = new Label();
3590                            v.ifnonnull(nonnull);
3591                            JetType leftType = bindingContext.get(BindingContext.EXPRESSION_TYPE, left);
3592                            assert leftType != null;
3593                            throwNewException("kotlin/TypeCastException", DescriptorRenderer.TEXT.renderType(leftType) +
3594                                                                         " cannot be cast to " +
3595                                                                         DescriptorRenderer.TEXT.renderType(rightType));
3596                            v.mark(nonnull);
3597                        }
3598                    }
3599                    else {
3600                        v.dup();
3601                        v.instanceOf(rightTypeAsm);
3602                        Label ok = new Label();
3603                        v.ifne(ok);
3604                        v.pop();
3605                        v.aconst(null);
3606                        v.mark(ok);
3607                    }
3608    
3609                    v.checkcast(rightTypeAsm);
3610                    return StackValue.onStack(rightTypeAsm);
3611                }
3612                else {
3613                    throw new UnsupportedOperationException("Don't know how to handle non-class types in as/as? : " + descriptor);
3614                }
3615            }
3616        }
3617    
3618        @Override
3619        public StackValue visitIsExpression(@NotNull JetIsExpression expression, StackValue receiver) {
3620            StackValue match = StackValue.expression(OBJECT_TYPE, expression.getLeftHandSide(), this);
3621            return generateIsCheck(match, expression.getTypeRef(), expression.isNegated());
3622        }
3623    
3624        private StackValue generateExpressionMatch(StackValue expressionToMatch, JetExpression patternExpression) {
3625            if (expressionToMatch != null) {
3626                Type subjectType = expressionToMatch.type;
3627                expressionToMatch.dupReceiver(v);
3628                expressionToMatch.put(subjectType, v);
3629                JetType condJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, patternExpression);
3630                Type condType;
3631                if (isNumberPrimitive(subjectType) || subjectType.getSort() == Type.BOOLEAN) {
3632                    assert condJetType != null;
3633                    condType = asmType(condJetType);
3634                    if (!(isNumberPrimitive(condType) || condType.getSort() == Type.BOOLEAN)) {
3635                        subjectType = boxType(subjectType);
3636                        expressionToMatch.coerceTo(subjectType, v);
3637                    }
3638                }
3639                else {
3640                    condType = OBJECT_TYPE;
3641                }
3642                gen(patternExpression, condType);
3643                return genEqualsForExpressionsOnStack(v, JetTokens.EQEQ, subjectType, condType);
3644            }
3645            else {
3646                return gen(patternExpression);
3647            }
3648        }
3649    
3650        private StackValue generateIsCheck(StackValue expressionToMatch, JetTypeReference typeReference, boolean negated) {
3651            JetType jetType = bindingContext.get(BindingContext.TYPE, typeReference);
3652            expressionToMatch.dupReceiver(v);
3653            generateInstanceOf(expressionToMatch, jetType, false);
3654            StackValue value = StackValue.onStack(Type.BOOLEAN_TYPE);
3655            return negated ? StackValue.not(value) : value;
3656        }
3657    
3658        private void generateInstanceOf(StackValue expressionToGen, JetType jetType, boolean leaveExpressionOnStack) {
3659            expressionToGen.put(OBJECT_TYPE, v);
3660            if (leaveExpressionOnStack) {
3661                v.dup();
3662            }
3663            Type type = boxType(asmType(jetType));
3664            if (jetType.isNullable()) {
3665                Label nope = new Label();
3666                Label end = new Label();
3667    
3668                v.dup();
3669                v.ifnull(nope);
3670                v.instanceOf(type);
3671                v.goTo(end);
3672                v.mark(nope);
3673                v.pop();
3674                v.iconst(1);
3675                v.mark(end);
3676            }
3677            else {
3678                v.instanceOf(type);
3679            }
3680        }
3681    
3682        @Override
3683        public StackValue visitWhenExpression(@NotNull JetWhenExpression expression, StackValue receiver) {
3684            return generateWhenExpression(expression, false);
3685        }
3686    
3687        public StackValue generateWhenExpression(JetWhenExpression expression, boolean isStatement) {
3688            JetExpression expr = expression.getSubjectExpression();
3689            JetType subjectJetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, expr);
3690            Type subjectType = asmTypeOrVoid(subjectJetType);
3691            Type resultType = isStatement ? Type.VOID_TYPE : expressionType(expression);
3692            int subjectLocal = expr != null ? myFrameMap.enterTemp(subjectType) : -1;
3693            if (subjectLocal != -1) {
3694                gen(expr, subjectType);
3695                tempVariables.put(expr, StackValue.local(subjectLocal, subjectType));
3696                v.store(subjectLocal, subjectType);
3697            }
3698    
3699            Label end = new Label();
3700            boolean hasElse = JetPsiUtil.checkWhenExpressionHasSingleElse(expression);
3701    
3702            Label nextCondition = null;
3703            for (JetWhenEntry whenEntry : expression.getEntries()) {
3704                if (nextCondition != null) {
3705                    v.mark(nextCondition);
3706                }
3707                nextCondition = new Label();
3708                FrameMap.Mark mark = myFrameMap.mark();
3709                Label thisEntry = new Label();
3710                if (!whenEntry.isElse()) {
3711                    JetWhenCondition[] conditions = whenEntry.getConditions();
3712                    for (int i = 0; i < conditions.length; i++) {
3713                        StackValue conditionValue = generateWhenCondition(subjectType, subjectLocal, conditions[i]);
3714                        conditionValue.condJump(nextCondition, true, v);
3715                        if (i < conditions.length - 1) {
3716                            v.goTo(thisEntry);
3717                            v.mark(nextCondition);
3718                            nextCondition = new Label();
3719                        }
3720                    }
3721                }
3722    
3723                v.visitLabel(thisEntry);
3724                gen(whenEntry.getExpression(), resultType);
3725                mark.dropTo();
3726                if (!whenEntry.isElse()) {
3727                    v.goTo(end);
3728                }
3729            }
3730            if (!hasElse && nextCondition != null) {
3731                v.mark(nextCondition);
3732                if (!isStatement) {
3733                    // a result is expected
3734                    if (Boolean.TRUE.equals(bindingContext.get(BindingContext.EXHAUSTIVE_WHEN, expression))) {
3735                        // when() is supposed to be exhaustive
3736                        throwNewException("kotlin/NoWhenBranchMatchedException");
3737                    }
3738                    else {
3739                        // non-exhaustive when() with no else -> Unit must be expected
3740                        StackValue.putUnitInstance(v);
3741                    }
3742                }
3743            }
3744    
3745            markLineNumber(expression);
3746            v.mark(end);
3747    
3748            myFrameMap.leaveTemp(subjectType);
3749            tempVariables.remove(expr);
3750            return StackValue.onStack(resultType);
3751        }
3752    
3753        private StackValue generateWhenCondition(Type subjectType, int subjectLocal, JetWhenCondition condition) {
3754            if (condition instanceof JetWhenConditionInRange) {
3755                JetWhenConditionInRange conditionInRange = (JetWhenConditionInRange) condition;
3756                return generateIn(StackValue.local(subjectLocal, subjectType),
3757                                  conditionInRange.getRangeExpression(),
3758                                  conditionInRange.getOperationReference());
3759            }
3760            StackValue.Local match = subjectLocal == -1 ? null : StackValue.local(subjectLocal, subjectType);
3761            if (condition instanceof JetWhenConditionIsPattern) {
3762                JetWhenConditionIsPattern patternCondition = (JetWhenConditionIsPattern) condition;
3763                return generateIsCheck(match, patternCondition.getTypeRef(), patternCondition.isNegated());
3764            }
3765            else if (condition instanceof JetWhenConditionWithExpression) {
3766                JetExpression patternExpression = ((JetWhenConditionWithExpression) condition).getExpression();
3767                return generateExpressionMatch(match, patternExpression);
3768            }
3769            else {
3770                throw new UnsupportedOperationException("unsupported kind of when condition");
3771            }
3772        }
3773    
3774        private void invokeFunctionByReference(JetSimpleNameExpression operationReference) {
3775            ResolvedCall<?> resolvedCall = bindingContext.get(RESOLVED_CALL, operationReference);
3776            Call call = bindingContext.get(CALL, operationReference);
3777            invokeFunction(call, StackValue.none(), resolvedCall);
3778        }
3779    
3780        private boolean isIntRangeExpr(JetExpression rangeExpression) {
3781            if (rangeExpression instanceof JetBinaryExpression) {
3782                JetBinaryExpression binaryExpression = (JetBinaryExpression) rangeExpression;
3783                if (binaryExpression.getOperationReference().getReferencedNameElementType() == JetTokens.RANGE) {
3784                    JetType jetType = bindingContext.get(BindingContext.EXPRESSION_TYPE, rangeExpression);
3785                    assert jetType != null;
3786                    DeclarationDescriptor descriptor = jetType.getConstructor().getDeclarationDescriptor();
3787                    return INTEGRAL_RANGES.contains(descriptor);
3788                }
3789            }
3790            return false;
3791        }
3792    
3793        private void throwNewException(@NotNull String className) {
3794            throwNewException(className, null);
3795        }
3796    
3797        private void throwNewException(@NotNull String className, @Nullable String message) {
3798            v.anew(Type.getObjectType(className));
3799            v.dup();
3800            if (message != null) {
3801                v.visitLdcInsn(message);
3802                v.invokespecial(className, "<init>", "(Ljava/lang/String;)V");
3803            }
3804            else {
3805                v.invokespecial(className, "<init>", "()V");
3806            }
3807            v.athrow();
3808        }
3809    
3810        private Call makeFakeCall(ReceiverValue initializerAsReceiver) {
3811            JetSimpleNameExpression fake = JetPsiFactory.createSimpleName(state.getProject(), "fake");
3812            return CallMaker.makeCall(fake, initializerAsReceiver);
3813        }
3814    
3815        @Override
3816        public String toString() {
3817            return context.getContextDescriptor().toString();
3818        }
3819    
3820        @NotNull
3821        private ScriptCodegen getParentScriptCodegen() {
3822            MemberCodegen codegen = parentCodegen;
3823            while (codegen != null) {
3824                if (codegen instanceof ScriptCodegen) {
3825                    return (ScriptCodegen) codegen;
3826                }
3827                codegen = codegen.getParentCodegen();
3828            }
3829            throw new IllegalStateException("Script codegen should be present in codegen tree");
3830        }
3831    
3832        @NotNull
3833        public FrameMap getFrameMap() {
3834            return myFrameMap;
3835        }
3836    
3837        @NotNull
3838        public MethodContext getContext() {
3839            return context;
3840        }
3841    
3842        @NotNull
3843        public NameGenerator getInlineNameGenerator() {
3844            NameGenerator nameGenerator = getParentCodegen().getInlineNameGenerator();
3845            Name name = context.getContextDescriptor().getName();
3846            return nameGenerator.subGenerator((name.isSpecial() ? "$special" : name.asString()) + "$$inlined" );
3847        }
3848    }