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