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