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