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