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