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