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