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