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