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