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