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