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