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