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