001    /*
002     * Copyright 2010-2016 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.Function0;
032    import kotlin.jvm.functions.Function1;
033    import org.jetbrains.annotations.NotNull;
034    import org.jetbrains.annotations.Nullable;
035    import org.jetbrains.kotlin.backend.common.CodegenUtil;
036    import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
037    import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
038    import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
039    import org.jetbrains.kotlin.codegen.context.*;
040    import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegen;
041    import org.jetbrains.kotlin.codegen.coroutines.CoroutineCodegenUtilKt;
042    import org.jetbrains.kotlin.codegen.coroutines.ResolvedCallWithRealDescriptor;
043    import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
044    import org.jetbrains.kotlin.codegen.inline.*;
045    import org.jetbrains.kotlin.codegen.intrinsics.*;
046    import org.jetbrains.kotlin.codegen.pseudoInsns.PseudoInsnsKt;
047    import org.jetbrains.kotlin.codegen.signature.BothSignatureWriter;
048    import org.jetbrains.kotlin.codegen.signature.JvmSignatureWriter;
049    import org.jetbrains.kotlin.codegen.state.GenerationState;
050    import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
051    import org.jetbrains.kotlin.codegen.when.SwitchCodegen;
052    import org.jetbrains.kotlin.codegen.when.SwitchCodegenUtil;
053    import org.jetbrains.kotlin.config.ApiVersion;
054    import org.jetbrains.kotlin.descriptors.*;
055    import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
056    import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor;
057    import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor;
058    import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
059    import org.jetbrains.kotlin.diagnostics.Errors;
060    import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
061    import org.jetbrains.kotlin.lexer.KtTokens;
062    import org.jetbrains.kotlin.load.java.JvmAbi;
063    import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
064    import org.jetbrains.kotlin.load.kotlin.TypeSignatureMappingKt;
065    import org.jetbrains.kotlin.name.Name;
066    import org.jetbrains.kotlin.psi.*;
067    import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
068    import org.jetbrains.kotlin.resolve.BindingContext;
069    import org.jetbrains.kotlin.resolve.BindingContextUtils;
070    import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
071    import org.jetbrains.kotlin.resolve.DescriptorUtils;
072    import org.jetbrains.kotlin.resolve.calls.callResolverUtil.CallResolverUtilKt;
073    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
074    import org.jetbrains.kotlin.resolve.calls.model.*;
075    import org.jetbrains.kotlin.resolve.calls.util.CallMaker;
076    import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject;
077    import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant;
078    import org.jetbrains.kotlin.resolve.constants.ConstantValue;
079    import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
080    import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluatorKt;
081    import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
082    import org.jetbrains.kotlin.resolve.inline.InlineUtil;
083    import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
084    import org.jetbrains.kotlin.resolve.jvm.JvmBindingContextSlices;
085    import org.jetbrains.kotlin.resolve.jvm.RuntimeAssertionInfo;
086    import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
087    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
088    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
089    import org.jetbrains.kotlin.resolve.scopes.receivers.*;
090    import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor;
091    import org.jetbrains.kotlin.types.KotlinType;
092    import org.jetbrains.kotlin.types.TypeProjection;
093    import org.jetbrains.kotlin.types.TypeUtils;
094    import org.jetbrains.kotlin.types.expressions.DoubleColonLHS;
095    import org.jetbrains.kotlin.types.typesApproximation.CapturedTypeApproximationKt;
096    import org.jetbrains.kotlin.util.OperatorNameConventions;
097    import org.jetbrains.org.objectweb.asm.Label;
098    import org.jetbrains.org.objectweb.asm.MethodVisitor;
099    import org.jetbrains.org.objectweb.asm.Opcodes;
100    import org.jetbrains.org.objectweb.asm.Type;
101    import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
102    import org.jetbrains.org.objectweb.asm.commons.Method;
103    
104    import java.util.*;
105    
106    import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isInt;
107    import static org.jetbrains.kotlin.codegen.AsmUtil.*;
108    import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.*;
109    import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.*;
110    import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
111    import static org.jetbrains.kotlin.resolve.BindingContext.*;
112    import static org.jetbrains.kotlin.resolve.BindingContextUtils.*;
113    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
114    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isObject;
115    import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
116    import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionExpression;
117    import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral;
118    import static org.jetbrains.org.objectweb.asm.Opcodes.*;
119    
120    public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> implements LocalLookup {
121        private final GenerationState state;
122        final KotlinTypeMapper typeMapper;
123        private final BindingContext bindingContext;
124    
125        public final InstructionAdapter v;
126        public final FrameMap myFrameMap;
127        public final MethodContext context;
128        private final Type returnType;
129    
130        private final CodegenStatementVisitor statementVisitor = new CodegenStatementVisitor(this);
131        private final MemberCodegen<?> parentCodegen;
132        private final TailRecursionCodegen tailRecursionCodegen;
133        public final CallGenerator defaultCallGenerator = new CallGenerator.DefaultCallGenerator(this);
134    
135        private final Stack<BlockStackElement> blockStackElements = new Stack<BlockStackElement>();
136    
137        /*
138         * When we create a temporary variable to hold some value not to compute it many times
139         * we put it into this map to emit access to that variable instead of evaluating the whole expression
140         */
141        public final Map<KtElement, StackValue> tempVariables = Maps.newHashMap();
142    
143        private int myLastLineNumber = -1;
144        private boolean shouldMarkLineNumbers = true;
145        private int finallyDepth = 0;
146    
147        public ExpressionCodegen(
148                @NotNull MethodVisitor mv,
149                @NotNull FrameMap frameMap,
150                @NotNull Type returnType,
151                @NotNull MethodContext context,
152                @NotNull GenerationState state,
153                @NotNull MemberCodegen<?> parentCodegen
154        ) {
155            this.state = state;
156            this.typeMapper = state.getTypeMapper();
157            this.bindingContext = state.getBindingContext();
158            this.v = new InstructionAdapter(mv);
159            this.myFrameMap = frameMap;
160            this.context = context;
161            this.returnType = returnType;
162    
163            this.parentCodegen = parentCodegen;
164            this.tailRecursionCodegen = new TailRecursionCodegen(context, this, this.v, state);
165        }
166    
167        @Nullable
168        private static FunctionDescriptor getOriginalSuspendLambdaDescriptorFromContext(MethodContext context) {
169            if ((context.getParentContext() instanceof ClosureContext) &&
170                (context.getParentContext().closure != null) &&
171                context.getParentContext().closure.isSuspend()) {
172                return ((ClosureContext) context.getParentContext()).getOriginalSuspendLambdaDescriptor();
173            }
174    
175            return null;
176        }
177    
178        static class BlockStackElement {
179        }
180    
181        static class LoopBlockStackElement extends BlockStackElement {
182            final Label continueLabel;
183            final Label breakLabel;
184            public final KtSimpleNameExpression targetLabel;
185    
186            LoopBlockStackElement(Label breakLabel, Label continueLabel, KtSimpleNameExpression targetLabel) {
187                this.breakLabel = breakLabel;
188                this.continueLabel = continueLabel;
189                this.targetLabel = targetLabel;
190            }
191        }
192    
193        static class FinallyBlockStackElement extends BlockStackElement {
194            List<Label> gaps = new ArrayList<Label>();
195    
196            final KtTryExpression expression;
197    
198            FinallyBlockStackElement(KtTryExpression expression) {
199                this.expression = expression;
200            }
201    
202            private void addGapLabel(Label label){
203                gaps.add(label);
204            }
205        }
206    
207        @NotNull
208        public GenerationState getState() {
209            return state;
210        }
211    
212        @NotNull
213        public BindingContext getBindingContext() {
214            return bindingContext;
215        }
216    
217        @NotNull
218        public MemberCodegen<?> getParentCodegen() {
219            return parentCodegen;
220        }
221    
222        @NotNull
223        public ObjectLiteralResult generateObjectLiteral(@NotNull KtObjectLiteralExpression literal) {
224            KtObjectDeclaration objectDeclaration = literal.getObjectDeclaration();
225    
226            ClassDescriptor classDescriptor = bindingContext.get(CLASS, objectDeclaration);
227            assert classDescriptor != null;
228    
229            Type asmType = asmTypeForAnonymousClass(bindingContext, objectDeclaration);
230            ClassBuilder classBuilder = state.getFactory().newVisitor(
231                    JvmDeclarationOriginKt.OtherOrigin(objectDeclaration, classDescriptor),
232                    asmType,
233                    literal.getContainingFile()
234            );
235    
236            ClassContext objectContext = context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION);
237    
238            MemberCodegen literalCodegen = new ImplementationBodyCodegen(
239                    objectDeclaration, objectContext, classBuilder, state, getParentCodegen(),
240                    /* isLocal = */ true);
241            literalCodegen.generate();
242    
243            addReifiedParametersFromSignature(literalCodegen, classDescriptor);
244            propagateChildReifiedTypeParametersUsages(literalCodegen.getReifiedTypeParametersUsages());
245    
246            return new ObjectLiteralResult(
247                    literalCodegen.getReifiedTypeParametersUsages().wereUsedReifiedParameters(),
248                    classDescriptor
249            );
250        }
251    
252        private static void addReifiedParametersFromSignature(@NotNull MemberCodegen member, @NotNull ClassDescriptor descriptor) {
253            for (KotlinType type : descriptor.getTypeConstructor().getSupertypes()) {
254                for (TypeProjection supertypeArgument : type.getArguments()) {
255                    TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(supertypeArgument.getType());
256                    if (parameterDescriptor != null && parameterDescriptor.isReified()) {
257                        member.getReifiedTypeParametersUsages().addUsedReifiedParameter(parameterDescriptor.getName().asString());
258                    }
259                }
260            }
261        }
262    
263        private static class ObjectLiteralResult {
264            private final boolean wereReifiedMarkers;
265            private final ClassDescriptor classDescriptor;
266    
267            public ObjectLiteralResult(boolean wereReifiedMarkers, @NotNull ClassDescriptor classDescriptor) {
268                this.wereReifiedMarkers = wereReifiedMarkers;
269                this.classDescriptor = classDescriptor;
270            }
271        }
272    
273        @NotNull
274        private StackValue castToRequiredTypeOfInterfaceIfNeeded(
275                StackValue inner,
276                @NotNull ClassDescriptor provided,
277                @NotNull ClassDescriptor required
278        ) {
279            if (!isJvmInterface(provided) && isJvmInterface(required)) {
280                return StackValue.coercion(inner, asmType(required.getDefaultType()));
281            }
282    
283            return inner;
284        }
285    
286        public StackValue genQualified(StackValue receiver, KtElement selector) {
287            return genQualified(receiver, selector, this);
288        }
289    
290        private StackValue genQualified(StackValue receiver, KtElement selector, KtVisitor<StackValue, StackValue> visitor) {
291            if (tempVariables.containsKey(selector)) {
292                throw new IllegalStateException("Inconsistent state: expression saved to a temporary variable is a selector");
293            }
294            if (!(selector instanceof KtBlockExpression)) {
295                markStartLineNumber(selector);
296            }
297            try {
298                if (selector instanceof KtExpression) {
299                    StackValue samValue = genSamInterfaceValue((KtExpression) selector, visitor);
300                    if (samValue != null) {
301                        return samValue;
302                    }
303                }
304    
305                StackValue stackValue = selector.accept(visitor, receiver);
306    
307                RuntimeAssertionInfo runtimeAssertionInfo = null;
308                if (selector instanceof KtExpression) {
309                    runtimeAssertionInfo = bindingContext.get(JvmBindingContextSlices.RUNTIME_ASSERTION_INFO, (KtExpression) selector);
310                }
311    
312                if (BuiltinSpecialBridgesKt.isValueArgumentForCallToMethodWithTypeCheckBarrier(selector, bindingContext)) return stackValue;
313    
314                return genNotNullAssertions(state, stackValue, runtimeAssertionInfo);
315            }
316            catch (ProcessCanceledException e) {
317                throw e;
318            }
319            catch (CompilationException e) {
320                throw e;
321            }
322            catch (Throwable error) {
323                String message = error.getMessage();
324                throw new CompilationException(message != null ? message : "null", error, selector);
325            }
326        }
327    
328        public StackValue gen(KtElement expr) {
329            StackValue tempVar = tempVariables.get(expr);
330            return tempVar != null ? tempVar : genQualified(StackValue.none(), expr);
331        }
332    
333        public void gen(KtElement expr, Type type) {
334            StackValue value = Type.VOID_TYPE.equals(type) ? genStatement(expr) : gen(expr);
335            putStackValue(expr, type, value);
336        }
337    
338        private void putStackValue(@Nullable KtElement expr, @NotNull Type type, @NotNull StackValue value) {
339            // for repl store the result of the last line into special field
340            if (value.type != Type.VOID_TYPE && state.getReplSpecific().getShouldGenerateScriptResultValue()) {
341                ScriptContext context = getScriptContext();
342                if (expr == context.getLastStatement()) {
343                    StackValue.Field resultValue = StackValue.field(context.getResultFieldInfo(), StackValue.LOCAL_0);
344                    resultValue.store(value, v);
345                    state.getReplSpecific().setHasResult(true);
346                    return;
347                }
348            }
349    
350            value.put(type, v);
351        }
352    
353        @NotNull
354        private ScriptContext getScriptContext() {
355            CodegenContext context = getContext();
356            while (!(context instanceof ScriptContext)) {
357                context = context.getParentContext();
358            }
359            return (ScriptContext) context;
360        }
361    
362        public StackValue genLazy(KtElement expr, Type type) {
363            StackValue value = gen(expr);
364            return StackValue.coercion(value, type);
365        }
366    
367        private StackValue genStatement(KtElement statement) {
368            return genQualified(StackValue.none(), statement, statementVisitor);
369        }
370    
371        @Override
372        public StackValue visitClass(@NotNull KtClass klass, StackValue data) {
373            return visitClassOrObject(klass);
374        }
375    
376        @Override
377        public StackValue visitTypeAlias(@NotNull KtTypeAlias typeAlias, StackValue data) {
378            return StackValue.none();
379        }
380    
381        private StackValue visitClassOrObject(KtClassOrObject declaration) {
382            ClassDescriptor descriptor = bindingContext.get(CLASS, declaration);
383            assert descriptor != null;
384    
385            Type asmType = asmTypeForAnonymousClass(bindingContext, declaration);
386            ClassBuilder classBuilder = state.getFactory().newVisitor(JvmDeclarationOriginKt.OtherOrigin(declaration, descriptor), asmType, declaration.getContainingFile());
387    
388            ClassContext objectContext = context.intoAnonymousClass(descriptor, this, OwnerKind.IMPLEMENTATION);
389            new ImplementationBodyCodegen(declaration, objectContext, classBuilder, state, getParentCodegen(), /* isLocal = */ true).generate();
390    
391            if (declaration instanceof KtClass && ((KtClass) declaration).isInterface()) {
392                Type traitImplType = state.getTypeMapper().mapDefaultImpls(descriptor);
393                ClassBuilder traitImplBuilder = state.getFactory().newVisitor(JvmDeclarationOriginKt.DefaultImpls(declaration, descriptor), traitImplType, declaration.getContainingFile());
394                ClassContext traitImplContext = context.intoAnonymousClass(descriptor, this, OwnerKind.DEFAULT_IMPLS);
395                new InterfaceImplBodyCodegen(declaration, traitImplContext, traitImplBuilder, state, parentCodegen).generate();
396            }
397    
398            return StackValue.none();
399        }
400    
401        @Override
402        public StackValue visitObjectDeclaration(@NotNull KtObjectDeclaration declaration, StackValue data) {
403            return visitClassOrObject(declaration);
404        }
405    
406        @Override
407        public StackValue visitExpression(@NotNull KtExpression expression, StackValue receiver) {
408            throw new UnsupportedOperationException("Codegen for " + expression + " is not yet implemented");
409        }
410    
411        @Override
412        public StackValue visitSuperExpression(@NotNull KtSuperExpression expression, StackValue data) {
413            return StackValue.thisOrOuter(this, getSuperCallLabelTarget(context, expression), true, false);
414        }
415    
416        @NotNull
417        public static ClassDescriptor getSuperCallLabelTarget(
418                @NotNull CodegenContext<?> context,
419                @NotNull KtSuperExpression expression
420        ) {
421            KotlinType thisTypeForSuperCall = context.getState().getBindingContext().get(BindingContext.THIS_TYPE_FOR_SUPER_EXPRESSION, expression);
422            assert thisTypeForSuperCall != null : "This type for superCall ''" + expression.getText() + "'' should be not null!";
423            ClassifierDescriptor descriptor = thisTypeForSuperCall.getConstructor().getDeclarationDescriptor();
424            assert descriptor instanceof ClassDescriptor :
425                    "'This' reference target for ''" + expression.getText() + "''should be class descriptor, but was " + descriptor;
426            return (ClassDescriptor) descriptor;
427        }
428    
429        @NotNull
430        private Type asmType(@NotNull KotlinType type) {
431            return typeMapper.mapType(type);
432        }
433    
434        @NotNull
435        private Type expressionTypeForBranchingOperation(@Nullable KtExpression expression) {
436            if (context.getFunctionDescriptor().isSuspend() &&
437                !CoroutineCodegenUtilKt.isStateMachineNeeded(context.getFunctionDescriptor(), bindingContext) &&
438                Boolean.TRUE.equals(bindingContext.get(IS_TAIL_EXPRESSION_IN_SUSPEND_FUNCTION, expression))) {
439                return AsmTypes.OBJECT_TYPE;
440            }
441            return expressionType(expression);
442        }
443    
444        @NotNull
445        public Type expressionType(@Nullable KtExpression expression) {
446            return CodegenUtilKt.asmType(expression, typeMapper, bindingContext);
447        }
448    
449        @Nullable
450        private KotlinType expressionJetType(@Nullable KtExpression expression) {
451            return CodegenUtilKt.kotlinType(expression, bindingContext);
452        }
453    
454        @Override
455        public StackValue visitParenthesizedExpression(@NotNull KtParenthesizedExpression expression, StackValue receiver) {
456            return genQualified(receiver, expression.getExpression());
457        }
458    
459        @Override
460        public StackValue visitAnnotatedExpression(@NotNull KtAnnotatedExpression expression, StackValue receiver) {
461            return genQualified(receiver, expression.getBaseExpression());
462        }
463    
464        private static boolean isEmptyExpression(@Nullable KtElement expr) {
465            if (expr == null) {
466                return true;
467            }
468            if (expr instanceof KtBlockExpression) {
469                KtBlockExpression blockExpression = (KtBlockExpression) expr;
470                List<KtExpression> statements = blockExpression.getStatements();
471                if (statements.size() == 0 || statements.size() == 1 && isEmptyExpression(statements.get(0))) {
472                    return true;
473                }
474            }
475            return false;
476        }
477    
478        @Override
479        public StackValue visitIfExpression(@NotNull KtIfExpression expression, StackValue receiver) {
480            return generateIfExpression(expression, false);
481        }
482    
483        /* package */ StackValue generateIfExpression(@NotNull final KtIfExpression expression, final boolean isStatement) {
484            final Type asmType = isStatement ? Type.VOID_TYPE : expressionTypeForBranchingOperation(expression);
485            final StackValue condition = gen(expression.getCondition());
486    
487            final KtExpression thenExpression = expression.getThen();
488            final KtExpression elseExpression = expression.getElse();
489    
490            if (isEmptyExpression(thenExpression)) {
491                if (isEmptyExpression(elseExpression)) {
492                    return StackValue.coercion(condition, asmType);
493                }
494                return generateSingleBranchIf(condition, expression, elseExpression, false, isStatement);
495            }
496            else {
497                if (isEmptyExpression(elseExpression)) {
498                    return generateSingleBranchIf(condition, expression, thenExpression, true, isStatement);
499                }
500            }
501    
502            return StackValue.operation(asmType, new Function1<InstructionAdapter, Unit>() {
503                @Override
504                public Unit invoke(InstructionAdapter v) {
505                    Label elseLabel = new Label();
506                    BranchedValue.Companion.condJump(condition, elseLabel, true, v);
507    
508                    Label end = new Label();
509    
510                    gen(thenExpression, asmType);
511    
512                    v.goTo(end);
513                    v.mark(elseLabel);
514    
515                    gen(elseExpression, asmType);
516    
517                    markLineNumber(expression, isStatement);
518                    v.mark(end);
519                    return Unit.INSTANCE;
520                }
521            });
522        }
523    
524        @Override
525        public StackValue visitWhileExpression(@NotNull final KtWhileExpression expression, StackValue receiver) {
526            return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
527                @Override
528                public Unit invoke(InstructionAdapter adapter) {
529                    generateWhile(expression);
530                    return Unit.INSTANCE;
531                }
532            });
533        }
534    
535        private void generateWhile(@NotNull KtWhileExpression expression) {
536            Label condition = new Label();
537            v.mark(condition);
538    
539            Label end = new Label();
540            blockStackElements.push(new LoopBlockStackElement(end, condition, targetLabel(expression)));
541    
542            StackValue conditionValue = gen(expression.getCondition());
543            BranchedValue.Companion.loopJump(conditionValue, end, true, v);
544    
545            generateLoopBody(expression.getBody());
546    
547            markStartLineNumber(expression);
548            v.goTo(condition);
549    
550            v.mark(end);
551    
552            blockStackElements.pop();
553        }
554    
555        @Override
556        public StackValue visitDoWhileExpression(@NotNull final KtDoWhileExpression expression, StackValue receiver) {
557            return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
558                @Override
559                public Unit invoke(InstructionAdapter adapter) {
560                    generateDoWhile(expression);
561                    return Unit.INSTANCE;
562                }
563            });
564        }
565    
566        private void generateDoWhile(@NotNull KtDoWhileExpression expression) {
567            Label beginLoopLabel = new Label();
568            v.mark(beginLoopLabel);
569    
570            Label breakLabel = new Label();
571            Label continueLabel = new Label();
572    
573            blockStackElements.push(new LoopBlockStackElement(breakLabel, continueLabel, targetLabel(expression)));
574    
575            PseudoInsnsKt.fakeAlwaysFalseIfeq(v, continueLabel);
576            PseudoInsnsKt.fakeAlwaysFalseIfeq(v, breakLabel);
577    
578            KtExpression body = expression.getBody();
579            KtExpression condition = expression.getCondition();
580            StackValue conditionValue;
581    
582            StackValueWithLeaveTask leaveTask = null;
583            if (body instanceof KtBlockExpression) {
584                // If body's a block, it can contain variable declarations which may be used in the condition of a do-while loop.
585                // We handle this case separately because otherwise such variable will be out of the frame map after the block ends
586                List<KtExpression> doWhileStatements = ((KtBlockExpression) body).getStatements();
587    
588                List<KtExpression> statements = new ArrayList<KtExpression>(doWhileStatements.size() + 1);
589                statements.addAll(doWhileStatements);
590                statements.add(condition);
591    
592                //Need to split leave task and condition cause otherwise BranchedValue optimizations wouldn't work
593                leaveTask = generateBlock(statements, false, continueLabel, null);
594                conditionValue = leaveTask.getStackValue();
595            }
596            else {
597                if (body != null) {
598                    gen(body, Type.VOID_TYPE);
599                }
600                v.mark(continueLabel);
601                conditionValue = gen(condition);
602            }
603    
604            BranchedValue.Companion.loopJump(conditionValue, beginLoopLabel, false, v);
605            if (leaveTask != null) {
606                leaveTask.getLeaveTasks().invoke(conditionValue);
607            }
608            v.mark(breakLabel);
609    
610            blockStackElements.pop();
611        }
612    
613        @Override
614        public StackValue visitForExpression(@NotNull final KtForExpression forExpression, StackValue receiver) {
615            return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
616                @Override
617                public Unit invoke(InstructionAdapter adapter) {
618                    generateFor(forExpression);
619                    return Unit.INSTANCE;
620                }
621            });
622        }
623    
624        private void generateFor(@NotNull KtForExpression forExpression) {
625            ResolvedCall<? extends CallableDescriptor> loopRangeCall = RangeCodegenUtil.getLoopRangeResolvedCall(forExpression, bindingContext);
626            if (loopRangeCall != null) {
627                AbstractForLoopGenerator optimizedForLoopGenerator = createOptimizedForLoopGeneratorOrNull(forExpression, loopRangeCall);
628                if (optimizedForLoopGenerator != null) {
629                    generateForLoop(optimizedForLoopGenerator);
630                    return;
631                }
632            }
633    
634            KtExpression loopRange = forExpression.getLoopRange();
635            assert loopRange != null;
636            KotlinType loopRangeType = bindingContext.getType(loopRange);
637            assert loopRangeType != null;
638            Type asmLoopRangeType = asmType(loopRangeType);
639            if (asmLoopRangeType.getSort() == Type.ARRAY) {
640                generateForLoop(new ForInArrayLoopGenerator(forExpression));
641            }
642            else if (RangeCodegenUtil.isRange(loopRangeType)) {
643                generateForLoop(new ForInRangeInstanceLoopGenerator(forExpression));
644            }
645            else if (RangeCodegenUtil.isProgression(loopRangeType)) {
646                generateForLoop(new ForInProgressionExpressionLoopGenerator(forExpression));
647            }
648            else {
649                generateForLoop(new IteratorForLoopGenerator(forExpression));
650            }
651        }
652    
653        @Nullable
654        private AbstractForLoopGenerator createOptimizedForLoopGeneratorOrNull(
655                @NotNull KtForExpression forExpression,
656                @NotNull ResolvedCall<? extends CallableDescriptor> loopRangeCall
657        ) {
658            CallableDescriptor loopRangeCallee = loopRangeCall.getResultingDescriptor();
659            if (RangeCodegenUtil.isPrimitiveNumberRangeTo(loopRangeCallee)) {
660                return new ForInRangeLiteralLoopGenerator(forExpression, loopRangeCall);
661            }
662            else if (RangeCodegenUtil.isPrimitiveNumberDownTo(loopRangeCallee)) {
663                return new ForInDownToProgressionLoopGenerator(forExpression, loopRangeCall);
664            }
665            else if (RangeCodegenUtil.isArrayOrPrimitiveArrayIndices(loopRangeCallee)) {
666                return new ForInArrayIndicesRangeLoopGenerator(forExpression, loopRangeCall);
667            }
668            else if (RangeCodegenUtil.isCollectionIndices(loopRangeCallee)) {
669                return new ForInCollectionIndicesRangeLoopGenerator(forExpression, loopRangeCall);
670            }
671            else if (RangeCodegenUtil.isCharSequenceIndices(loopRangeCallee)) {
672                return new ForInCharSequenceIndicesRangeLoopGenerator(forExpression, loopRangeCall);
673            }
674    
675            return null;
676        }
677    
678        @NotNull
679        private static KotlinType getExpectedReceiverType(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
680            ReceiverParameterDescriptor extensionReceiver = resolvedCall.getResultingDescriptor().getExtensionReceiverParameter();
681            assert extensionReceiver != null : "Extension receiver should be non-null";
682            return extensionReceiver.getType();
683        }
684    
685        @Nullable
686        private static KtExpression getSingleArgumentExpression(@NotNull ResolvedCall<? extends CallableDescriptor> resolvedCall) {
687            List<ResolvedValueArgument> resolvedValueArguments = resolvedCall.getValueArgumentsByIndex();
688            if (resolvedValueArguments == null) return null;
689            if (resolvedValueArguments.size() != 1) return null;
690            List<ValueArgument> valueArguments = resolvedValueArguments.get(0).getArguments();
691            if (valueArguments.size() != 1) return null;
692            return valueArguments.get(0).getArgumentExpression();
693        }
694    
695        private OwnerKind contextKind() {
696            return context.getContextKind();
697        }
698    
699        private void generateForLoop(AbstractForLoopGenerator generator) {
700            Label loopExit = new Label();
701            Label loopEntry = new Label();
702            Label continueLabel = new Label();
703    
704            generator.beforeLoop();
705            generator.checkEmptyLoop(loopExit);
706    
707            v.mark(loopEntry);
708            generator.checkPreCondition(loopExit);
709    
710            // Some forms of for-loop can be optimized as post-condition loops.
711            PseudoInsnsKt.fakeAlwaysFalseIfeq(v, continueLabel);
712    
713            generator.beforeBody();
714            blockStackElements.push(new LoopBlockStackElement(loopExit, continueLabel, targetLabel(generator.forExpression)));
715            generator.body();
716            blockStackElements.pop();
717            v.mark(continueLabel);
718            generator.afterBody(loopExit);
719    
720            v.goTo(loopEntry);
721    
722            v.mark(loopExit);
723            generator.afterLoop();
724        }
725    
726        private abstract class AbstractForLoopGenerator {
727    
728            // for (e : E in c) {...}
729            protected final KtForExpression forExpression;
730            private final Label loopParameterStartLabel = new Label();
731            private final Label bodyEnd = new Label();
732            private final List<Runnable> leaveVariableTasks = Lists.newArrayList();
733    
734            protected final KotlinType elementType;
735            protected final Type asmElementType;
736    
737            protected int loopParameterVar;
738            protected Type loopParameterType;
739    
740            private AbstractForLoopGenerator(@NotNull KtForExpression forExpression) {
741                this.forExpression = forExpression;
742                this.elementType = getElementType(forExpression);
743                this.asmElementType = asmType(elementType);
744            }
745    
746            @NotNull
747            private KotlinType getElementType(KtForExpression forExpression) {
748                KtExpression loopRange = forExpression.getLoopRange();
749                assert loopRange != null;
750                ResolvedCall<FunctionDescriptor> nextCall = getNotNull(bindingContext,
751                                                                       LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange,
752                                                                       "No next() function " + DiagnosticUtils.atLocation(loopRange));
753                //noinspection ConstantConditions
754                return nextCall.getResultingDescriptor().getReturnType();
755            }
756    
757            public void beforeLoop() {
758                KtParameter loopParameter = forExpression.getLoopParameter();
759                if (loopParameter == null) return;
760                KtDestructuringDeclaration multiParameter = loopParameter.getDestructuringDeclaration();
761                if (multiParameter != null) {
762                    // E tmp<e> = tmp<iterator>.next()
763                    loopParameterType = asmElementType;
764                    loopParameterVar = createLoopTempVariable(asmElementType);
765                }
766                else {
767                    // E e = tmp<iterator>.next()
768                    final VariableDescriptor parameterDescriptor = bindingContext.get(VALUE_PARAMETER, loopParameter);
769                    loopParameterType = asmType(parameterDescriptor.getType());
770                    loopParameterVar = myFrameMap.enter(parameterDescriptor, loopParameterType);
771                    scheduleLeaveVariable(new Runnable() {
772                        @Override
773                        public void run() {
774                            myFrameMap.leave(parameterDescriptor);
775                            v.visitLocalVariable(parameterDescriptor.getName().asString(),
776                                                 loopParameterType.getDescriptor(), null,
777                                                 loopParameterStartLabel, bodyEnd,
778                                                 loopParameterVar);
779                        }
780                    });
781                }
782            }
783    
784            public abstract void checkEmptyLoop(@NotNull Label loopExit);
785    
786            public abstract void checkPreCondition(@NotNull Label loopExit);
787    
788            public void beforeBody() {
789                assignToLoopParameter();
790                v.mark(loopParameterStartLabel);
791    
792                KtDestructuringDeclaration destructuringDeclaration = forExpression.getDestructuringDeclaration();
793                if (destructuringDeclaration != null) {
794                    generateDestructuringDeclaration(destructuringDeclaration);
795                }
796            }
797    
798            private void generateDestructuringDeclaration(@NotNull KtDestructuringDeclaration destructuringDeclaration) {
799                final Label destructuringStartLabel = new Label();
800    
801                List<VariableDescriptor> componentDescriptors =
802                        CollectionsKt.map(
803                                destructuringDeclaration.getEntries(),
804                                new Function1<KtDestructuringDeclarationEntry, VariableDescriptor>() {
805                                    @Override
806                                    public VariableDescriptor invoke(KtDestructuringDeclarationEntry entry) {
807                                        return getVariableDescriptorNotNull(entry);
808                                    }
809                                }
810                        );
811    
812                for (final VariableDescriptor componentDescriptor : CodegenUtilKt.filterOutDescriptorsWithSpecialNames(componentDescriptors)) {
813                    @SuppressWarnings("ConstantConditions") final Type componentAsmType = asmType(componentDescriptor.getReturnType());
814                    final int componentVarIndex = myFrameMap.enter(componentDescriptor, componentAsmType);
815                    scheduleLeaveVariable(new Runnable() {
816                        @Override
817                        public void run() {
818                            myFrameMap.leave(componentDescriptor);
819                            v.visitLocalVariable(componentDescriptor.getName().asString(),
820                                                 componentAsmType.getDescriptor(), null,
821                                                 destructuringStartLabel, bodyEnd,
822                                                 componentVarIndex);
823                        }
824                    });
825                }
826    
827                v.visitLabel(destructuringStartLabel);
828    
829                initializeDestructuringDeclarationVariables(
830                        destructuringDeclaration,
831                        new TransientReceiver(elementType),
832                        StackValue.local(loopParameterVar, asmElementType));
833            }
834    
835            protected abstract void assignToLoopParameter();
836    
837            protected abstract void increment(@NotNull Label loopExit);
838    
839            public void body() {
840                generateLoopBody(forExpression.getBody());
841            }
842    
843            private void scheduleLeaveVariable(Runnable runnable) {
844                leaveVariableTasks.add(runnable);
845            }
846    
847            protected int createLoopTempVariable(final Type type) {
848                int varIndex = myFrameMap.enterTemp(type);
849                scheduleLeaveVariable(new Runnable() {
850                    @Override
851                    public void run() {
852                        myFrameMap.leaveTemp(type);
853                    }
854                });
855                return varIndex;
856            }
857    
858            public void afterBody(@NotNull Label loopExit) {
859                markStartLineNumber(forExpression);
860    
861                increment(loopExit);
862    
863                v.mark(bodyEnd);
864            }
865    
866            public void afterLoop() {
867                for (Runnable task : Lists.reverse(leaveVariableTasks)) {
868                    task.run();
869                }
870            }
871    
872            // This method consumes range/progression from stack
873            // The result is stored to local variable
874            protected void generateRangeOrProgressionProperty(
875                    @NotNull Type loopRangeType,
876                    @NotNull String getterName,
877                    @NotNull Type getterReturnType,
878                    @NotNull Type varType,
879                    int varToStore
880            ) {
881                v.invokevirtual(loopRangeType.getInternalName(), getterName, "()" + getterReturnType.getDescriptor(), false);
882                StackValue.local(varToStore, varType).store(StackValue.onStack(getterReturnType), v);
883            }
884        }
885    
886        private void generateLoopBody(@Nullable KtExpression body) {
887            if (body != null) {
888                gen(body, Type.VOID_TYPE);
889            }
890        }
891    
892        private class IteratorForLoopGenerator extends AbstractForLoopGenerator {
893    
894            private int iteratorVarIndex;
895            private final ResolvedCall<FunctionDescriptor> iteratorCall;
896            private final ResolvedCall<FunctionDescriptor> nextCall;
897            private final Type asmTypeForIterator;
898    
899            private IteratorForLoopGenerator(@NotNull KtForExpression forExpression) {
900                super(forExpression);
901    
902                KtExpression loopRange = forExpression.getLoopRange();
903                assert loopRange != null;
904                this.iteratorCall = getNotNull(bindingContext,
905                                               LOOP_RANGE_ITERATOR_RESOLVED_CALL, loopRange,
906                                               "No .iterator() function " + DiagnosticUtils.atLocation(loopRange));
907    
908                KotlinType iteratorType = iteratorCall.getResultingDescriptor().getReturnType();
909                assert iteratorType != null;
910                this.asmTypeForIterator = asmType(iteratorType);
911    
912                this.nextCall = getNotNull(bindingContext,
913                                           LOOP_RANGE_NEXT_RESOLVED_CALL, loopRange,
914                                           "No next() function " + DiagnosticUtils.atLocation(loopRange));
915            }
916    
917            @Override
918            public void beforeLoop() {
919                super.beforeLoop();
920    
921                // Iterator<E> tmp<iterator> = c.iterator()
922    
923                iteratorVarIndex = createLoopTempVariable(asmTypeForIterator);
924    
925                StackValue.local(iteratorVarIndex, asmTypeForIterator).store(invokeFunction(iteratorCall, StackValue.none()), v);
926            }
927    
928            @Override
929            public void checkEmptyLoop(@NotNull Label loopExit) {
930            }
931    
932            @Override
933            public void checkPreCondition(@NotNull Label loopExit) {
934                // tmp<iterator>.hasNext()
935    
936                KtExpression loopRange = forExpression.getLoopRange();
937                @SuppressWarnings("ConstantConditions") ResolvedCall<FunctionDescriptor> hasNextCall = getNotNull(bindingContext,
938                                                                          LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, loopRange,
939                                                                          "No hasNext() function " + DiagnosticUtils.atLocation(loopRange));
940                @SuppressWarnings("ConstantConditions") Call fakeCall = makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType()));
941                StackValue result = invokeFunction(fakeCall, hasNextCall, StackValue.local(iteratorVarIndex, asmTypeForIterator));
942                result.put(Type.BOOLEAN_TYPE, v);
943    
944                v.ifeq(loopExit);
945            }
946    
947            @Override
948            protected void assignToLoopParameter() {
949                @SuppressWarnings("ConstantConditions") Call fakeCall =
950                        makeFakeCall(new TransientReceiver(iteratorCall.getResultingDescriptor().getReturnType()));
951                StackValue value = invokeFunction(fakeCall, nextCall, StackValue.local(iteratorVarIndex, asmTypeForIterator));
952                //noinspection ConstantConditions
953                StackValue.local(loopParameterVar, loopParameterType).store(value, v);
954            }
955    
956            @Override
957            protected void increment(@NotNull Label loopExit) {
958            }
959        }
960    
961        private class ForInArrayLoopGenerator extends AbstractForLoopGenerator {
962            private int indexVar;
963            private int arrayVar;
964            private final KotlinType loopRangeType;
965    
966            private ForInArrayLoopGenerator(@NotNull KtForExpression forExpression) {
967                super(forExpression);
968                loopRangeType = bindingContext.getType(forExpression.getLoopRange());
969            }
970    
971            @Override
972            public void beforeLoop() {
973                super.beforeLoop();
974    
975                indexVar = createLoopTempVariable(Type.INT_TYPE);
976    
977                KtExpression loopRange = forExpression.getLoopRange();
978                StackValue value = gen(loopRange);
979                Type asmLoopRangeType = asmType(loopRangeType);
980                if (value instanceof StackValue.Local && value.type.equals(asmLoopRangeType)) {
981                    arrayVar = ((StackValue.Local) value).index; // no need to copy local variable into another variable
982                }
983                else {
984                    arrayVar = createLoopTempVariable(OBJECT_TYPE);
985                    value.put(asmLoopRangeType, v);
986                    v.store(arrayVar, OBJECT_TYPE);
987                }
988    
989                v.iconst(0);
990                v.store(indexVar, Type.INT_TYPE);
991            }
992    
993            @Override
994            public void checkEmptyLoop(@NotNull Label loopExit) {
995            }
996    
997            @Override
998            public void checkPreCondition(@NotNull Label loopExit) {
999                v.load(indexVar, Type.INT_TYPE);
1000                v.load(arrayVar, OBJECT_TYPE);
1001                v.arraylength();
1002                v.ificmpge(loopExit);
1003            }
1004    
1005            @Override
1006            protected void assignToLoopParameter() {
1007                Type arrayElParamType;
1008                if (KotlinBuiltIns.isArray(loopRangeType)) {
1009                    arrayElParamType = boxType(asmElementType);
1010                }
1011                else {
1012                    arrayElParamType = asmElementType;
1013                }
1014    
1015                v.load(arrayVar, OBJECT_TYPE);
1016                v.load(indexVar, Type.INT_TYPE);
1017                v.aload(arrayElParamType);
1018                StackValue.onStack(arrayElParamType).put(asmElementType, v);
1019                v.store(loopParameterVar, asmElementType);
1020            }
1021    
1022            @Override
1023            protected void increment(@NotNull Label loopExit) {
1024                v.iinc(indexVar, 1);
1025            }
1026        }
1027    
1028        private abstract class AbstractForInProgressionOrRangeLoopGenerator extends AbstractForLoopGenerator {
1029            protected int endVar;
1030    
1031            private StackValue loopParameter;
1032    
1033            private AbstractForInProgressionOrRangeLoopGenerator(@NotNull KtForExpression forExpression) {
1034                super(forExpression);
1035    
1036                switch (asmElementType.getSort()) {
1037                    case Type.INT:
1038                    case Type.BYTE:
1039                    case Type.SHORT:
1040                    case Type.CHAR:
1041                    case Type.LONG:
1042                        break;
1043    
1044                    default:
1045                        throw new IllegalStateException("Unexpected range element type: " + asmElementType);
1046                }
1047            }
1048    
1049            @Override
1050            public void beforeLoop() {
1051                super.beforeLoop();
1052    
1053                endVar = createLoopTempVariable(asmElementType);
1054            }
1055    
1056            protected void checkPostCondition(@NotNull Label loopExit) {
1057                assert endVar != -1 :
1058                        "endVar must be allocated, endVar = " + endVar;
1059                loopParameter().put(asmElementType, v);
1060                v.load(endVar, asmElementType);
1061                if (asmElementType.getSort() == Type.LONG) {
1062                    v.lcmp();
1063                    v.ifeq(loopExit);
1064                }
1065                else {
1066                    v.ificmpeq(loopExit);
1067                }
1068            }
1069    
1070            @Override
1071            public void checkPreCondition(@NotNull Label loopExit) {
1072            }
1073    
1074            @NotNull
1075            protected StackValue loopParameter() {
1076                if (loopParameter == null) {
1077                    loopParameter = StackValue.local(loopParameterVar, loopParameterType);
1078                }
1079                return loopParameter;
1080            }
1081        }
1082    
1083        private abstract class AbstractForInRangeLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator {
1084            private final int step;
1085    
1086            private AbstractForInRangeLoopGenerator(@NotNull KtForExpression forExpression, int step) {
1087                super(forExpression);
1088                this.step = step;
1089                assert step == 1 || step == -1 : "'step' should be either 1 or -1: " + step;
1090            }
1091    
1092            private AbstractForInRangeLoopGenerator(@NotNull KtForExpression forExpression) {
1093                this(forExpression, 1);
1094            }
1095    
1096            @Override
1097            public void beforeLoop() {
1098                super.beforeLoop();
1099    
1100                storeRangeStartAndEnd();
1101            }
1102    
1103            protected abstract void storeRangeStartAndEnd();
1104    
1105            @Override
1106            public void checkEmptyLoop(@NotNull Label loopExit) {
1107                loopParameter().put(asmElementType, v);
1108                v.load(endVar, asmElementType);
1109                if (asmElementType.getSort() == Type.LONG) {
1110                    v.lcmp();
1111                    if (step > 0) {
1112                        v.ifgt(loopExit);
1113                    }
1114                    else {
1115                        v.iflt(loopExit);
1116                    }
1117                }
1118                else {
1119                    if (step > 0) {
1120                        v.ificmpgt(loopExit);
1121                    }
1122                    else {
1123                        v.ificmplt(loopExit);
1124                    }
1125                }
1126            }
1127    
1128            @Override
1129            protected void assignToLoopParameter() {
1130            }
1131    
1132            @Override
1133            protected void increment(@NotNull Label loopExit) {
1134                checkPostCondition(loopExit);
1135    
1136                if (loopParameterType == Type.INT_TYPE) {
1137                    v.iinc(loopParameterVar, step);
1138                }
1139                else {
1140                    StackValue loopParameter = loopParameter();
1141                    loopParameter.put(asmElementType, v);
1142                    genIncrement(asmElementType, step, v);
1143                    loopParameter.store(StackValue.onStack(asmElementType), v);
1144                }
1145            }
1146        }
1147    
1148        private class ForInRangeLiteralLoopGenerator extends AbstractForInRangeLoopGenerator {
1149            private final ReceiverValue from;
1150            private final KtExpression to;
1151    
1152            private ForInRangeLiteralLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
1153                super(forExpression);
1154                this.from = loopRangeCall.getDispatchReceiver();
1155                this.to = getSingleArgumentExpression(loopRangeCall);
1156            }
1157    
1158            @Override
1159            protected void storeRangeStartAndEnd() {
1160                loopParameter().store(generateReceiverValue(from, false), v);
1161                StackValue.local(endVar, asmElementType).store(gen(to), v);
1162            }
1163        }
1164    
1165        private class ForInDownToProgressionLoopGenerator extends AbstractForInRangeLoopGenerator {
1166            private final ReceiverValue from;
1167            private final KtExpression to;
1168    
1169            private ForInDownToProgressionLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
1170                super(forExpression, -1);
1171                this.from = loopRangeCall.getExtensionReceiver();
1172                this.to = getSingleArgumentExpression(loopRangeCall);
1173            }
1174    
1175            @Override
1176            protected void storeRangeStartAndEnd() {
1177                loopParameter().store(generateReceiverValue(from, false), v);
1178                StackValue.local(endVar, asmElementType).store(gen(to), v);
1179            }
1180        }
1181    
1182        private class ForInRangeInstanceLoopGenerator extends AbstractForInRangeLoopGenerator {
1183            private ForInRangeInstanceLoopGenerator(@NotNull KtForExpression forExpression) {
1184                super(forExpression);
1185            }
1186    
1187            @Override
1188            protected void storeRangeStartAndEnd() {
1189                KotlinType loopRangeType = bindingContext.getType(forExpression.getLoopRange());
1190                assert loopRangeType != null;
1191                Type asmLoopRangeType = asmType(loopRangeType);
1192                gen(forExpression.getLoopRange(), asmLoopRangeType);
1193                v.dup();
1194    
1195                // ranges inherit first and last from corresponding progressions
1196                generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType, loopParameterVar);
1197                generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar);
1198            }
1199        }
1200    
1201        private abstract class ForInOptimizedIndicesLoopGenerator extends AbstractForInRangeLoopGenerator {
1202            protected final ReceiverValue receiverValue;
1203            protected final KotlinType expectedReceiverType;
1204    
1205            private ForInOptimizedIndicesLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
1206                super(forExpression);
1207                this.receiverValue = loopRangeCall.getExtensionReceiver();
1208                this.expectedReceiverType = getExpectedReceiverType(loopRangeCall);
1209            }
1210    
1211            @Override
1212            protected void storeRangeStartAndEnd() {
1213                loopParameter().store(StackValue.constant(0, asmElementType), v);
1214    
1215                StackValue receiver = generateReceiverValue(receiverValue, false);
1216                Type receiverType = asmType(expectedReceiverType);
1217                receiver.put(receiverType, v);
1218                getReceiverSizeAsInt();
1219                v.iconst(1);
1220                v.sub(Type.INT_TYPE);
1221                StackValue.local(endVar, asmElementType).store(StackValue.onStack(Type.INT_TYPE), v);
1222            }
1223    
1224            /**
1225             * <code>(receiver -> size:I)</code>
1226             */
1227            protected abstract void getReceiverSizeAsInt();
1228        }
1229    
1230        private class ForInCollectionIndicesRangeLoopGenerator extends ForInOptimizedIndicesLoopGenerator {
1231            private ForInCollectionIndicesRangeLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
1232                super(forExpression, loopRangeCall);
1233            }
1234    
1235            @Override
1236            protected void getReceiverSizeAsInt() {
1237                v.invokeinterface("java/util/Collection", "size", "()I");
1238            }
1239        }
1240    
1241        private class ForInArrayIndicesRangeLoopGenerator extends ForInOptimizedIndicesLoopGenerator {
1242            private ForInArrayIndicesRangeLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
1243                super(forExpression, loopRangeCall);
1244            }
1245    
1246            @Override
1247            protected void getReceiverSizeAsInt() {
1248                v.arraylength();
1249            }
1250        }
1251    
1252        private class ForInCharSequenceIndicesRangeLoopGenerator extends ForInOptimizedIndicesLoopGenerator {
1253            private ForInCharSequenceIndicesRangeLoopGenerator(@NotNull KtForExpression forExpression, @NotNull ResolvedCall<?> loopRangeCall) {
1254                super(forExpression, loopRangeCall);
1255            }
1256    
1257            @Override
1258            protected void getReceiverSizeAsInt() {
1259                v.invokeinterface("java/lang/CharSequence", "length", "()I");
1260            }
1261        }
1262    
1263        private class ForInProgressionExpressionLoopGenerator extends AbstractForInProgressionOrRangeLoopGenerator {
1264            private int incrementVar;
1265            private Type incrementType;
1266    
1267            private ForInProgressionExpressionLoopGenerator(@NotNull KtForExpression forExpression) {
1268                super(forExpression);
1269            }
1270    
1271            @Override
1272            public void beforeLoop() {
1273                super.beforeLoop();
1274    
1275                incrementVar = createLoopTempVariable(asmElementType);
1276    
1277                KotlinType loopRangeType = bindingContext.getType(forExpression.getLoopRange());
1278                assert loopRangeType != null;
1279                Type asmLoopRangeType = asmType(loopRangeType);
1280    
1281                Collection<PropertyDescriptor> incrementProp =
1282                        loopRangeType.getMemberScope().getContributedVariables(Name.identifier("step"), NoLookupLocation.FROM_BACKEND);
1283                assert incrementProp.size() == 1 : loopRangeType + " " + incrementProp.size();
1284                incrementType = asmType(incrementProp.iterator().next().getType());
1285    
1286                gen(forExpression.getLoopRange(), asmLoopRangeType);
1287                v.dup();
1288                v.dup();
1289    
1290                generateRangeOrProgressionProperty(asmLoopRangeType, "getFirst", asmElementType, loopParameterType, loopParameterVar);
1291                generateRangeOrProgressionProperty(asmLoopRangeType, "getLast", asmElementType, asmElementType, endVar);
1292                generateRangeOrProgressionProperty(asmLoopRangeType, "getStep", incrementType, incrementType, incrementVar);
1293            }
1294    
1295            @Override
1296            public void checkEmptyLoop(@NotNull Label loopExit) {
1297                loopParameter().put(asmElementType, v);
1298                v.load(endVar, asmElementType);
1299                v.load(incrementVar, incrementType);
1300    
1301                Label negativeIncrement = new Label();
1302                Label afterIf = new Label();
1303    
1304                if (asmElementType.getSort() == Type.LONG) {
1305                    v.lconst(0L);
1306                    v.lcmp();
1307                    v.ifle(negativeIncrement); // if increment < 0, jump
1308    
1309                    // increment > 0
1310                    v.lcmp();
1311                    v.ifgt(loopExit);
1312                    v.goTo(afterIf);
1313    
1314                    // increment < 0
1315                    v.mark(negativeIncrement);
1316                    v.lcmp();
1317                    v.iflt(loopExit);
1318                    v.mark(afterIf);
1319                }
1320                else {
1321                    v.ifle(negativeIncrement); // if increment < 0, jump
1322    
1323                    // increment > 0
1324                    v.ificmpgt(loopExit);
1325                    v.goTo(afterIf);
1326    
1327                    // increment < 0
1328                    v.mark(negativeIncrement);
1329                    v.ificmplt(loopExit);
1330                    v.mark(afterIf);
1331                }
1332            }
1333    
1334            @Override
1335            protected void assignToLoopParameter() {
1336            }
1337    
1338            @Override
1339            protected void increment(@NotNull Label loopExit) {
1340                checkPostCondition(loopExit);
1341    
1342                StackValue loopParameter = loopParameter();
1343                loopParameter.put(asmElementType, v);
1344                v.load(incrementVar, asmElementType);
1345                v.add(asmElementType);
1346    
1347                if (asmElementType == Type.BYTE_TYPE || asmElementType == Type.SHORT_TYPE || asmElementType == Type.CHAR_TYPE) {
1348                    StackValue.coerce(Type.INT_TYPE, asmElementType, v);
1349                }
1350    
1351                loopParameter.store(StackValue.onStack(asmElementType), v);
1352            }
1353        }
1354    
1355    
1356        @Override
1357        public StackValue visitBreakExpression(@NotNull KtBreakExpression expression, StackValue receiver) {
1358            return generateBreakOrContinueExpression(expression, true, new Label());
1359        }
1360    
1361        @Override
1362        public StackValue visitContinueExpression(@NotNull KtContinueExpression expression, StackValue receiver) {
1363            return generateBreakOrContinueExpression(expression, false, new Label());
1364        }
1365    
1366        @NotNull
1367        private StackValue generateBreakOrContinueExpression(
1368                @NotNull KtExpressionWithLabel expression,
1369                boolean isBreak,
1370                final @NotNull Label afterBreakContinueLabel
1371        ) {
1372            assert expression instanceof KtContinueExpression || expression instanceof KtBreakExpression;
1373    
1374            if (blockStackElements.isEmpty()) {
1375                throw new UnsupportedOperationException("Target label for break/continue not found");
1376            }
1377    
1378            BlockStackElement stackElement = blockStackElements.peek();
1379    
1380            if (stackElement instanceof FinallyBlockStackElement) {
1381                FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement;
1382                //noinspection ConstantConditions
1383                genFinallyBlockOrGoto(finallyBlockStackElement, null, afterBreakContinueLabel);
1384            }
1385            else if (stackElement instanceof LoopBlockStackElement) {
1386                LoopBlockStackElement loopBlockStackElement = (LoopBlockStackElement) stackElement;
1387                KtSimpleNameExpression labelElement = expression.getTargetLabel();
1388                //noinspection ConstantConditions
1389                if (labelElement == null ||
1390                    loopBlockStackElement.targetLabel != null &&
1391                    labelElement.getReferencedName().equals(loopBlockStackElement.targetLabel.getReferencedName())) {
1392                    final Label label = isBreak ? loopBlockStackElement.breakLabel : loopBlockStackElement.continueLabel;
1393                    return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
1394                                                    @Override
1395                                                    public Unit invoke(InstructionAdapter adapter) {
1396                                                        PseudoInsnsKt.fixStackAndJump(v, label);
1397                                                        v.mark(afterBreakContinueLabel);
1398                                                        return Unit.INSTANCE;
1399                                                    }
1400                                                }
1401                    );
1402                }
1403            }
1404            else {
1405                throw new UnsupportedOperationException("Wrong BlockStackElement in processing stack");
1406            }
1407    
1408            blockStackElements.pop();
1409            StackValue result = generateBreakOrContinueExpression(expression, isBreak, afterBreakContinueLabel);
1410            blockStackElements.push(stackElement);
1411            return result;
1412        }
1413    
1414        private StackValue generateSingleBranchIf(
1415                final StackValue condition,
1416                final KtIfExpression ifExpression,
1417                final KtExpression expression,
1418                final boolean inverse,
1419                final boolean isStatement
1420        ) {
1421            Type targetType = isStatement ? Type.VOID_TYPE : expressionType(ifExpression);
1422            return StackValue.operation(targetType, new Function1<InstructionAdapter, Unit>() {
1423                @Override
1424                public Unit invoke(InstructionAdapter v) {
1425                    Label elseLabel = new Label();
1426                    BranchedValue.Companion.condJump(condition, elseLabel, inverse, v);
1427    
1428                    if (isStatement) {
1429                        gen(expression, Type.VOID_TYPE);
1430                        v.mark(elseLabel);
1431                    }
1432                    else {
1433                        Type targetType = expressionType(ifExpression);
1434                        gen(expression, targetType);
1435                        Label end = new Label();
1436                        v.goTo(end);
1437    
1438                        v.mark(elseLabel);
1439                        StackValue.putUnitInstance(v);
1440    
1441                        markStartLineNumber(ifExpression);
1442                        v.mark(end);
1443                    }
1444                    return null;
1445                }
1446            });
1447        }
1448    
1449        @Override
1450        public StackValue visitConstantExpression(@NotNull KtConstantExpression expression, StackValue receiver) {
1451            ConstantValue<?> compileTimeValue = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext, state.getShouldInlineConstVals());
1452            assert compileTimeValue != null;
1453            return StackValue.constant(compileTimeValue.getValue(), expressionType(expression));
1454        }
1455    
1456        @Nullable
1457        public static ConstantValue<?> getPrimitiveOrStringCompileTimeConstant(
1458                @NotNull KtExpression expression,
1459                @NotNull BindingContext bindingContext,
1460                boolean shouldInlineConstVals) {
1461            ConstantValue<?> constant = getCompileTimeConstant(expression, bindingContext, false, shouldInlineConstVals);
1462            if (constant == null || ConstantExpressionEvaluatorKt.isStandaloneOnlyConstant(constant)) {
1463                return null;
1464            }
1465            return constant;
1466        }
1467    
1468        @Nullable
1469        public static ConstantValue<?> getCompileTimeConstant(
1470                @NotNull KtExpression expression,
1471                @NotNull BindingContext bindingContext,
1472                boolean shouldInlineConstVals) {
1473            return getCompileTimeConstant(expression, bindingContext, false, shouldInlineConstVals);
1474        }
1475    
1476        @Nullable
1477        public static ConstantValue<?> getCompileTimeConstant(
1478                @NotNull KtExpression expression,
1479                @NotNull final BindingContext bindingContext,
1480                boolean takeUpConstValsAsConst,
1481                boolean shouldInlineConstVals
1482        ) {
1483            CompileTimeConstant<?> compileTimeValue = ConstantExpressionEvaluator.getConstant(expression, bindingContext);
1484            if (compileTimeValue == null || compileTimeValue.getUsesNonConstValAsConstant()) {
1485                return null;
1486            }
1487    
1488            if (!shouldInlineConstVals && !takeUpConstValsAsConst && compileTimeValue.getUsesVariableAsConstant()) {
1489                final Ref<Boolean> containsNonInlinedVals = new Ref<Boolean>(false);
1490                KtVisitor constantChecker = new KtVisitor() {
1491                    @Override
1492                    public Object visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression, Object data) {
1493                        ResolvedCall resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext);
1494                        if (resolvedCall != null) {
1495                            CallableDescriptor callableDescriptor = resolvedCall.getResultingDescriptor();
1496                            if (callableDescriptor instanceof PropertyDescriptor &&
1497                                !JvmCodegenUtil.isInlinedJavaConstProperty((VariableDescriptor) callableDescriptor)) {
1498                                    containsNonInlinedVals.set(true);
1499                            }
1500                        }
1501                        return null;
1502                    }
1503    
1504                    @Override
1505                    public Object visitKtElement(@NotNull KtElement element, Object data) {
1506                        if (!containsNonInlinedVals.get()) {
1507                            element.acceptChildren(this);
1508                        }
1509                        return null;
1510                    }
1511                };
1512    
1513                expression.accept(constantChecker);
1514    
1515                if (containsNonInlinedVals.get()) {
1516                    return null;
1517                }
1518            }
1519    
1520            KotlinType expectedType = bindingContext.getType(expression);
1521            return compileTimeValue.toConstantValue(expectedType);
1522        }
1523    
1524        @Override
1525        public StackValue visitStringTemplateExpression(@NotNull KtStringTemplateExpression expression, StackValue receiver) {
1526            StringBuilder constantValue = new StringBuilder("");
1527            final KtStringTemplateEntry[] entries = expression.getEntries();
1528    
1529            if (entries.length == 1 && entries[0] instanceof KtStringTemplateEntryWithExpression) {
1530                KtExpression expr = entries[0].getExpression();
1531                return genToString(gen(expr), expressionType(expr));
1532            }
1533    
1534            for (KtStringTemplateEntry entry : entries) {
1535                if (entry instanceof KtLiteralStringTemplateEntry) {
1536                    constantValue.append(entry.getText());
1537                }
1538                else if (entry instanceof KtEscapeStringTemplateEntry) {
1539                    constantValue.append(((KtEscapeStringTemplateEntry) entry).getUnescapedValue());
1540                }
1541                else {
1542                    constantValue = null;
1543                    break;
1544                }
1545            }
1546            if (constantValue != null) {
1547                Type type = expressionType(expression);
1548                return StackValue.constant(constantValue.toString(), type);
1549            }
1550            else {
1551                return StackValue.operation(JAVA_STRING_TYPE, new Function1<InstructionAdapter, Unit>() {
1552                    @Override
1553                    public Unit invoke(InstructionAdapter v) {
1554                        genStringBuilderConstructor(v);
1555                        for (KtStringTemplateEntry entry : entries) {
1556                            if (entry instanceof KtStringTemplateEntryWithExpression) {
1557                                invokeAppend(entry.getExpression());
1558                            }
1559                            else {
1560                                String text = entry instanceof KtEscapeStringTemplateEntry
1561                                              ? ((KtEscapeStringTemplateEntry) entry).getUnescapedValue()
1562                                              : entry.getText();
1563                                v.aconst(text);
1564                                genInvokeAppendMethod(v, JAVA_STRING_TYPE);
1565                            }
1566                        }
1567                        v.invokevirtual("java/lang/StringBuilder", "toString", "()Ljava/lang/String;", false);
1568                        return Unit.INSTANCE;
1569                    }
1570                });
1571            }
1572        }
1573    
1574        @Override
1575        public StackValue visitBlockExpression(@NotNull KtBlockExpression expression, StackValue receiver) {
1576            return generateBlock(expression, false);
1577        }
1578    
1579        @Override
1580        public StackValue visitNamedFunction(@NotNull KtNamedFunction function, StackValue data) {
1581            return visitNamedFunction(function, data, false);
1582        }
1583    
1584        public StackValue visitNamedFunction(@NotNull KtNamedFunction function, StackValue data, boolean isStatement) {
1585            assert data == StackValue.none();
1586    
1587            if (KtPsiUtil.isScriptDeclaration(function)) {
1588                return StackValue.none();
1589            }
1590    
1591            StackValue closure = genClosure(function, null);
1592            if (isStatement) {
1593                DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, function);
1594                int index = lookupLocalIndex(descriptor);
1595                closure.put(OBJECT_TYPE, v);
1596                v.store(index, OBJECT_TYPE);
1597                return StackValue.none();
1598            }
1599            else {
1600                return closure;
1601            }
1602        }
1603    
1604        @Override
1605        public StackValue visitLambdaExpression(@NotNull KtLambdaExpression expression, StackValue receiver) {
1606            if (Boolean.TRUE.equals(bindingContext.get(BLOCK, expression))) {
1607                return gen(expression.getFunctionLiteral().getBodyExpression());
1608            }
1609            else {
1610                return genClosure(expression.getFunctionLiteral(), null);
1611            }
1612        }
1613    
1614        @NotNull
1615        private StackValue genClosure(KtDeclarationWithBody declaration, @Nullable SamType samType) {
1616            FunctionDescriptor descriptor = bindingContext.get(FUNCTION, declaration);
1617            assert descriptor != null : "Function is not resolved to descriptor: " + declaration.getText();
1618    
1619            return genClosure(
1620                    declaration, descriptor, new ClosureGenerationStrategy(state, declaration), samType, null, null
1621            );
1622        }
1623    
1624        @NotNull
1625        private StackValue genClosure(
1626                @NotNull KtElement declaration,
1627                @NotNull FunctionDescriptor descriptor,
1628                @NotNull FunctionGenerationStrategy strategy,
1629                @Nullable SamType samType,
1630                @Nullable FunctionDescriptor functionReferenceTarget,
1631                @Nullable StackValue functionReferenceReceiver
1632        ) {
1633            ClassBuilder cv = state.getFactory().newVisitor(
1634                    JvmDeclarationOriginKt.OtherOrigin(declaration, descriptor),
1635                    asmTypeForAnonymousClass(bindingContext, descriptor),
1636                    declaration.getContainingFile()
1637            );
1638    
1639            ClosureCodegen coroutineCodegen = CoroutineCodegen.createByLambda(this, descriptor, declaration, cv);
1640            ClosureCodegen closureCodegen = coroutineCodegen != null ? coroutineCodegen : new ClosureCodegen(
1641                    state, declaration, samType, context.intoClosure(descriptor, this, typeMapper),
1642                    functionReferenceTarget, strategy, parentCodegen, cv
1643            );
1644    
1645            closureCodegen.generate();
1646    
1647            return putClosureInstanceOnStack(closureCodegen, functionReferenceReceiver);
1648        }
1649    
1650        @NotNull
1651        public StackValue putClosureInstanceOnStack(
1652                @NotNull ClosureCodegen closureCodegen,
1653                @Nullable StackValue functionReferenceReceiver
1654        ) {
1655            if (closureCodegen.getReifiedTypeParametersUsages().wereUsedReifiedParameters()) {
1656                ReifiedTypeInliner.putNeedClassReificationMarker(v);
1657                propagateChildReifiedTypeParametersUsages(closureCodegen.getReifiedTypeParametersUsages());
1658            }
1659    
1660            return closureCodegen.putInstanceOnStack(this, functionReferenceReceiver);
1661        }
1662    
1663        @Override
1664        public StackValue visitObjectLiteralExpression(@NotNull KtObjectLiteralExpression expression, StackValue receiver) {
1665            final ObjectLiteralResult objectLiteralResult = generateObjectLiteral(expression);
1666            final ClassDescriptor classDescriptor = objectLiteralResult.classDescriptor;
1667            final Type type = typeMapper.mapType(classDescriptor);
1668    
1669            return StackValue.operation(type, new Function1<InstructionAdapter, Unit>() {
1670                @Override
1671                public Unit invoke(InstructionAdapter v) {
1672                    if (objectLiteralResult.wereReifiedMarkers) {
1673                        ReifiedTypeInliner.putNeedClassReificationMarker(v);
1674                    }
1675                    v.anew(type);
1676                    v.dup();
1677    
1678                    pushClosureOnStack(classDescriptor, true, defaultCallGenerator, /* functionReferenceReceiver = */ null);
1679    
1680                    ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
1681                    assert primaryConstructor != null : "There should be primary constructor for object literal";
1682                    ResolvedCall<ConstructorDescriptor> superCall = getDelegationConstructorCall(bindingContext, primaryConstructor);
1683                    if (superCall != null) {
1684                        // For an anonymous object, we should also generate all non-default arguments that it captures for its super call
1685                        ConstructorDescriptor superConstructor = superCall.getResultingDescriptor();
1686                        ConstructorDescriptor constructorToCall = SamCodegenUtil.resolveSamAdapter(superConstructor);
1687                        List<ValueParameterDescriptor> superValueParameters = superConstructor.getValueParameters();
1688                        int params = superValueParameters.size();
1689                        List<Type> superMappedTypes = typeMapper.mapToCallableMethod(constructorToCall, false).getValueParameterTypes();
1690                        assert superMappedTypes.size() >= params : String
1691                                .format("Incorrect number of mapped parameters vs arguments: %d < %d for %s",
1692                                        superMappedTypes.size(), params, classDescriptor);
1693    
1694                        List<ResolvedValueArgument> valueArguments = new ArrayList<ResolvedValueArgument>(params);
1695                        List<ValueParameterDescriptor> valueParameters = new ArrayList<ValueParameterDescriptor>(params);
1696                        List<Type> mappedTypes = new ArrayList<Type>(params);
1697                        for (ValueParameterDescriptor parameter : superValueParameters) {
1698                            ResolvedValueArgument argument = superCall.getValueArguments().get(parameter);
1699                            if (!(argument instanceof DefaultValueArgument)) {
1700                                valueArguments.add(argument);
1701                                valueParameters.add(parameter);
1702                                mappedTypes.add(superMappedTypes.get(parameter.getIndex()));
1703                            }
1704                        }
1705                        ArgumentGenerator argumentGenerator =
1706                                new CallBasedArgumentGenerator(ExpressionCodegen.this, defaultCallGenerator, valueParameters, mappedTypes);
1707    
1708                        argumentGenerator.generate(valueArguments, valueArguments);
1709                    }
1710    
1711                    Collection<ClassConstructorDescriptor> constructors = classDescriptor.getConstructors();
1712                    assert constructors.size() == 1 : "Unexpected number of constructors for class: " + classDescriptor + " " + constructors;
1713                    ConstructorDescriptor constructorDescriptor = CollectionsKt.single(constructors);
1714    
1715                    Method constructor = typeMapper.mapAsmMethod(SamCodegenUtil.resolveSamAdapter(constructorDescriptor));
1716                    v.invokespecial(type.getInternalName(), "<init>", constructor.getDescriptor(), false);
1717                    return Unit.INSTANCE;
1718                }
1719            });
1720        }
1721    
1722        public void pushClosureOnStack(
1723                @NotNull ClassDescriptor classDescriptor,
1724                boolean putThis,
1725                @NotNull CallGenerator callGenerator,
1726                @Nullable StackValue functionReferenceReceiver
1727        ) {
1728            CalculatedClosure closure = bindingContext.get(CLOSURE, classDescriptor);
1729            if (closure == null) return;
1730    
1731            int paramIndex = 0;
1732    
1733            if (putThis) {
1734                ClassDescriptor captureThis = closure.getCaptureThis();
1735                if (captureThis != null) {
1736                    StackValue thisOrOuter = generateThisOrOuter(captureThis, false);
1737                    assert !isPrimitive(thisOrOuter.type) : "This or outer should be non primitive: " + thisOrOuter.type;
1738                    callGenerator.putCapturedValueOnStack(thisOrOuter, thisOrOuter.type, paramIndex++);
1739                }
1740            }
1741    
1742            KotlinType captureReceiver = closure.getCaptureReceiverType();
1743            if (captureReceiver != null) {
1744                StackValue capturedReceiver =
1745                        functionReferenceReceiver != null ? functionReferenceReceiver :
1746                        generateExtensionReceiver(unwrapOriginalReceiverOwnerForSuspendFunction(context));
1747                callGenerator.putCapturedValueOnStack(capturedReceiver, capturedReceiver.type, paramIndex++);
1748            }
1749    
1750            for (Map.Entry<DeclarationDescriptor, EnclosedValueDescriptor> entry : closure.getCaptureVariables().entrySet()) {
1751                Type sharedVarType = typeMapper.getSharedVarType(entry.getKey());
1752                if (sharedVarType == null) {
1753                    sharedVarType = typeMapper.mapType((VariableDescriptor) entry.getKey());
1754                }
1755                StackValue capturedVar = lookupOuterValue(entry.getValue());
1756                callGenerator.putCapturedValueOnStack(capturedVar, sharedVarType, paramIndex++);
1757            }
1758    
1759    
1760            ClassDescriptor superClass = DescriptorUtilsKt.getSuperClassNotAny(classDescriptor);
1761            if (superClass != null) {
1762                pushClosureOnStack(
1763                        superClass, putThis && closure.getCaptureThis() == null, callGenerator, /* functionReferenceReceiver = */ null
1764                );
1765            }
1766    
1767            if (closure.isSuspend()) {
1768                // resultContinuation
1769                if (closure.isSuspendLambda()) {
1770                    v.aconst(null);
1771                }
1772                else {
1773                    assert context.getFunctionDescriptor().isSuspend() : "Coroutines closure must be created only inside suspend functions";
1774                    ValueParameterDescriptor continuationParameter = CollectionsKt.last(context.getFunctionDescriptor().getValueParameters());
1775                    StackValue continuationValue = findLocalOrCapturedValue(continuationParameter);
1776    
1777                    assert continuationValue != null : "Couldn't find a value for continuation parameter of " + context.getFunctionDescriptor();
1778    
1779                    callGenerator.putCapturedValueOnStack(continuationValue, continuationValue.type, paramIndex++);
1780                }
1781            }
1782        }
1783    
1784        @NotNull
1785        private static CallableDescriptor unwrapOriginalReceiverOwnerForSuspendFunction(@NotNull MethodContext context) {
1786            FunctionDescriptor originalForDoResume =
1787                    context.getFunctionDescriptor().getUserData(CoroutineCodegenUtilKt.INITIAL_SUSPEND_DESCRIPTOR_FOR_DO_RESUME);
1788    
1789            if (originalForDoResume != null) {
1790                return originalForDoResume;
1791            }
1792    
1793            if (context.getFunctionDescriptor().isSuspend()) {
1794                return CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(context.getFunctionDescriptor());
1795            }
1796    
1797            return context.getFunctionDescriptor();
1798        }
1799    
1800        /* package */ StackValue generateBlock(@NotNull KtBlockExpression expression, boolean isStatement) {
1801            if (expression.getParent() instanceof KtNamedFunction) {
1802                // For functions end of block should be end of function label
1803                return generateBlock(expression.getStatements(), isStatement, null, context.getMethodEndLabel());
1804            }
1805            return generateBlock(expression.getStatements(), isStatement, null, null);
1806        }
1807    
1808        @NotNull
1809        public StackValue lookupOuterValue(EnclosedValueDescriptor d) {
1810            DeclarationDescriptor descriptor = d.getDescriptor();
1811            for (LocalLookup.LocalLookupCase aCase : LocalLookup.LocalLookupCase.values()) {
1812                if (aCase.isCase(descriptor)) {
1813                    return aCase.outerValue(d, this);
1814                }
1815            }
1816            throw new IllegalStateException("Can't get outer value in " + this + " for " + d);
1817        }
1818    
1819        private StackValueWithLeaveTask generateBlock(
1820                @NotNull List<KtExpression> statements,
1821                boolean isStatement,
1822                @Nullable Label labelBeforeLastExpression,
1823                @Nullable final Label labelBlockEnd
1824        ) {
1825            final Label blockEnd = labelBlockEnd != null ? labelBlockEnd : new Label();
1826    
1827            final List<Function<StackValue, Void>> leaveTasks = Lists.newArrayList();
1828    
1829            @Nullable
1830            StackValue blockResult = null;
1831    
1832            for (Iterator<KtExpression> iterator = statements.iterator(); iterator.hasNext(); ) {
1833                KtExpression possiblyLabeledStatement = iterator.next();
1834    
1835                KtElement statement = KtPsiUtil.safeDeparenthesize(possiblyLabeledStatement);
1836    
1837                if (statement instanceof KtNamedDeclaration) {
1838                    KtNamedDeclaration declaration = (KtNamedDeclaration) statement;
1839                    if (KtPsiUtil.isScriptDeclaration(declaration)) {
1840                        continue;
1841                    }
1842                }
1843    
1844                putDescriptorIntoFrameMap(statement);
1845    
1846                boolean isExpression = !iterator.hasNext() && !isStatement;
1847                if (isExpression && labelBeforeLastExpression != null) {
1848                    v.mark(labelBeforeLastExpression);
1849                }
1850    
1851                // Note that this statementResult value is potentially unused (in case of handleResult coroutine call)
1852                // It's supposed here that no bytecode is emitted until 'put' call on relevant StackValue object
1853                StackValue statementResult = isExpression ? gen(possiblyLabeledStatement) : genStatement(possiblyLabeledStatement);
1854    
1855                if (!iterator.hasNext()) {
1856                    blockResult = statementResult;
1857                }
1858                else {
1859                    statementResult.put(Type.VOID_TYPE, v);
1860                }
1861    
1862                addLeaveTaskToRemoveDescriptorFromFrameMap(statement, blockEnd, leaveTasks);
1863            }
1864    
1865            if (statements.isEmpty()) {
1866                blockResult = StackValue.none();
1867            }
1868    
1869            assert blockResult != null : "Block result should be initialized in the loop or the condition above";
1870    
1871            return new StackValueWithLeaveTask(blockResult, new Function1<StackValue, Unit>() {
1872                @Override
1873                public Unit invoke(StackValue value) {
1874                    if (labelBlockEnd == null) {
1875                        v.mark(blockEnd);
1876                    }
1877                    for (Function<StackValue, Void> task : Lists.reverse(leaveTasks)) {
1878                        task.fun(value);
1879                    }
1880                    return Unit.INSTANCE;
1881                }
1882            });
1883        }
1884    
1885        @Nullable
1886        private StackValue getCoroutineInstanceValueForSuspensionPoint(@NotNull ResolvedCall<?> resolvedCall) {
1887            FunctionDescriptor enclosingSuspendLambdaForSuspensionPoint =
1888                    bindingContext.get(ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall());
1889    
1890            if (enclosingSuspendLambdaForSuspensionPoint == null) return null;
1891            return genCoroutineInstanceBySuspendFunction(enclosingSuspendLambdaForSuspensionPoint);
1892        }
1893    
1894        @Nullable
1895        private StackValue genCoroutineInstanceBySuspendFunction(@NotNull FunctionDescriptor suspendFunction) {
1896            if (!CoroutineCodegenUtilKt.isStateMachineNeeded(suspendFunction, bindingContext)) return null;
1897            ClassDescriptor suspendLambdaClassDescriptor = bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, suspendFunction);
1898            assert suspendLambdaClassDescriptor != null : "Coroutine class descriptor should not be null";
1899    
1900            return StackValue.thisOrOuter(this, suspendLambdaClassDescriptor, false, false);
1901        }
1902    
1903        @NotNull
1904        private Type getVariableType(@NotNull VariableDescriptor variableDescriptor) {
1905            Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
1906            return sharedVarType != null ? sharedVarType : getVariableTypeNoSharing(variableDescriptor);
1907        }
1908    
1909        @NotNull
1910        private Type getVariableTypeNoSharing(@NotNull VariableDescriptor variableDescriptor) {
1911            KotlinType varType = isDelegatedLocalVariable(variableDescriptor)
1912                                 ? JvmCodegenUtil.getPropertyDelegateType((VariableDescriptorWithAccessors) variableDescriptor, bindingContext)
1913                                 : variableDescriptor.getType();
1914            //noinspection ConstantConditions
1915            return asmType(varType);
1916        }
1917    
1918        private static boolean isSharedVarType(@NotNull Type type) {
1919            return type.getSort() == Type.OBJECT && type.getInternalName().startsWith(REF_TYPE_PREFIX);
1920        }
1921    
1922    
1923        private void putDescriptorIntoFrameMap(@NotNull KtElement statement) {
1924            if (statement instanceof KtDestructuringDeclaration) {
1925                KtDestructuringDeclaration multiDeclaration = (KtDestructuringDeclaration) statement;
1926                for (KtDestructuringDeclarationEntry entry : multiDeclaration.getEntries()) {
1927                    putLocalVariableIntoFrameMap(entry);
1928                }
1929            }
1930    
1931            if (statement instanceof KtVariableDeclaration) {
1932                putLocalVariableIntoFrameMap((KtVariableDeclaration) statement);
1933            }
1934    
1935            if (statement instanceof KtNamedFunction) {
1936                DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, statement);
1937                assert descriptor instanceof FunctionDescriptor : "Couldn't find function declaration in binding context " + statement.getText();
1938                Type type = asmTypeForAnonymousClass(bindingContext, (FunctionDescriptor) descriptor);
1939                myFrameMap.enter(descriptor, type);
1940            }
1941        }
1942    
1943        private void putLocalVariableIntoFrameMap(@NotNull KtVariableDeclaration statement) {
1944            VariableDescriptor variableDescriptor = getVariableDescriptorNotNull(statement);
1945            // Do not modify local variables table for variables like _ in val (_, y) = pair
1946            // They always will have special name
1947            if (variableDescriptor.getName().isSpecial()) return;
1948    
1949            Type type = getVariableType(variableDescriptor);
1950            int index = myFrameMap.enter(variableDescriptor, type);
1951    
1952            if (isDelegatedLocalVariable(variableDescriptor)) {
1953                myFrameMap.enter(getDelegatedLocalVariableMetadata(variableDescriptor, bindingContext), AsmTypes.K_PROPERTY0_TYPE);
1954            }
1955    
1956            if (isSharedVarType(type)) {
1957                markLineNumber(statement, false);
1958                v.anew(type);
1959                v.dup();
1960                v.invokespecial(type.getInternalName(), "<init>", "()V", false);
1961                v.store(index, OBJECT_TYPE);
1962            }
1963        }
1964    
1965        private void addLeaveTaskToRemoveDescriptorFromFrameMap(
1966                @NotNull KtElement statement,
1967                @NotNull Label blockEnd,
1968                @NotNull List<Function<StackValue, Void>> leaveTasks
1969        ) {
1970            if (statement instanceof KtDestructuringDeclaration) {
1971                KtDestructuringDeclaration multiDeclaration = (KtDestructuringDeclaration) statement;
1972                for (KtDestructuringDeclarationEntry entry : multiDeclaration.getEntries()) {
1973                    addLeaveTaskToRemoveLocalVariableFromFrameMap(entry, blockEnd, leaveTasks);
1974                }
1975            }
1976    
1977            if (statement instanceof KtVariableDeclaration) {
1978                addLeaveTaskToRemoveLocalVariableFromFrameMap((KtVariableDeclaration) statement, blockEnd, leaveTasks);
1979            }
1980    
1981            if (statement instanceof KtNamedFunction) {
1982                addLeaveTaskToRemoveNamedFunctionFromFrameMap((KtNamedFunction) statement, blockEnd, leaveTasks);
1983            }
1984        }
1985    
1986        private void addLeaveTaskToRemoveLocalVariableFromFrameMap(
1987                @NotNull KtVariableDeclaration statement,
1988                final Label blockEnd,
1989                @NotNull List<Function<StackValue, Void>> leaveTasks
1990        ) {
1991            final VariableDescriptor variableDescriptor = getVariableDescriptorNotNull(statement);
1992    
1993            // Do not modify local variables table for variables like _ in val (_, y) = pair
1994            // They always will have special name
1995            if (variableDescriptor.getName().isSpecial()) return;
1996    
1997            final Type type = getVariableType(variableDescriptor);
1998    
1999            final Label scopeStart = new Label();
2000            v.mark(scopeStart);
2001    
2002            leaveTasks.add(new Function<StackValue, Void>() {
2003                @Override
2004                public Void fun(StackValue answer) {
2005                    if (isDelegatedLocalVariable(variableDescriptor)) {
2006                        myFrameMap.leave(getDelegatedLocalVariableMetadata(variableDescriptor, bindingContext));
2007                    }
2008    
2009                    int index = myFrameMap.leave(variableDescriptor);
2010    
2011                    if (isSharedVarType(type)) {
2012                        v.aconst(null);
2013                        v.store(index, OBJECT_TYPE);
2014                    }
2015                    v.visitLocalVariable(variableDescriptor.getName().asString(), type.getDescriptor(), null, scopeStart, blockEnd, index);
2016                    return null;
2017                }
2018            });
2019        }
2020    
2021        private void addLeaveTaskToRemoveNamedFunctionFromFrameMap(
2022                @NotNull final KtNamedFunction statement,
2023                final Label blockEnd,
2024                @NotNull List<Function<StackValue, Void>> leaveTasks
2025        ) {
2026            final FunctionDescriptor functionDescriptor = (FunctionDescriptor) bindingContext.get(DECLARATION_TO_DESCRIPTOR, statement);
2027            assert functionDescriptor != null;
2028    
2029            final Type type = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
2030    
2031            final Label scopeStart = new Label();
2032            v.mark(scopeStart);
2033    
2034            leaveTasks.add(new Function<StackValue, Void>() {
2035                @Override
2036                public Void fun(StackValue answer) {
2037                    int index = myFrameMap.leave(functionDescriptor);
2038    
2039                    assert !functionDescriptor.getName().isSpecial() : "Local variable should be generated only for function with name: " + statement.getText();
2040                    v.visitLocalVariable(functionDescriptor.getName().asString() + "$", type.getDescriptor(), null, scopeStart, blockEnd, index);
2041                    return null;
2042                }
2043            });
2044        }
2045    
2046        public boolean isShouldMarkLineNumbers() {
2047            return shouldMarkLineNumbers;
2048        }
2049    
2050        public void setShouldMarkLineNumbers(boolean shouldMarkLineNumbers) {
2051            this.shouldMarkLineNumbers = shouldMarkLineNumbers;
2052        }
2053    
2054        public void markStartLineNumber(@NotNull KtElement element) {
2055            markLineNumber(element, false);
2056        }
2057    
2058        public void markLineNumber(@NotNull KtElement statement, boolean markEndOffset) {
2059            if (!shouldMarkLineNumbers) return;
2060    
2061            Integer lineNumber = CodegenUtil.getLineNumberForElement(statement, markEndOffset);
2062            if (lineNumber == null || lineNumber == myLastLineNumber) {
2063                return;
2064            }
2065            myLastLineNumber = lineNumber;
2066    
2067            Label label = new Label();
2068            v.visitLabel(label);
2069            v.visitLineNumber(lineNumber, label);
2070        }
2071    
2072        //we should generate additional linenumber info after inline call only if it used as argument
2073        public void markLineNumberAfterInlineIfNeeded() {
2074            if (!shouldMarkLineNumbers) {
2075                //if it used as general argument
2076                if (myLastLineNumber > -1) {
2077                    Label label = new Label();
2078                    v.visitLabel(label);
2079                    v.visitLineNumber(myLastLineNumber, label);
2080                }
2081            } else {
2082                //if it used as argument of infix call (in this case lineNumber for simple inlineCall also would be reset)
2083                myLastLineNumber = -1;
2084            }
2085        }
2086    
2087        public int getLastLineNumber() {
2088            return myLastLineNumber;
2089        }
2090    
2091        private void doFinallyOnReturn(@NotNull Label afterReturnLabel) {
2092            if(!blockStackElements.isEmpty()) {
2093                BlockStackElement stackElement = blockStackElements.peek();
2094                if (stackElement instanceof FinallyBlockStackElement) {
2095                    FinallyBlockStackElement finallyBlockStackElement = (FinallyBlockStackElement) stackElement;
2096                    genFinallyBlockOrGoto(finallyBlockStackElement, null, afterReturnLabel);
2097                }
2098                else if (stackElement instanceof LoopBlockStackElement) {
2099    
2100                } else {
2101                    throw new UnsupportedOperationException("Wrong BlockStackElement in processing stack");
2102                }
2103    
2104                blockStackElements.pop();
2105                doFinallyOnReturn(afterReturnLabel);
2106                blockStackElements.push(stackElement);
2107            }
2108        }
2109    
2110        public boolean hasFinallyBlocks() {
2111            for (BlockStackElement element : blockStackElements) {
2112                if (element instanceof FinallyBlockStackElement) {
2113                    return true;
2114                }
2115            }
2116            return false;
2117        }
2118    
2119        private void genFinallyBlockOrGoto(
2120                @Nullable FinallyBlockStackElement finallyBlockStackElement,
2121                @Nullable Label tryCatchBlockEnd,
2122                @Nullable Label afterJumpLabel
2123        ) {
2124            if (finallyBlockStackElement != null) {
2125                finallyDepth++;
2126                assert finallyBlockStackElement.gaps.size() % 2 == 0 : "Finally block gaps are inconsistent";
2127    
2128                BlockStackElement topOfStack = blockStackElements.pop();
2129                assert topOfStack == finallyBlockStackElement : "Top element of stack doesn't equals processing finally block";
2130    
2131                KtTryExpression jetTryExpression = finallyBlockStackElement.expression;
2132                Label finallyStart = new Label();
2133                v.mark(finallyStart);
2134                finallyBlockStackElement.addGapLabel(finallyStart);
2135                if (InlineCodegenUtil.isFinallyMarkerRequired(context)) {
2136                    InlineCodegenUtil.generateFinallyMarker(v, finallyDepth, true);
2137                }
2138                //noinspection ConstantConditions
2139                gen(jetTryExpression.getFinallyBlock().getFinalExpression(), Type.VOID_TYPE);
2140    
2141                if (InlineCodegenUtil.isFinallyMarkerRequired(context)) {
2142                    InlineCodegenUtil.generateFinallyMarker(v, finallyDepth, false);
2143                }
2144            }
2145    
2146            if (tryCatchBlockEnd != null) {
2147                v.goTo(tryCatchBlockEnd);
2148            }
2149    
2150            if (finallyBlockStackElement != null) {
2151                finallyDepth--;
2152                Label finallyEnd = afterJumpLabel != null ? afterJumpLabel : new Label();
2153                if (afterJumpLabel == null) {
2154                    v.mark(finallyEnd);
2155                }
2156                finallyBlockStackElement.addGapLabel(finallyEnd);
2157    
2158                blockStackElements.push(finallyBlockStackElement);
2159            }
2160        }
2161    
2162        @Override
2163        public StackValue visitReturnExpression(@NotNull final KtReturnExpression expression, final StackValue receiver) {
2164            return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
2165                @Override
2166                public Unit invoke(InstructionAdapter adapter) {
2167                    KtExpression returnedExpression = expression.getReturnedExpression();
2168                    CallableMemberDescriptor descriptor = getContext().getContextDescriptor();
2169                    NonLocalReturnInfo nonLocalReturn = getNonLocalReturnInfo(descriptor, expression);
2170                    boolean isNonLocalReturn = nonLocalReturn != null;
2171                    if (isNonLocalReturn && state.isInlineDisabled()) {
2172                        state.getDiagnostics().report(Errors.NON_LOCAL_RETURN_IN_DISABLED_INLINE.on(expression));
2173                        genThrow(v, "java/lang/UnsupportedOperationException",
2174                                 "Non-local returns are not allowed with inlining disabled");
2175                        return Unit.INSTANCE;
2176                    }
2177    
2178                    Type returnType = isNonLocalReturn ? nonLocalReturn.returnType : ExpressionCodegen.this.returnType;
2179                    StackValue valueToReturn = returnedExpression != null ? gen(returnedExpression) : StackValue.none();
2180    
2181                    putStackValue(returnedExpression, returnType, valueToReturn);
2182    
2183                    Label afterReturnLabel = new Label();
2184                    generateFinallyBlocksIfNeeded(returnType, afterReturnLabel);
2185    
2186                    if (isNonLocalReturn) {
2187                        InlineCodegenUtil.generateGlobalReturnFlag(v, nonLocalReturn.labelName);
2188                        v.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
2189                    }
2190                    else {
2191                        v.areturn(ExpressionCodegen.this.returnType);
2192                    }
2193    
2194                    v.mark(afterReturnLabel);
2195                    return Unit.INSTANCE;
2196                }
2197            });
2198        }
2199    
2200        public void generateFinallyBlocksIfNeeded(Type returnType, @NotNull Label afterReturnLabel) {
2201            if (hasFinallyBlocks()) {
2202                if (!Type.VOID_TYPE.equals(returnType)) {
2203                    int returnValIndex = myFrameMap.enterTemp(returnType);
2204                    StackValue.Local localForReturnValue = StackValue.local(returnValIndex, returnType);
2205                    localForReturnValue.store(StackValue.onStack(returnType), v);
2206                    doFinallyOnReturn(afterReturnLabel);
2207                    localForReturnValue.put(returnType, v);
2208                    myFrameMap.leaveTemp(returnType);
2209                }
2210                else {
2211                    doFinallyOnReturn(afterReturnLabel);
2212                }
2213            }
2214        }
2215    
2216        @Nullable
2217        private NonLocalReturnInfo getNonLocalReturnInfo(@NotNull CallableMemberDescriptor descriptor, @NotNull KtReturnExpression expression) {
2218            //call inside lambda
2219            if (isFunctionLiteral(descriptor) || isFunctionExpression(descriptor)) {
2220                if (expression.getLabelName() == null) {
2221                    if (isFunctionLiteral(descriptor)) {
2222                        //non labeled return couldn't be local in lambda
2223                        FunctionDescriptor containingFunction =
2224                                BindingContextUtils.getContainingFunctionSkipFunctionLiterals(descriptor, true).getFirst();
2225                        //FIRST_FUN_LABEL to prevent clashing with existing labels
2226                        return new NonLocalReturnInfo(typeMapper.mapReturnType(containingFunction), InlineCodegenUtil.FIRST_FUN_LABEL);
2227                    } else {
2228                        //local
2229                        return null;
2230                    }
2231                }
2232    
2233                PsiElement element = bindingContext.get(LABEL_TARGET, expression.getTargetLabel());
2234                if (element != DescriptorToSourceUtils.getSourceFromDescriptor(context.getContextDescriptor())) {
2235                    DeclarationDescriptor elementDescriptor = typeMapper.getBindingContext().get(DECLARATION_TO_DESCRIPTOR, element);
2236                    assert element != null : "Expression should be not null " + expression.getText();
2237                    assert elementDescriptor != null : "Descriptor should be not null: " + element.getText();
2238                    return new NonLocalReturnInfo(typeMapper.mapReturnType((CallableDescriptor) elementDescriptor), expression.getLabelName());
2239                }
2240            }
2241            return null;
2242        }
2243    
2244        public void returnExpression(KtExpression expr) {
2245            boolean isBlockedNamedFunction = expr instanceof KtBlockExpression && expr.getParent() instanceof KtNamedFunction;
2246    
2247            FunctionDescriptor originalSuspendLambdaDescriptor = getOriginalSuspendLambdaDescriptorFromContext(context);
2248            boolean isVoidCoroutineLambda =
2249                    originalSuspendLambdaDescriptor != null && TypeSignatureMappingKt.hasVoidReturnType(originalSuspendLambdaDescriptor);
2250    
2251            // If generating body for named block-bodied function or Unit-typed coroutine lambda, generate it as sequence of statements
2252            Type typeForExpression =
2253                    isBlockedNamedFunction || isVoidCoroutineLambda
2254                    ? Type.VOID_TYPE
2255                    : returnType;
2256    
2257            gen(expr, typeForExpression);
2258    
2259            // If it does not end with return we should return something
2260            // because if we don't there can be VerifyError (specific cases with Nothing-typed expressions)
2261            if (!endsWithReturn(expr)) {
2262                markLineNumber(expr, true);
2263    
2264                if (isLambdaVoidBody(expr, typeForExpression)) {
2265                    markLineNumber((KtFunctionLiteral) expr.getParent(), true);
2266                }
2267    
2268                if (typeForExpression.getSort() == Type.VOID) {
2269                    StackValue.none().put(returnType, v);
2270                }
2271    
2272                v.areturn(returnType);
2273            }
2274        }
2275    
2276        private static boolean endsWithReturn(KtElement bodyExpression) {
2277            if (bodyExpression instanceof KtBlockExpression) {
2278                List<KtExpression> statements = ((KtBlockExpression) bodyExpression).getStatements();
2279                return statements.size() > 0 && statements.get(statements.size() - 1) instanceof KtReturnExpression;
2280            }
2281    
2282            return bodyExpression instanceof KtReturnExpression;
2283        }
2284    
2285        private static boolean isLambdaVoidBody(KtElement bodyExpression, Type returnType) {
2286            if (bodyExpression instanceof KtBlockExpression) {
2287                PsiElement parent = bodyExpression.getParent();
2288                if (parent instanceof KtFunctionLiteral) {
2289                    return Type.VOID_TYPE.equals(returnType);
2290                }
2291            }
2292    
2293            return false;
2294        }
2295    
2296        @Override
2297        public StackValue visitSimpleNameExpression(@NotNull KtSimpleNameExpression expression, @NotNull StackValue receiver) {
2298            ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCall(expression, bindingContext);
2299    
2300            DeclarationDescriptor descriptor;
2301            if (resolvedCall == null) {
2302                descriptor = bindingContext.get(REFERENCE_TARGET, expression);
2303            }
2304            else {
2305                if (resolvedCall instanceof VariableAsFunctionResolvedCall) {
2306                    VariableAsFunctionResolvedCall call = (VariableAsFunctionResolvedCall) resolvedCall;
2307                    resolvedCall = call.getVariableCall();
2308                }
2309    
2310                descriptor = resolvedCall.getResultingDescriptor();
2311    
2312                //Check early if KCallableNameProperty is applicable to prevent closure generation
2313                StackValue intrinsicResult = applyIntrinsic(descriptor, KCallableNameProperty.class, resolvedCall, receiver);
2314                if (intrinsicResult != null) return intrinsicResult;
2315    
2316                receiver = StackValue.receiver(resolvedCall, receiver, this, null);
2317                if (descriptor instanceof FakeCallableDescriptorForObject) {
2318                    descriptor = ((FakeCallableDescriptorForObject) descriptor).getReferencedDescriptor();
2319                }
2320            }
2321    
2322            assert descriptor != null : "Couldn't find descriptor for '" + expression.getText() + "'";
2323            descriptor = descriptor.getOriginal();
2324    
2325            boolean isSyntheticField = descriptor instanceof SyntheticFieldDescriptor;
2326            if (isSyntheticField) {
2327                descriptor = ((SyntheticFieldDescriptor) descriptor).getPropertyDescriptor();
2328            }
2329    
2330            StackValue intrinsicResult = applyIntrinsic(descriptor, IntrinsicPropertyGetter.class, resolvedCall, receiver);
2331            if (intrinsicResult != null) return intrinsicResult;
2332    
2333            if (descriptor instanceof PropertyDescriptor) {
2334                PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor;
2335    
2336                Collection<ExpressionCodegenExtension> codegenExtensions = ExpressionCodegenExtension.Companion.getInstances(state.getProject());
2337                if (!codegenExtensions.isEmpty() && resolvedCall != null) {
2338                    ExpressionCodegenExtension.Context context = new ExpressionCodegenExtension.Context(typeMapper, v);
2339                    KotlinType returnType = propertyDescriptor.getReturnType();
2340                    for (ExpressionCodegenExtension extension : codegenExtensions) {
2341                        if (returnType != null) {
2342                            StackValue value = extension.applyProperty(receiver, resolvedCall, context);
2343                            if (value != null) return value;
2344                        }
2345                    }
2346                }
2347    
2348                boolean directToField = isSyntheticField && contextKind() != OwnerKind.DEFAULT_IMPLS;
2349                ClassDescriptor superCallTarget = resolvedCall == null ? null : getSuperCallTarget(resolvedCall.getCall());
2350    
2351                if (directToField) {
2352                    receiver = StackValue.receiverWithoutReceiverArgument(receiver);
2353                }
2354    
2355                return intermediateValueForProperty(propertyDescriptor, directToField, directToField, superCallTarget, false, receiver, resolvedCall);
2356            }
2357    
2358            if (descriptor instanceof TypeAliasDescriptor) {
2359                ClassDescriptor classDescriptor = ((TypeAliasDescriptor) descriptor).getClassDescriptor();
2360                if (classDescriptor == null) {
2361                    throw new IllegalStateException("Type alias " + descriptor + " static member refernece should be rejected by type checker, " +
2362                                                    "since there is no class corresponding to this type alias.");
2363                }
2364                descriptor = classDescriptor;
2365            }
2366    
2367            if (descriptor instanceof ClassDescriptor) {
2368                ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
2369                if (isObject(classDescriptor)) {
2370                    return StackValue.singleton(classDescriptor, typeMapper);
2371                }
2372                if (isEnumEntry(classDescriptor)) {
2373                    return StackValue.enumEntry(classDescriptor, typeMapper);
2374                }
2375                ClassDescriptor companionObjectDescriptor = classDescriptor.getCompanionObjectDescriptor();
2376                if (companionObjectDescriptor != null) {
2377                    return StackValue.singleton(companionObjectDescriptor, typeMapper);
2378                }
2379                return StackValue.none();
2380            }
2381    
2382            StackValue localOrCaptured = findLocalOrCapturedValue(descriptor);
2383            if (localOrCaptured != null) {
2384                return localOrCaptured;
2385            }
2386            throw new UnsupportedOperationException("don't know how to generate reference " + descriptor);
2387        }
2388    
2389        @Nullable
2390        private StackValue applyIntrinsic(
2391                DeclarationDescriptor descriptor,
2392                Class<? extends IntrinsicPropertyGetter> intrinsicType,
2393                ResolvedCall<?> resolvedCall,
2394                @NotNull StackValue receiver
2395        ) {
2396            if (descriptor instanceof CallableMemberDescriptor) {
2397                CallableMemberDescriptor memberDescriptor = DescriptorUtils.unwrapFakeOverride((CallableMemberDescriptor) descriptor);
2398                IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(memberDescriptor);
2399                if (intrinsicType.isInstance(intrinsic)) {
2400                    //TODO: intrinsic properties (see intermediateValueForProperty)
2401                    Type returnType = typeMapper.mapType(memberDescriptor);
2402                    return ((IntrinsicPropertyGetter) intrinsic).generate(resolvedCall, this, returnType, receiver);
2403                }
2404            }
2405            return null;
2406        }
2407    
2408        @Nullable
2409        private ClassDescriptor getSuperCallTarget(@NotNull Call call) {
2410            KtSuperExpression superExpression = CallResolverUtilKt.getSuperCallExpression(call);
2411            return superExpression == null ? null : getSuperCallLabelTarget(context, superExpression);
2412        }
2413    
2414        @Nullable
2415        public StackValue findLocalOrCapturedValue(@NotNull DeclarationDescriptor descriptor) {
2416            int index = lookupLocalIndex(descriptor);
2417            if (index >= 0) {
2418                return stackValueForLocal(descriptor, index);
2419            }
2420    
2421            return findCapturedValue(descriptor);
2422        }
2423    
2424        @Nullable
2425        public StackValue findCapturedValue(@NotNull DeclarationDescriptor descriptor) {
2426            if (context instanceof ConstructorContext) {
2427                return lookupCapturedValueInConstructorParameters(descriptor);
2428            }
2429    
2430            return lookupValuaAndLocalVariableMetadata(descriptor, StackValue.LOCAL_0, state, false, context, this);
2431        }
2432    
2433        @Nullable
2434        static StackValue lookupValuaAndLocalVariableMetadata(
2435                @NotNull DeclarationDescriptor descriptor,
2436                @NotNull StackValue prefix,
2437                @NotNull GenerationState state,
2438                boolean ignoreNoOuter,
2439                @NotNull CodegenContext context,
2440                @Nullable ExpressionCodegen codegen
2441        ) {
2442            StackValue value = context.lookupInContext(descriptor, prefix, state, ignoreNoOuter);
2443            if(!isDelegatedLocalVariable(descriptor) || value == null) {
2444                return value;
2445            }
2446    
2447    
2448            VariableDescriptor metadata = getDelegatedLocalVariableMetadata((VariableDescriptor) descriptor, state.getBindingContext());
2449            StackValue metadataValue = context.lookupInContext(metadata, prefix, state, ignoreNoOuter);
2450            assert metadataValue != null : "Metadata stack value should be non-null for local delegated property";
2451            //required for ImplementationBodyCodegen.lookupConstructorExpressionsInClosureIfPresent
2452            if (codegen == null) return null;
2453            return codegen.delegatedVariableValue(value, metadataValue, (VariableDescriptorWithAccessors) descriptor,
2454                                                  state.getTypeMapper());
2455        }
2456    
2457        @Nullable
2458        private StackValue lookupCapturedValueInConstructorParameters(@NotNull DeclarationDescriptor descriptor) {
2459            StackValue parentResult = context.lookupInContext(descriptor, StackValue.LOCAL_0, state, false);
2460            if (context.closure == null || parentResult == null) return parentResult;
2461    
2462            int parameterOffsetInConstructor = context.closure.getCapturedParameterOffsetInConstructor(descriptor);
2463            // when captured parameter is singleton
2464            // see compiler/testData/codegen/box/objects/objectInLocalAnonymousObject.kt (fun local() captured in A)
2465            if (parameterOffsetInConstructor == -1) return parentResult;
2466    
2467            assert parentResult instanceof StackValue.Field || parentResult instanceof StackValue.FieldForSharedVar
2468                    : "Part of closure should be either Field or FieldForSharedVar";
2469    
2470            if (parentResult instanceof StackValue.FieldForSharedVar) {
2471                return StackValue.shared(parameterOffsetInConstructor, parentResult.type);
2472            }
2473    
2474            return adjustVariableValue(StackValue.local(parameterOffsetInConstructor, parentResult.type), descriptor);
2475        }
2476    
2477        private StackValue stackValueForLocal(DeclarationDescriptor descriptor, int index) {
2478            if (descriptor instanceof VariableDescriptor) {
2479                VariableDescriptor variableDescriptor = (VariableDescriptor) descriptor;
2480    
2481                Type sharedVarType = typeMapper.getSharedVarType(descriptor);
2482                Type varType = getVariableTypeNoSharing(variableDescriptor);
2483                if (sharedVarType != null) {
2484                    return StackValue.shared(index, varType);
2485                }
2486                else {
2487                    return adjustVariableValue(StackValue.local(index, varType), variableDescriptor);
2488                }
2489            }
2490            else {
2491                return StackValue.local(index, OBJECT_TYPE);
2492            }
2493        }
2494    
2495        @Override
2496        public boolean lookupLocal(DeclarationDescriptor descriptor) {
2497            return lookupLocalIndex(descriptor) != -1;
2498        }
2499    
2500        public int lookupLocalIndex(DeclarationDescriptor descriptor) {
2501            return myFrameMap.getIndex(getParameterSynonymOrThis(descriptor));
2502        }
2503    
2504        private DeclarationDescriptor getParameterSynonymOrThis(DeclarationDescriptor descriptor) {
2505            if (!(descriptor instanceof ValueParameterDescriptor)) return descriptor;
2506    
2507            DeclarationDescriptor synonym = bindingContext.get(CodegenBinding.PARAMETER_SYNONYM, (ValueParameterDescriptor) descriptor);
2508            return synonym != null ? synonym : descriptor;
2509        }
2510    
2511        @NotNull
2512        public StackValue.Property intermediateValueForProperty(
2513                @NotNull PropertyDescriptor propertyDescriptor,
2514                boolean forceField,
2515                @Nullable ClassDescriptor superCallTarget,
2516                @NotNull StackValue receiver
2517        ) {
2518            return intermediateValueForProperty(propertyDescriptor, forceField, false, superCallTarget, false, receiver, null);
2519        }
2520    
2521        private CodegenContext getBackingFieldContext(
2522                @NotNull FieldAccessorKind accessorKind,
2523                @NotNull DeclarationDescriptor containingDeclaration
2524        ) {
2525            switch (accessorKind) {
2526                case NORMAL: return context.getParentContext();
2527                // For companion object property, backing field lives in object containing class
2528                // Otherwise, it lives in its containing declaration
2529                case IN_CLASS_COMPANION: return context.findParentContextWithDescriptor(containingDeclaration.getContainingDeclaration());
2530                case FIELD_FROM_LOCAL: return context.findParentContextWithDescriptor(containingDeclaration);
2531                default: throw new IllegalStateException();
2532            }
2533        }
2534    
2535        public StackValue.Property intermediateValueForProperty(
2536                @NotNull PropertyDescriptor propertyDescriptor,
2537                boolean forceField,
2538                boolean syntheticBackingField,
2539                @Nullable ClassDescriptor superCallTarget,
2540                boolean skipAccessorsForPrivateFieldInOuterClass,
2541                @NotNull StackValue receiver,
2542                @Nullable ResolvedCall resolvedCall
2543        ) {
2544            if (propertyDescriptor instanceof SyntheticJavaPropertyDescriptor) {
2545                return intermediateValueForSyntheticExtensionProperty((SyntheticJavaPropertyDescriptor) propertyDescriptor, receiver);
2546            }
2547    
2548            DeclarationDescriptor containingDeclaration = propertyDescriptor.getContainingDeclaration();
2549    
2550            FieldAccessorKind fieldAccessorKind = FieldAccessorKind.NORMAL;
2551            boolean isBackingFieldInClassCompanion = JvmAbi.isPropertyWithBackingFieldInOuterClass(propertyDescriptor);
2552            if (isBackingFieldInClassCompanion && (forceField || propertyDescriptor.isConst() && Visibilities.isPrivate(propertyDescriptor.getVisibility()))) {
2553                fieldAccessorKind = FieldAccessorKind.IN_CLASS_COMPANION;
2554            }
2555            else if (syntheticBackingField && context.getFirstCrossInlineOrNonInlineContext().getParentContext().getContextDescriptor() != containingDeclaration) {
2556                fieldAccessorKind = FieldAccessorKind.FIELD_FROM_LOCAL;
2557            }
2558            boolean isStaticBackingField = DescriptorUtils.isStaticDeclaration(propertyDescriptor) ||
2559                                           AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor);
2560            boolean isSuper = superCallTarget != null;
2561            boolean isExtensionProperty = propertyDescriptor.getExtensionReceiverParameter() != null;
2562    
2563            KotlinType delegateType = JvmCodegenUtil.getPropertyDelegateType(propertyDescriptor, bindingContext);
2564            boolean isDelegatedProperty = delegateType != null;
2565    
2566            CallableMethod callableGetter = null;
2567            CallableMethod callableSetter = null;
2568    
2569            CodegenContext backingFieldContext = getBackingFieldContext(fieldAccessorKind, containingDeclaration);
2570            DeclarationDescriptor ownerDescriptor = containingDeclaration;
2571            boolean skipPropertyAccessors;
2572    
2573            PropertyDescriptor originalPropertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
2574    
2575            if (fieldAccessorKind != FieldAccessorKind.NORMAL) {
2576                int flags = AsmUtil.getVisibilityForBackingField(propertyDescriptor, isDelegatedProperty);
2577                boolean isInlinedConst = propertyDescriptor.isConst() && state.getShouldInlineConstVals();
2578                skipPropertyAccessors = isInlinedConst || (flags & ACC_PRIVATE) == 0 || skipAccessorsForPrivateFieldInOuterClass;
2579    
2580                if (!skipPropertyAccessors) {
2581                    //noinspection ConstantConditions
2582                    propertyDescriptor = (PropertyDescriptor) backingFieldContext.getAccessor(
2583                            propertyDescriptor, fieldAccessorKind, delegateType, superCallTarget
2584                    );
2585                    assert propertyDescriptor instanceof AccessorForPropertyBackingField :
2586                            "Unexpected accessor descriptor: " + propertyDescriptor;
2587                    ownerDescriptor = propertyDescriptor;
2588                }
2589            }
2590            else {
2591                if (!isBackingFieldInClassCompanion) {
2592                    ownerDescriptor = propertyDescriptor;
2593                }
2594                skipPropertyAccessors = forceField;
2595            }
2596    
2597            if (!skipPropertyAccessors) {
2598                if (!couldUseDirectAccessToProperty(propertyDescriptor, true, isDelegatedProperty, context, state.getShouldInlineConstVals())) {
2599                    propertyDescriptor = context.getAccessorForSuperCallIfNeeded(propertyDescriptor, superCallTarget, state);
2600    
2601                    propertyDescriptor = context.accessibleDescriptor(propertyDescriptor, superCallTarget);
2602    
2603                    PropertyGetterDescriptor getter = propertyDescriptor.getGetter();
2604                    if (getter != null && !isConstOrHasJvmFieldAnnotation(propertyDescriptor)) {
2605                        callableGetter = typeMapper.mapToCallableMethod(getter, isSuper);
2606                    }
2607                }
2608    
2609                if (propertyDescriptor.isVar()) {
2610                    PropertySetterDescriptor setter = propertyDescriptor.getSetter();
2611                    if (setter != null &&
2612                        !couldUseDirectAccessToProperty(propertyDescriptor, false, isDelegatedProperty, context, state.getShouldInlineConstVals()) &&
2613                        !isConstOrHasJvmFieldAnnotation(propertyDescriptor)) {
2614                        callableSetter = typeMapper.mapToCallableMethod(setter, isSuper);
2615                    }
2616                }
2617            }
2618    
2619            if (!isStaticBackingField) {
2620                propertyDescriptor = DescriptorUtils.unwrapFakeOverride(propertyDescriptor);
2621            }
2622    
2623            Type backingFieldOwner = typeMapper.mapOwner(ownerDescriptor);
2624    
2625            String fieldName;
2626            if (isExtensionProperty && !isDelegatedProperty) {
2627                fieldName = null;
2628            }
2629            else if (originalPropertyDescriptor.getContainingDeclaration() == backingFieldContext.getContextDescriptor()) {
2630                assert backingFieldContext instanceof FieldOwnerContext
2631                        : "Actual context is " + backingFieldContext + " but should be instance of FieldOwnerContext";
2632                fieldName = ((FieldOwnerContext) backingFieldContext).getFieldName(propertyDescriptor, isDelegatedProperty);
2633            }
2634            else {
2635                fieldName = KotlinTypeMapper.mapDefaultFieldName(propertyDescriptor, isDelegatedProperty);
2636            }
2637    
2638            return StackValue.property(propertyDescriptor, backingFieldOwner,
2639                                       typeMapper.mapType(
2640                                               isDelegatedProperty && forceField ? delegateType : propertyDescriptor.getOriginal().getType()),
2641                                       isStaticBackingField, fieldName, callableGetter, callableSetter, receiver, this, resolvedCall);
2642        }
2643    
2644        @NotNull
2645        private StackValue.Property intermediateValueForSyntheticExtensionProperty(
2646                @NotNull SyntheticJavaPropertyDescriptor propertyDescriptor,
2647                @NotNull StackValue receiver
2648        ) {
2649            Type type = typeMapper.mapType(propertyDescriptor.getOriginal().getType());
2650            CallableMethod callableGetter =
2651                    typeMapper.mapToCallableMethod(context.accessibleDescriptor(propertyDescriptor.getGetMethod(), null), false);
2652            FunctionDescriptor setMethod = propertyDescriptor.getSetMethod();
2653            CallableMethod callableSetter =
2654                    setMethod != null ? typeMapper.mapToCallableMethod(context.accessibleDescriptor(setMethod, null), false) : null;
2655            return StackValue.property(propertyDescriptor, null, type, false, null, callableGetter, callableSetter, receiver, this, null);
2656        }
2657    
2658        @Override
2659        public StackValue visitCallExpression(@NotNull KtCallExpression expression, StackValue receiver) {
2660            ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
2661            FunctionDescriptor descriptor = accessibleFunctionDescriptor(resolvedCall);
2662    
2663            if (descriptor instanceof ConstructorDescriptor) {
2664                return generateNewCall(expression, resolvedCall);
2665            }
2666    
2667            if (descriptor.getOriginal() instanceof SamConstructorDescriptor) {
2668                KtExpression argumentExpression = bindingContext.get(SAM_CONSTRUCTOR_TO_ARGUMENT, expression);
2669                assert argumentExpression != null : "Argument expression is not saved for a SAM constructor: " + descriptor;
2670                return genSamInterfaceValue(argumentExpression, this);
2671            }
2672    
2673            return invokeFunction(resolvedCall, receiver);
2674        }
2675    
2676        @Nullable
2677        private StackValue genSamInterfaceValue(
2678                @NotNull KtExpression probablyParenthesizedExpression,
2679                @NotNull final KtVisitor<StackValue, StackValue> visitor
2680        ) {
2681            final KtExpression expression = KtPsiUtil.deparenthesize(probablyParenthesizedExpression);
2682            final SamType samType = bindingContext.get(SAM_VALUE, probablyParenthesizedExpression);
2683            if (samType == null || expression == null) return null;
2684    
2685            if (expression instanceof KtLambdaExpression) {
2686                return genClosure(((KtLambdaExpression) expression).getFunctionLiteral(), samType);
2687            }
2688    
2689            if (expression instanceof KtNamedFunction) {
2690                return genClosure((KtNamedFunction) expression, samType);
2691            }
2692    
2693            final Type asmType =
2694                    state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingKtFile(), this);
2695    
2696            return StackValue.operation(asmType, new Function1<InstructionAdapter, Unit>() {
2697                @Override
2698                public Unit invoke(InstructionAdapter v) {
2699                    v.anew(asmType);
2700                    v.dup();
2701    
2702                    Type functionType = typeMapper.mapType(samType.getKotlinFunctionType());
2703                    expression.accept(visitor, StackValue.none()).put(functionType, v);
2704    
2705                    Label ifNonNull = new Label();
2706                    Label afterAll = new Label();
2707    
2708                    v.dup();
2709                    v.ifnonnull(ifNonNull);
2710    
2711                    // if null: pop function value and wrapper objects, put null
2712                    v.pop();
2713                    v.pop2();
2714                    v.aconst(null);
2715                    v.goTo(afterAll);
2716    
2717                    v.mark(ifNonNull);
2718                    v.invokespecial(asmType.getInternalName(), "<init>", Type.getMethodDescriptor(Type.VOID_TYPE, functionType), false);
2719    
2720                    v.mark(afterAll);
2721                    return null;
2722                }
2723            });
2724        }
2725    
2726        @NotNull
2727        protected FunctionDescriptor accessibleFunctionDescriptor(@NotNull ResolvedCall<?> resolvedCall) {
2728            FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
2729            if (descriptor instanceof TypeAliasConstructorDescriptor) {
2730                descriptor = ((TypeAliasConstructorDescriptor) descriptor).getUnderlyingConstructorDescriptor();
2731            }
2732            FunctionDescriptor originalIfSamAdapter = SamCodegenUtil.getOriginalIfSamAdapter(descriptor);
2733            if (originalIfSamAdapter != null) {
2734                descriptor = originalIfSamAdapter;
2735            }
2736    
2737            descriptor = CoroutineCodegenUtilKt.unwrapInitialDescriptorForSuspendFunction(descriptor);
2738    
2739            // $default method is not private, so you need no accessor to call it
2740            return CallUtilKt.usesDefaultArguments(resolvedCall)
2741                   ? descriptor
2742                   : context.accessibleDescriptor(descriptor, getSuperCallTarget(resolvedCall.getCall()));
2743        }
2744    
2745        @NotNull
2746        public StackValue invokeFunction(@NotNull ResolvedCall<?> resolvedCall, @NotNull StackValue receiver) {
2747            return invokeFunction(resolvedCall.getCall(), resolvedCall, receiver);
2748        }
2749    
2750        @NotNull
2751        public StackValue invokeFunction(@NotNull Call call, @NotNull ResolvedCall<?> resolvedCall, @NotNull StackValue receiver) {
2752            ResolvedCallWithRealDescriptor callWithRealDescriptor =
2753                    CoroutineCodegenUtilKt.replaceSuspensionFunctionWithRealDescriptor(
2754                            resolvedCall, state.getProject(), state.getBindingContext()
2755                    );
2756            if (callWithRealDescriptor != null) {
2757                StackValue coroutineInstanceValueForSuspensionPoint = getCoroutineInstanceValueForSuspensionPoint(resolvedCall);
2758                StackValue coroutineInstanceValue =
2759                        coroutineInstanceValueForSuspensionPoint != null
2760                        ? coroutineInstanceValueForSuspensionPoint
2761                        : getContinuationParameterFromEnclosingSuspendFunction(resolvedCall);
2762                tempVariables.put(callWithRealDescriptor.getFakeContinuationExpression(), coroutineInstanceValue);
2763    
2764                return invokeFunction(callWithRealDescriptor.getResolvedCall(), receiver);
2765            }
2766            FunctionDescriptor fd = accessibleFunctionDescriptor(resolvedCall);
2767            ClassDescriptor superCallTarget = getSuperCallTarget(call);
2768    
2769            fd = context.getAccessorForSuperCallIfNeeded(fd, superCallTarget, state);
2770    
2771            Collection<ExpressionCodegenExtension> codegenExtensions = ExpressionCodegenExtension.Companion.getInstances(state.getProject());
2772            if (!codegenExtensions.isEmpty()) {
2773                ExpressionCodegenExtension.Context context = new ExpressionCodegenExtension.Context(typeMapper, v);
2774                for (ExpressionCodegenExtension extension : codegenExtensions) {
2775                    StackValue stackValue = extension.applyFunction(receiver, resolvedCall, context);
2776                    if (stackValue != null) return stackValue;
2777                }
2778            }
2779    
2780            Callable callable = resolveToCallable(fd, superCallTarget != null, resolvedCall);
2781    
2782            return callable.invokeMethodWithArguments(resolvedCall, receiver, this);
2783        }
2784    
2785        private StackValue getContinuationParameterFromEnclosingSuspendFunction(@NotNull ResolvedCall<?> resolvedCall) {
2786            FunctionDescriptor enclosingSuspendFunction =
2787                    bindingContext.get(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.getCall());
2788    
2789            assert enclosingSuspendFunction != null
2790                    : "Suspend functions may be called either as suspension points or from another suspend function";
2791    
2792            FunctionDescriptor enclosingSuspendFunctionJvmView =
2793                    bindingContext.get(CodegenBinding.SUSPEND_FUNCTION_TO_JVM_VIEW, enclosingSuspendFunction);
2794    
2795            assert enclosingSuspendFunctionJvmView != null : "No JVM view function found for " + enclosingSuspendFunction;
2796    
2797            ValueParameterDescriptor continuationParameter =
2798                    enclosingSuspendFunctionJvmView.getValueParameters()
2799                            .get(enclosingSuspendFunctionJvmView.getValueParameters().size() - 1);
2800    
2801            return findLocalOrCapturedValue(continuationParameter);
2802        }
2803    
2804        @Nullable
2805        // Find the first parent of the current context which corresponds to a subclass of a given class
2806        public static CodegenContext getParentContextSubclassOf(ClassDescriptor descriptor, CodegenContext context) {
2807            CodegenContext c = context;
2808            while (c != null) {
2809                if (c instanceof ClassContext && DescriptorUtils.isSubclass(c.getThisDescriptor(), descriptor)) {
2810                    return c;
2811                }
2812                c = c.getParentContext();
2813            }
2814            return null;
2815        }
2816    
2817        @NotNull
2818        Callable resolveToCallable(@NotNull FunctionDescriptor fd, boolean superCall, @NotNull ResolvedCall resolvedCall) {
2819            IntrinsicMethod intrinsic = state.getIntrinsics().getIntrinsic(fd);
2820            if (intrinsic != null) {
2821                return intrinsic.toCallable(fd, superCall, resolvedCall, this);
2822            }
2823    
2824            return resolveToCallableMethod(fd, superCall);
2825        }
2826    
2827        @NotNull
2828        private CallableMethod resolveToCallableMethod(@NotNull FunctionDescriptor fd, boolean superCall) {
2829            return typeMapper.mapToCallableMethod(SamCodegenUtil.resolveSamAdapter(fd), superCall);
2830        }
2831    
2832        public void invokeMethodWithArguments(
2833                @NotNull Callable callableMethod,
2834                @NotNull ResolvedCall<?> resolvedCall,
2835                @NotNull StackValue receiver
2836        ) {
2837            CallGenerator callGenerator = getOrCreateCallGenerator(resolvedCall);
2838            CallableDescriptor descriptor = resolvedCall.getResultingDescriptor();
2839    
2840            assert callGenerator == defaultCallGenerator || !tailRecursionCodegen.isTailRecursion(resolvedCall) :
2841                    "Tail recursive method can't be inlined: " + descriptor;
2842    
2843            ArgumentGenerator argumentGenerator = new CallBasedArgumentGenerator(this, callGenerator, descriptor.getValueParameters(),
2844                                                                                 callableMethod.getValueParameterTypes());
2845    
2846            invokeMethodWithArguments(callableMethod, resolvedCall, receiver, callGenerator, argumentGenerator);
2847        }
2848    
2849        public void invokeMethodWithArguments(
2850                @NotNull Callable callableMethod,
2851                @NotNull ResolvedCall<?> resolvedCall,
2852                @NotNull StackValue receiver,
2853                @NotNull CallGenerator callGenerator,
2854                @NotNull ArgumentGenerator argumentGenerator
2855        ) {
2856            boolean isSuspensionPoint = CoroutineCodegenUtilKt.isSuspensionPointInStateMachine(resolvedCall, bindingContext);
2857            boolean isConstructor = resolvedCall.getResultingDescriptor() instanceof ConstructorDescriptor;
2858            putReceiverAndInlineMarkerIfNeeded(callableMethod, resolvedCall, receiver, isSuspensionPoint, isConstructor);
2859    
2860            callGenerator.processAndPutHiddenParameters(false);
2861    
2862            List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
2863            assert valueArguments != null : "Failed to arrange value arguments by index: " + resolvedCall.getResultingDescriptor();
2864    
2865            DefaultCallArgs defaultArgs =
2866                    argumentGenerator.generate(valueArguments, new ArrayList<ResolvedValueArgument>(resolvedCall.getValueArguments().values()));
2867    
2868            if (tailRecursionCodegen.isTailRecursion(resolvedCall)) {
2869                tailRecursionCodegen.generateTailRecursion(resolvedCall);
2870                return;
2871            }
2872    
2873            boolean defaultMaskWasGenerated = defaultArgs.generateOnStackIfNeeded(callGenerator, isConstructor);
2874    
2875            // Extra constructor marker argument
2876            if (callableMethod instanceof CallableMethod) {
2877                List<JvmMethodParameterSignature> callableParameters = ((CallableMethod) callableMethod).getValueParameters();
2878                for (JvmMethodParameterSignature parameter: callableParameters) {
2879                    if (parameter.getKind() == JvmMethodParameterKind.CONSTRUCTOR_MARKER) {
2880                        callGenerator.putValueIfNeeded(parameter.getAsmType(), StackValue.constant(null, parameter.getAsmType()));
2881                    }
2882                }
2883            }
2884    
2885            if (isSuspensionPoint) {
2886                v.invokestatic(
2887                        CoroutineCodegenUtilKt.COROUTINE_MARKER_OWNER,
2888                        CoroutineCodegenUtilKt.BEFORE_SUSPENSION_POINT_MARKER_NAME,
2889                        "()V", false
2890                );
2891            }
2892    
2893            callGenerator.genCall(callableMethod, resolvedCall, defaultMaskWasGenerated, this);
2894    
2895            if (isSuspensionPoint) {
2896                v.invokestatic(
2897                        CoroutineCodegenUtilKt.COROUTINE_MARKER_OWNER,
2898                        CoroutineCodegenUtilKt.AFTER_SUSPENSION_POINT_MARKER_NAME, "()V", false);
2899                addInlineMarker(v, false);
2900            }
2901    
2902            KotlinType returnType = resolvedCall.getResultingDescriptor().getReturnType();
2903            if (returnType != null && KotlinBuiltIns.isNothing(returnType)) {
2904                v.aconst(null);
2905                v.athrow();
2906            }
2907        }
2908    
2909        private void putReceiverAndInlineMarkerIfNeeded(
2910                @NotNull Callable callableMethod,
2911                @NotNull ResolvedCall<?> resolvedCall,
2912                @NotNull StackValue receiver,
2913                boolean isSuspensionPoint,
2914                boolean isConstructor
2915        ) {
2916            boolean isSafeCallOrOnStack = receiver instanceof StackValue.SafeCall || receiver instanceof StackValue.OnStack;
2917    
2918            if (isSuspensionPoint && !isSafeCallOrOnStack) {
2919                // Inline markers are used to spill the stack before coroutine suspension
2920                addInlineMarker(v, true);
2921            }
2922    
2923            if (!isConstructor) { // otherwise already
2924                receiver = StackValue.receiver(resolvedCall, receiver, this, callableMethod);
2925                receiver.put(receiver.type, v);
2926    
2927                // In regular cases we add an inline marker just before receiver is loaded (to spill the stack before a suspension)
2928                // But in case of safe call things we get the following bytecode:
2929    
2930                // ---- inlineMarkerBefore()
2931                // LOAD $receiver
2932                // IFNULL L1
2933                // ---- load the rest of the arguments
2934                // INVOKEVIRTUAL suspendCall()
2935                // ---- inlineMarkerBefore()
2936                // GOTO L2
2937                // L1
2938                // ACONST_NULL
2939                // L2
2940                // ...
2941                //
2942                // The problem is that the stack before the call is not restored in case of null receiver.
2943                // The solution is to spill stack just after receiver is loaded (after IFNULL) in case of safe call.
2944                // But the problem is that we should leave the receiver itself on the stack, so we store it in a temporary variable.
2945                if (isSuspensionPoint && isSafeCallOrOnStack) {
2946                    boolean bothReceivers =
2947                            receiver instanceof StackValue.CallReceiver
2948                            && ((StackValue.CallReceiver) receiver).getDispatchReceiver().type.getSort() != Type.VOID
2949                            && ((StackValue.CallReceiver) receiver).getExtensionReceiver().type.getSort() != Type.VOID;
2950                    Type firstReceiverType =
2951                            bothReceivers
2952                            ? ((StackValue.CallReceiver) receiver).getDispatchReceiver().type
2953                            : receiver.type;
2954    
2955                    Type secondReceiverType = bothReceivers ? receiver.type : null;
2956    
2957                    int tmpVarForFirstReceiver = myFrameMap.enterTemp(firstReceiverType);
2958                    int tmpVarForSecondReceiver = -1;
2959    
2960                    if (secondReceiverType != null) {
2961                        tmpVarForSecondReceiver = myFrameMap.enterTemp(secondReceiverType);
2962                        v.store(tmpVarForSecondReceiver, secondReceiverType);
2963                    }
2964                    v.store(tmpVarForFirstReceiver, firstReceiverType);
2965    
2966                    addInlineMarker(v, true);
2967    
2968                    v.load(tmpVarForFirstReceiver, firstReceiverType);
2969                    if (secondReceiverType != null) {
2970                        v.load(tmpVarForSecondReceiver, secondReceiverType);
2971                        myFrameMap.leaveTemp(secondReceiverType);
2972                    }
2973    
2974                    myFrameMap.leaveTemp(firstReceiverType);
2975                }
2976    
2977                callableMethod.afterReceiverGeneration(v);
2978            }
2979        }
2980    
2981        @NotNull
2982        private CallGenerator getOrCreateCallGenerator(
2983                @NotNull CallableDescriptor descriptor,
2984                @Nullable KtElement callElement,
2985                @Nullable TypeParameterMappings typeParameterMappings,
2986                boolean isDefaultCompilation
2987        ) {
2988            if (callElement == null) return defaultCallGenerator;
2989    
2990            // We should inline callable containing reified type parameters even if inline is disabled
2991            // because they may contain something to reify and straight call will probably fail at runtime
2992            boolean isInline = (!state.isInlineDisabled() || InlineUtil.containsReifiedTypeParameters(descriptor)) &&
2993                               (InlineUtil.isInline(descriptor) || InlineUtil.isArrayConstructorWithLambda(descriptor));
2994    
2995            if (!isInline) return defaultCallGenerator;
2996    
2997            FunctionDescriptor original =
2998                    unwrapInitialSignatureDescriptor(DescriptorUtils.unwrapFakeOverride((FunctionDescriptor) descriptor.getOriginal()));
2999            if (isDefaultCompilation) {
3000                return new InlineCodegenForDefaultBody(original, this, state);
3001            }
3002            else {
3003                return new InlineCodegen(this, state, original, callElement, typeParameterMappings);
3004            }
3005        }
3006    
3007        @NotNull
3008        private static FunctionDescriptor unwrapInitialSignatureDescriptor(@NotNull FunctionDescriptor function) {
3009            if (function.getInitialSignatureDescriptor() != null) return function.getInitialSignatureDescriptor();
3010            return function;
3011        }
3012    
3013        @NotNull
3014        protected CallGenerator getOrCreateCallGeneratorForDefaultImplBody(@NotNull FunctionDescriptor descriptor, @Nullable KtNamedFunction function) {
3015            return getOrCreateCallGenerator(descriptor, function, null, true);
3016        }
3017    
3018        CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall) {
3019            return getOrCreateCallGenerator(resolvedCall, resolvedCall.getResultingDescriptor());
3020        }
3021    
3022        @NotNull
3023        CallGenerator getOrCreateCallGenerator(@NotNull ResolvedCall<?> resolvedCall, @NotNull CallableDescriptor descriptor) {
3024            Map<TypeParameterDescriptor, KotlinType> typeArguments = resolvedCall.getTypeArguments();
3025            TypeParameterMappings mappings = new TypeParameterMappings();
3026            for (Map.Entry<TypeParameterDescriptor, KotlinType> entry : typeArguments.entrySet()) {
3027                TypeParameterDescriptor key = entry.getKey();
3028                KotlinType type = entry.getValue();
3029    
3030                boolean isReified = key.isReified() || InlineUtil.isArrayConstructorWithLambda(resolvedCall.getResultingDescriptor());
3031    
3032                Pair<TypeParameterDescriptor, ReificationArgument> typeParameterAndReificationArgument = extractReificationArgument(type);
3033                if (typeParameterAndReificationArgument == null) {
3034                    KotlinType approximatedType = CapturedTypeApproximationKt.approximateCapturedTypes(entry.getValue()).getUpper();
3035                    // type is not generic
3036                    JvmSignatureWriter signatureWriter = new BothSignatureWriter(BothSignatureWriter.Mode.TYPE);
3037                    Type asmType = typeMapper.mapTypeParameter(approximatedType, signatureWriter);
3038    
3039                    mappings.addParameterMappingToType(
3040                            key.getName().getIdentifier(), approximatedType, asmType, signatureWriter.toString(), isReified
3041                    );
3042                }
3043                else {
3044                    mappings.addParameterMappingForFurtherReification(
3045                            key.getName().getIdentifier(), type, typeParameterAndReificationArgument.getSecond(), isReified
3046                    );
3047                }
3048            }
3049            return getOrCreateCallGenerator(descriptor, resolvedCall.getCall().getCallElement(), mappings, false);
3050        }
3051    
3052    
3053        @Nullable
3054        private static Pair<TypeParameterDescriptor, ReificationArgument> extractReificationArgument(@NotNull KotlinType type) {
3055            int arrayDepth = 0;
3056            boolean isNullable = type.isMarkedNullable();
3057            while (KotlinBuiltIns.isArray(type)) {
3058                arrayDepth++;
3059                type = type.getArguments().get(0).getType();
3060            }
3061    
3062            TypeParameterDescriptor parameterDescriptor = TypeUtils.getTypeParameterDescriptorOrNull(type);
3063            if (parameterDescriptor == null) return null;
3064    
3065            return new Pair<TypeParameterDescriptor, ReificationArgument>(
3066                    parameterDescriptor,
3067                    new ReificationArgument(parameterDescriptor.getName().asString(), isNullable, arrayDepth));
3068        }
3069    
3070        @NotNull
3071        public StackValue generateReceiverValue(@Nullable ReceiverValue receiverValue, boolean isSuper) {
3072            if (receiverValue instanceof ImplicitClassReceiver) {
3073                ClassDescriptor receiverDescriptor = ((ImplicitClassReceiver) receiverValue).getDeclarationDescriptor();
3074                if (DescriptorUtils.isCompanionObject(receiverDescriptor)) {
3075                    CallableMemberDescriptor contextDescriptor = context.getContextDescriptor();
3076                    if (contextDescriptor instanceof FunctionDescriptor && receiverDescriptor == contextDescriptor.getContainingDeclaration()) {
3077                        return StackValue.LOCAL_0;
3078                    }
3079                    else {
3080                        return StackValue.singleton(receiverDescriptor, typeMapper);
3081                    }
3082                }
3083                else if (receiverDescriptor instanceof ScriptDescriptor) {
3084                    return generateScriptReceiver
3085                            ((ScriptDescriptor) receiverDescriptor);
3086                }
3087                else {
3088                    return StackValue.thisOrOuter(this, receiverDescriptor, isSuper,
3089                                                  receiverValue instanceof CastImplicitClassReceiver || isEnumEntry(receiverDescriptor));
3090                }
3091            }
3092            else if (receiverValue instanceof ExtensionReceiver) {
3093                return generateExtensionReceiver(((ExtensionReceiver) receiverValue).getDeclarationDescriptor());
3094            }
3095            else if (receiverValue instanceof ExpressionReceiver) {
3096                return gen(((ExpressionReceiver) receiverValue).getExpression());
3097            }
3098            else {
3099                throw new UnsupportedOperationException("Unsupported receiver value: " + receiverValue);
3100            }
3101        }
3102    
3103        @NotNull
3104        private StackValue generateExtensionReceiver(@NotNull CallableDescriptor descriptor) {
3105            if (myFrameMap.getIndex(descriptor.getExtensionReceiverParameter()) != -1) {
3106                return StackValue.local(
3107                        myFrameMap.getIndex(descriptor.getExtensionReceiverParameter()),
3108                        typeMapper.mapType(descriptor.getExtensionReceiverParameter())
3109                );
3110            }
3111    
3112            return context.generateReceiver(descriptor, state, false);
3113        }
3114    
3115        @NotNull
3116        private StackValue generateScriptReceiver(@NotNull ScriptDescriptor receiver) {
3117            CodegenContext cur = context;
3118            StackValue result = StackValue.LOCAL_0;
3119            boolean inStartConstructorContext = cur instanceof ConstructorContext;
3120            while (cur != null) {
3121                if (!inStartConstructorContext) {
3122                    cur = getNotNullParentContextForMethod(cur);
3123                }
3124    
3125                if (cur instanceof ScriptContext) {
3126                    ScriptContext scriptContext = (ScriptContext) cur;
3127    
3128                    if (scriptContext.getScriptDescriptor() == receiver) {
3129                        //TODO lazy
3130                        return result;
3131                    }
3132                    Type currentScriptType = typeMapper.mapType(scriptContext.getScriptDescriptor());
3133                    Type classType = typeMapper.mapType(receiver);
3134                    String fieldName = scriptContext.getScriptFieldName(receiver);
3135                    return StackValue.field(classType, currentScriptType, fieldName, false, result, receiver);
3136                }
3137    
3138                result = cur.getOuterExpression(result, false);
3139    
3140                if (inStartConstructorContext) {
3141                    cur = getNotNullParentContextForMethod(cur);
3142                    inStartConstructorContext = false;
3143                }
3144    
3145                cur = cur.getParentContext();
3146            }
3147    
3148            throw new UnsupportedOperationException();
3149        }
3150    
3151        @NotNull
3152        public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper) {
3153            return generateThisOrOuter(calleeContainingClass, isSuper, false);
3154        }
3155    
3156        @NotNull
3157        public StackValue generateThisOrOuter(@NotNull ClassDescriptor calleeContainingClass, boolean isSuper, boolean forceOuter) {
3158            boolean isSingleton = calleeContainingClass.getKind().isSingleton();
3159            if (isSingleton) {
3160                if (calleeContainingClass.equals(context.getThisDescriptor()) &&
3161                    !CodegenUtilKt.isJvmStaticInObjectOrClass(context.getContextDescriptor())) {
3162                    return StackValue.local(0, typeMapper.mapType(calleeContainingClass));
3163                }
3164                else if (isEnumEntry(calleeContainingClass)) {
3165                    return StackValue.enumEntry(calleeContainingClass, typeMapper);
3166                }
3167                else {
3168                    return StackValue.singleton(calleeContainingClass, typeMapper);
3169                }
3170            }
3171    
3172            CodegenContext cur = context;
3173            Type type = asmType(calleeContainingClass.getDefaultType());
3174            StackValue result = StackValue.local(0, type);
3175            boolean inStartConstructorContext = cur instanceof ConstructorContext;
3176            while (cur != null) {
3177                ClassDescriptor thisDescriptor = cur.getThisDescriptor();
3178    
3179                if (!isSuper && thisDescriptor == calleeContainingClass) {
3180                    return result;
3181                }
3182    
3183                if (!forceOuter && isSuper && DescriptorUtils.isSubclass(thisDescriptor, calleeContainingClass)) {
3184                    return castToRequiredTypeOfInterfaceIfNeeded(result, thisDescriptor, calleeContainingClass);
3185                }
3186    
3187                forceOuter = false;
3188    
3189                //for constructor super call we should access to outer instance through parameter in locals, in other cases through field for captured outer
3190                if (inStartConstructorContext) {
3191                    result = cur.getOuterExpression(result, false);
3192                    cur = getNotNullParentContextForMethod(cur);
3193                    inStartConstructorContext = false;
3194                }
3195                else {
3196                    cur = getNotNullParentContextForMethod(cur);
3197                    result = cur.getOuterExpression(result, false);
3198                }
3199    
3200                cur = cur.getParentContext();
3201            }
3202    
3203            throw new UnsupportedOperationException();
3204        }
3205    
3206        @NotNull
3207        private static CodegenContext getNotNullParentContextForMethod(CodegenContext cur) {
3208            if (cur instanceof MethodContext) {
3209                cur = cur.getParentContext();
3210            }
3211            assert cur != null;
3212            return cur;
3213        }
3214    
3215    
3216        public void genVarargs(@NotNull VarargValueArgument valueArgument, @NotNull KotlinType outType) {
3217            Type type = asmType(outType);
3218            assert type.getSort() == Type.ARRAY;
3219            Type elementType = correctElementType(type);
3220            List<ValueArgument> arguments = valueArgument.getArguments();
3221            int size = arguments.size();
3222    
3223            boolean hasSpread = false;
3224            for (int i = 0; i != size; ++i) {
3225                if (arguments.get(i).getSpreadElement() != null) {
3226                    hasSpread = true;
3227                    break;
3228                }
3229            }
3230    
3231            if (hasSpread) {
3232                boolean arrayOfReferences = KotlinBuiltIns.isArray(outType);
3233                if (size == 1) {
3234                    // Arrays.copyOf(receiverValue, newLength)
3235                    ValueArgument argument = arguments.get(0);
3236                    Type arrayType = arrayOfReferences ? Type.getType("[Ljava/lang/Object;")
3237                                                       : Type.getType("[" + elementType.getDescriptor());
3238                    gen(argument.getArgumentExpression(), type);
3239                    v.dup();
3240                    v.arraylength();
3241                    v.invokestatic("java/util/Arrays", "copyOf", Type.getMethodDescriptor(arrayType, arrayType, Type.INT_TYPE), false);
3242                    if (arrayOfReferences) {
3243                        v.checkcast(type);
3244                    }
3245                }
3246                else {
3247                    String owner;
3248                    String addDescriptor;
3249                    String toArrayDescriptor;
3250                    if (arrayOfReferences) {
3251                        owner = "kotlin/jvm/internal/SpreadBuilder";
3252                        addDescriptor = "(Ljava/lang/Object;)V";
3253                        toArrayDescriptor = "([Ljava/lang/Object;)[Ljava/lang/Object;";
3254                    }
3255                    else {
3256                        String spreadBuilderClassName = AsmUtil.asmPrimitiveTypeToLangPrimitiveType(elementType).getTypeName().getIdentifier() + "SpreadBuilder";
3257                        owner = "kotlin/jvm/internal/" + spreadBuilderClassName;
3258                        addDescriptor = "(" + elementType.getDescriptor() + ")V";
3259                        toArrayDescriptor = "()" + type.getDescriptor();
3260                    }
3261                    v.anew(Type.getObjectType(owner));
3262                    v.dup();
3263                    v.iconst(size);
3264                    v.invokespecial(owner, "<init>", "(I)V", false);
3265                    for (int i = 0; i != size; ++i) {
3266                        v.dup();
3267                        ValueArgument argument = arguments.get(i);
3268                        if (argument.getSpreadElement() != null) {
3269                            gen(argument.getArgumentExpression(), OBJECT_TYPE);
3270                            v.invokevirtual(owner, "addSpread", "(Ljava/lang/Object;)V", false);
3271                        }
3272                        else {
3273                            gen(argument.getArgumentExpression(), elementType);
3274                            v.invokevirtual(owner, "add", addDescriptor, false);
3275                        }
3276                    }
3277                    if (arrayOfReferences) {
3278                        v.dup();
3279                        v.invokevirtual(owner, "size", "()I", false);
3280                        newArrayInstruction(outType);
3281                        v.invokevirtual(owner, "toArray", toArrayDescriptor, false);
3282                        v.checkcast(type);
3283                    }
3284                    else {
3285                        v.invokevirtual(owner, "toArray", toArrayDescriptor, false);
3286                    }
3287                }
3288            }
3289            else {
3290                v.iconst(arguments.size());
3291                newArrayInstruction(outType);
3292                for (int i = 0; i != size; ++i) {
3293                    v.dup();
3294                    StackValue rightSide = gen(arguments.get(i).getArgumentExpression());
3295                    StackValue.arrayElement(elementType, StackValue.onStack(type), StackValue.constant(i, Type.INT_TYPE)).store(rightSide, v);
3296                }
3297            }
3298        }
3299    
3300        public int indexOfLocalNotDelegated(KtReferenceExpression lhs) {
3301            DeclarationDescriptor declarationDescriptor = bindingContext.get(REFERENCE_TARGET, lhs);
3302            if (isVarCapturedInClosure(bindingContext, declarationDescriptor)) {
3303                return -1;
3304            }
3305            if (declarationDescriptor instanceof LocalVariableDescriptor && ((LocalVariableDescriptor) declarationDescriptor).isDelegated()) {
3306                return -1;
3307            }
3308            return lookupLocalIndex(declarationDescriptor);
3309        }
3310    
3311        @Override
3312        public StackValue visitClassLiteralExpression(@NotNull KtClassLiteralExpression expression, StackValue data) {
3313            KtExpression receiverExpression = expression.getReceiverExpression();
3314            assert receiverExpression != null : "Class literal expression should have a left-hand side";
3315            DoubleColonLHS lhs = bindingContext.get(DOUBLE_COLON_LHS, receiverExpression);
3316            assert lhs != null : "Class literal expression should have LHS resolved";
3317            return generateClassLiteralReference(lhs, receiverExpression, /* wrapIntoKClass = */ true);
3318        }
3319    
3320        @Override
3321        public StackValue visitCallableReferenceExpression(@NotNull KtCallableReferenceExpression expression, StackValue data) {
3322            ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression.getCallableReference(), bindingContext);
3323    
3324            KotlinType receiverExpressionType = expressionJetType(expression.getReceiverExpression());
3325            Type receiverAsmType = receiverExpressionType != null ? asmType(receiverExpressionType) : null;
3326            StackValue receiverValue = receiverExpressionType != null ? gen(expression.getReceiverExpression()) : null;
3327    
3328            FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
3329            if (functionDescriptor != null) {
3330                FunctionReferenceGenerationStrategy strategy =
3331                        new FunctionReferenceGenerationStrategy(state, functionDescriptor, resolvedCall, receiverAsmType, null, false);
3332    
3333                return genClosure(
3334                        expression, functionDescriptor, strategy, null,
3335                        (FunctionDescriptor) resolvedCall.getResultingDescriptor(), receiverValue
3336                );
3337            }
3338    
3339            VariableDescriptor variableDescriptor = getVariableDescriptorNotNull(expression);
3340            return generatePropertyReference(
3341                    expression, variableDescriptor, (VariableDescriptor) resolvedCall.getResultingDescriptor(),
3342                    receiverAsmType, receiverValue
3343            );
3344        }
3345    
3346        @NotNull
3347        private StackValue generatePropertyReference(
3348                @NotNull KtElement element,
3349                @NotNull VariableDescriptor variableDescriptor,
3350                @NotNull VariableDescriptor target,
3351                @Nullable final Type receiverAsmType,
3352                @Nullable final StackValue receiverValue
3353        ) {
3354            ClassDescriptor classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor);
3355    
3356            ClassBuilder classBuilder = state.getFactory().newVisitor(
3357                    JvmDeclarationOriginKt.OtherOrigin(element),
3358                    typeMapper.mapClass(classDescriptor),
3359                    element.getContainingFile()
3360            );
3361    
3362            PropertyReferenceCodegen codegen = new PropertyReferenceCodegen(
3363                    state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION),
3364                    element, classBuilder, variableDescriptor, target, receiverAsmType
3365            );
3366            codegen.generate();
3367    
3368            return codegen.putInstanceOnStack(receiverValue == null ? null : new Function0<Unit>() {
3369                @Override
3370                public Unit invoke() {
3371                    assert receiverAsmType != null : "Receiver type should not be null when receiver value is not null: " + receiverValue;
3372                    receiverValue.put(receiverAsmType, v);
3373                    return Unit.INSTANCE;
3374                }
3375            });
3376        }
3377    
3378        @NotNull
3379        public StackValue generateClassLiteralReference(
3380                @NotNull final DoubleColonLHS lhs,
3381                @Nullable final KtExpression receiverExpression,
3382                final boolean wrapIntoKClass
3383        ) {
3384            return StackValue.operation(wrapIntoKClass ? K_CLASS_TYPE : JAVA_CLASS_TYPE, new Function1<InstructionAdapter, Unit>() {
3385                @Override
3386                public Unit invoke(InstructionAdapter v) {
3387                    KotlinType type = lhs.getType();
3388                    if (lhs instanceof DoubleColonLHS.Expression && !((DoubleColonLHS.Expression) lhs).isObjectQualifier()) {
3389                        JavaClassProperty.INSTANCE.generateImpl(v, gen(receiverExpression));
3390                    }
3391                    else {
3392                        if (TypeUtils.isTypeParameter(type)) {
3393                            assert TypeUtils.isReifiedTypeParameter(type) :
3394                                    "Non-reified type parameter under ::class should be rejected by type checker: " + type;
3395                            putReifiedOperationMarkerIfTypeIsReifiedParameter(type, ReifiedTypeInliner.OperationKind.JAVA_CLASS);
3396                        }
3397    
3398                        putJavaLangClassInstance(v, typeMapper.mapType(type));
3399                    }
3400    
3401                    if (wrapIntoKClass) {
3402                        wrapJavaClassIntoKClass(v);
3403                    }
3404    
3405                    return Unit.INSTANCE;
3406                }
3407            });
3408        }
3409    
3410        @Override
3411        public StackValue visitDotQualifiedExpression(@NotNull KtDotQualifiedExpression expression, StackValue receiver) {
3412            StackValue receiverValue = StackValue.none(); //gen(expression.getReceiverExpression())
3413            return genQualified(receiverValue, expression.getSelectorExpression());
3414        }
3415    
3416        private StackValue generateExpressionWithNullFallback(@NotNull KtExpression expression, @NotNull Label ifnull) {
3417            KtExpression deparenthesized = KtPsiUtil.deparenthesize(expression);
3418            assert deparenthesized != null : "Unexpected empty expression";
3419    
3420            expression = deparenthesized;
3421            Type type = expressionType(expression);
3422    
3423            if (expression instanceof KtSafeQualifiedExpression && !isPrimitive(type)) {
3424                return StackValue.coercion(generateSafeQualifiedExpression((KtSafeQualifiedExpression) expression, ifnull), type);
3425            }
3426            else {
3427                return genLazy(expression, type);
3428            }
3429        }
3430    
3431        private StackValue generateSafeQualifiedExpression(@NotNull KtSafeQualifiedExpression expression, @NotNull Label ifNull) {
3432            KtExpression receiver = expression.getReceiverExpression();
3433            KtExpression selector = expression.getSelectorExpression();
3434    
3435            Type receiverType = expressionType(receiver);
3436            StackValue receiverValue = generateExpressionWithNullFallback(receiver, ifNull);
3437    
3438            //Do not optimize for primitives cause in case of safe call extension receiver should be generated before dispatch one
3439            StackValue newReceiver = new StackValue.SafeCall(receiverType, receiverValue, isPrimitive(receiverType) ? null : ifNull);
3440            return genQualified(newReceiver, selector);
3441        }
3442    
3443        @Override
3444        public StackValue visitSafeQualifiedExpression(@NotNull KtSafeQualifiedExpression expression, StackValue unused) {
3445            Label ifnull = new Label();
3446            Type type = boxType(expressionType(expression));
3447    
3448            StackValue value = generateSafeQualifiedExpression(expression, ifnull);
3449            StackValue newReceiver = StackValue.coercion(value, type);
3450            StackValue result;
3451    
3452            if (!isPrimitive(expressionType(expression.getReceiverExpression()))) {
3453                result = new StackValue.SafeFallback(type, ifnull, newReceiver);
3454            } else {
3455                result = newReceiver;
3456            }
3457    
3458            return result;
3459        }
3460    
3461        @Override
3462        public StackValue visitBinaryExpression(@NotNull KtBinaryExpression expression, @NotNull StackValue receiver) {
3463            KtSimpleNameExpression reference = expression.getOperationReference();
3464            IElementType opToken = reference.getReferencedNameElementType();
3465            if (opToken == KtTokens.EQ) {
3466                return generateAssignmentExpression(expression);
3467            }
3468            else if (KtTokens.AUGMENTED_ASSIGNMENTS.contains(opToken)) {
3469                return generateAugmentedAssignment(expression);
3470            }
3471            else if (opToken == KtTokens.ANDAND) {
3472                return generateBooleanAnd(expression);
3473            }
3474            else if (opToken == KtTokens.OROR) {
3475                return generateBooleanOr(expression);
3476            }
3477            else if (opToken == KtTokens.EQEQ || opToken == KtTokens.EXCLEQ ||
3478                     opToken == KtTokens.EQEQEQ || opToken == KtTokens.EXCLEQEQEQ) {
3479                return generateEquals(expression.getLeft(), expression.getRight(), opToken);
3480            }
3481            else if (opToken == KtTokens.LT || opToken == KtTokens.LTEQ ||
3482                     opToken == KtTokens.GT || opToken == KtTokens.GTEQ) {
3483                return generateComparison(expression, receiver);
3484            }
3485            else if (opToken == KtTokens.ELVIS) {
3486                return generateElvis(expression);
3487            }
3488            else if (opToken == KtTokens.IN_KEYWORD || opToken == KtTokens.NOT_IN) {
3489                return generateIn(StackValue.expression(expressionType(expression.getLeft()), expression.getLeft(), this),
3490                                  expression.getRight(), reference);
3491            }
3492            else {
3493                ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext, state.getShouldInlineConstVals());
3494                if (compileTimeConstant != null) {
3495                    return StackValue.constant(compileTimeConstant.getValue(), expressionType(expression));
3496                }
3497    
3498                ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
3499                FunctionDescriptor descriptor = (FunctionDescriptor) resolvedCall.getResultingDescriptor();
3500    
3501                if (descriptor instanceof ConstructorDescriptor) {
3502                    return generateConstructorCall(resolvedCall, expressionType(expression));
3503                }
3504    
3505                return invokeFunction(resolvedCall, receiver);
3506            }
3507        }
3508    
3509        private StackValue generateIn(final StackValue leftValue, KtExpression rangeExpression, final KtSimpleNameExpression operationReference) {
3510            final KtExpression deparenthesized = KtPsiUtil.deparenthesize(rangeExpression);
3511    
3512            assert deparenthesized != null : "For with empty range expression";
3513            final boolean isInverted = operationReference.getReferencedNameElementType() == KtTokens.NOT_IN;
3514            return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
3515                @Override
3516                public Unit invoke(InstructionAdapter v) {
3517                    if (RangeCodegenUtil.isPrimitiveRangeSpecializationOfType(leftValue.type, deparenthesized, bindingContext) ||
3518                        RangeCodegenUtil.isPrimitiveRangeToExtension(operationReference, bindingContext)) {
3519                        generateInPrimitiveRange(leftValue, (KtBinaryExpression) deparenthesized, isInverted);
3520                    }
3521                    else {
3522                        ResolvedCall<? extends CallableDescriptor> resolvedCall = CallUtilKt
3523                                .getResolvedCallWithAssert(operationReference, bindingContext);
3524                        StackValue result = invokeFunction(resolvedCall.getCall(), resolvedCall, StackValue.none());
3525                        result.put(result.type, v);
3526                        if (isInverted) {
3527                            genInvertBoolean(v);
3528                        }
3529                    }
3530                    return null;
3531                }
3532            });
3533        }
3534    
3535        /*
3536         * Translates x in a..b to a <= x && x <= b
3537         * and x !in a..b to a > x || x > b for any primitive type
3538         */
3539        private void generateInPrimitiveRange(StackValue argument, KtBinaryExpression rangeExpression, boolean isInverted) {
3540            Type rangeType = argument.type;
3541            int localVarIndex = myFrameMap.enterTemp(rangeType);
3542            // Load left bound
3543            gen(rangeExpression.getLeft(), rangeType);
3544            // Load x into local variable to avoid StackValue#put side-effects
3545            argument.put(rangeType, v);
3546            v.store(localVarIndex, rangeType);
3547            v.load(localVarIndex, rangeType);
3548    
3549            // If (x < left) goto L1
3550            Label l1 = new Label();
3551            emitGreaterThan(rangeType, l1);
3552    
3553            // If (x > right) goto L1
3554            v.load(localVarIndex, rangeType);
3555            gen(rangeExpression.getRight(), rangeType);
3556            emitGreaterThan(rangeType, l1);
3557    
3558            Label l2 = new Label();
3559            v.iconst(isInverted ? 0 : 1);
3560            v.goTo(l2);
3561    
3562            v.mark(l1);
3563            v.iconst(isInverted ? 1 : 0);
3564            v.mark(l2);
3565            myFrameMap.leaveTemp(rangeType);
3566        }
3567    
3568        private void emitGreaterThan(Type type, Label label) {
3569            if (AsmUtil.isIntPrimitive(type)) {
3570                v.ificmpgt(label);
3571            }
3572            else if (type == Type.LONG_TYPE) {
3573                v.lcmp();
3574                v.ifgt(label);
3575            }
3576            // '>' != 'compareTo' for NaN and +/- 0.0
3577            else if (type == Type.FLOAT_TYPE || type == Type.DOUBLE_TYPE) {
3578                v.cmpg(type);
3579                v.ifgt(label);
3580            }
3581            else {
3582                throw new UnsupportedOperationException("Unexpected type: " + type);
3583            }
3584        }
3585    
3586        private StackValue generateBooleanAnd(KtBinaryExpression expression) {
3587            return StackValue.and(gen(expression.getLeft()), gen(expression.getRight()));
3588        }
3589    
3590        private StackValue generateBooleanOr(KtBinaryExpression expression) {
3591            return StackValue.or(gen(expression.getLeft()), gen(expression.getRight()));
3592        }
3593    
3594        private StackValue generateEquals(@Nullable KtExpression left, @Nullable KtExpression right, @NotNull IElementType opToken) {
3595            Type leftType = expressionType(left);
3596            Type rightType = expressionType(right);
3597    
3598            if (KtPsiUtil.isNullConstant(left)) {
3599                return genCmpWithNull(right, opToken);
3600            }
3601    
3602            if (KtPsiUtil.isNullConstant(right)) {
3603                return genCmpWithNull(left, opToken);
3604            }
3605    
3606            if (isIntZero(left, leftType) && isIntPrimitive(rightType)) {
3607                return genCmpWithZero(right, opToken);
3608            }
3609    
3610            if (isIntZero(right, rightType) && isIntPrimitive(leftType)) {
3611                return genCmpWithZero(left, opToken);
3612            }
3613    
3614            if (isPrimitive(leftType) != isPrimitive(rightType)) {
3615                leftType = boxType(leftType);
3616                rightType = boxType(rightType);
3617            }
3618    
3619            if (opToken == KtTokens.EQEQEQ || opToken == KtTokens.EXCLEQEQEQ) {
3620                // TODO: always casting to the type of the left operand in case of primitives looks wrong
3621                Type operandType = isPrimitive(leftType) ? leftType : OBJECT_TYPE;
3622                return StackValue.cmp(opToken, operandType, genLazy(left, leftType), genLazy(right, rightType));
3623            }
3624    
3625            return genEqualsForExpressionsPreferIEEE754Arithmetic(left, right, opToken, leftType, rightType, null);
3626        }
3627    
3628        /*tries to use IEEE 754 arithmetic*/
3629        private StackValue genEqualsForExpressionsPreferIEEE754Arithmetic(
3630                @Nullable final KtExpression left,
3631                @Nullable final KtExpression right,
3632                @NotNull final IElementType opToken,
3633                @NotNull Type leftType,
3634                @NotNull Type rightType,
3635                @Nullable final StackValue pregeneratedLeft
3636        ) {
3637            assert (opToken == KtTokens.EQEQ || opToken == KtTokens.EXCLEQ) : "Optoken should be '==' or '!=', but: " + opToken;
3638    
3639            final TypeAndNullability left754Type = calcTypeForIEEE754ArithmeticIfNeeded(left);
3640            final TypeAndNullability right754Type = calcTypeForIEEE754ArithmeticIfNeeded(right);
3641            if (left754Type != null && right754Type != null && left754Type.type.equals(right754Type.type)) {
3642                //check nullability cause there is some optimizations in codegen for non-nullable case
3643                if (left754Type.isNullable || right754Type.isNullable) {
3644                    if (state.getLanguageVersionSettings().getApiVersion().compareTo(ApiVersion.KOTLIN_1_1) >= 0) {
3645                        return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
3646                            @Override
3647                            public Unit invoke(InstructionAdapter v) {
3648                                generate754EqualsForNullableTypesViaIntrinsic(v, opToken, pregeneratedLeft, left, left754Type, right, right754Type);
3649                                return Unit.INSTANCE;
3650                            }
3651                        });
3652                    }
3653                    else {
3654                        return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
3655                            @Override
3656                            public Unit invoke(InstructionAdapter v) {
3657                                generate754EqualsForNullableTypes(v, opToken, pregeneratedLeft, left, left754Type, right, right754Type);
3658                                return Unit.INSTANCE;
3659                            }
3660                        });
3661                    }
3662                }
3663                else {
3664                    leftType = left754Type.type;
3665                    rightType = right754Type.type;
3666                }
3667            }
3668    
3669            return genEqualsForExpressionsOnStack(
3670                    opToken,
3671                    pregeneratedLeft != null ? StackValue.coercion(pregeneratedLeft, leftType) : genLazy(left, leftType),
3672                    genLazy(right, rightType)
3673            );
3674        }
3675    
3676        private void generate754EqualsForNullableTypesViaIntrinsic(
3677                @NotNull InstructionAdapter v,
3678                @NotNull IElementType opToken,
3679                @Nullable StackValue pregeneratedLeft,
3680                @Nullable KtExpression left,
3681                @NotNull TypeAndNullability left754Type,
3682                @Nullable KtExpression right,
3683                @NotNull TypeAndNullability right754Type
3684        ) {
3685            Type leftType = left754Type.isNullable ? AsmUtil.boxType(left754Type.type) : left754Type.type;
3686    
3687            if (pregeneratedLeft != null)  {
3688                StackValue.coercion(pregeneratedLeft, leftType).put(leftType, v);
3689            }
3690            else {
3691                gen(left, leftType);
3692            }
3693            Type rightType = right754Type.isNullable ? AsmUtil.boxType(right754Type.type) : right754Type.type;
3694            gen(right, rightType);
3695    
3696            AsmUtil.genIEEE754EqualForNullableTypesCall(v, leftType, rightType);
3697    
3698            if (opToken == KtTokens.EXCLEQ) {
3699                genInvertBoolean(v);
3700            }
3701        }
3702    
3703        private void generate754EqualsForNullableTypes(
3704                @NotNull InstructionAdapter v,
3705                @NotNull IElementType opToken,
3706                @Nullable StackValue pregeneratedLeft,
3707                @Nullable KtExpression left,
3708                @NotNull TypeAndNullability left754Type,
3709                @Nullable KtExpression right,
3710                @NotNull TypeAndNullability right754Type
3711        ) {
3712            int equals = opToken == KtTokens.EQEQ ? 1 : 0;
3713            int notEquals = opToken != KtTokens.EQEQ ? 1 : 0;
3714            Label end = new Label();
3715            StackValue leftValue = pregeneratedLeft != null ? pregeneratedLeft : gen(left);
3716            leftValue.put(leftValue.type, v);
3717            leftValue = StackValue.onStack(leftValue.type);
3718            Type leftType = left754Type.type;
3719            Type rightType = right754Type.type;
3720            if (left754Type.isNullable) {
3721                leftValue.dup(v, false);
3722                Label leftIsNull = new Label();
3723                v.ifnull(leftIsNull);
3724                StackValue.coercion(leftValue, leftType).put(leftType, v);
3725                StackValue nonNullLeftValue = StackValue.onStack(leftType);
3726    
3727                StackValue rightValue = gen(right);
3728                rightValue.put(rightValue.type, v);
3729                rightValue = StackValue.onStack(rightValue.type);
3730                if (right754Type.isNullable) {
3731                    rightValue.dup(v, false);
3732                    Label rightIsNotNull = new Label();
3733                    v.ifnonnull(rightIsNotNull);
3734                    AsmUtil.pop(v, rightValue.type);
3735                    AsmUtil.pop(v, nonNullLeftValue.type);
3736                    v.iconst(notEquals);
3737                    v.goTo(end);
3738                    v.mark(rightIsNotNull);
3739                }
3740    
3741                StackValue.coercion(rightValue, rightType).put(rightType, v);
3742                StackValue nonNullRightValue = StackValue.onStack(rightType);
3743                StackValue.cmp(opToken, leftType, nonNullLeftValue, nonNullRightValue).put(Type.BOOLEAN_TYPE, v);
3744                v.goTo(end);
3745    
3746                //left is null case
3747                v.mark(leftIsNull);
3748                AsmUtil.pop(v, leftValue.type);//pop null left
3749                rightValue = gen(right);
3750                rightValue.put(rightValue.type, v);
3751                rightValue = StackValue.onStack(rightValue.type);
3752                if (right754Type.isNullable) {
3753                    Label rightIsNotNull = new Label();
3754                    v.ifnonnull(rightIsNotNull);
3755                    v.iconst(equals);
3756                    v.goTo(end);
3757                    v.mark(rightIsNotNull);
3758                    v.iconst(notEquals);
3759                    //v.goTo(end);
3760                }
3761                else {
3762                    AsmUtil.pop(v, rightValue.type);
3763                    v.iconst(notEquals);
3764                    //v.goTo(end);
3765                }
3766    
3767                v.mark(end);
3768                return;
3769            }
3770            else {
3771                StackValue.coercion(leftValue, leftType).put(leftType, v);
3772                leftValue = StackValue.onStack(leftType);
3773            }
3774    
3775            //right is nullable cause left is not
3776            StackValue rightValue = gen(right);
3777            rightValue.put(rightValue.type, v);
3778            rightValue = StackValue.onStack(rightValue.type);
3779    
3780            rightValue.dup(v, false);
3781            Label rightIsNotNull = new Label();
3782            v.ifnonnull(rightIsNotNull);
3783            AsmUtil.pop(v, rightValue.type);
3784            AsmUtil.pop(v, leftValue.type);
3785            v.iconst(notEquals);
3786            v.goTo(end);
3787    
3788            v.mark(rightIsNotNull);
3789            StackValue.coercion(rightValue, rightType).put(rightType, v);
3790            StackValue nonNullRightValue = StackValue.onStack(rightType);
3791            StackValue.cmp(opToken, leftType, leftValue, nonNullRightValue).put(Type.BOOLEAN_TYPE, v);
3792    
3793            v.mark(end);
3794        }
3795    
3796        private boolean isIntZero(KtExpression expr, Type exprType) {
3797            ConstantValue<?> exprValue = getPrimitiveOrStringCompileTimeConstant(expr, bindingContext, state.getShouldInlineConstVals());
3798            return isIntPrimitive(exprType) && exprValue != null && Integer.valueOf(0).equals(exprValue.getValue());
3799        }
3800    
3801        private StackValue genCmpWithZero(KtExpression exp, IElementType opToken) {
3802            return StackValue.compareIntWithZero(gen(exp), (KtTokens.EQEQ == opToken || KtTokens.EQEQEQ == opToken) ? IFNE : IFEQ);
3803        }
3804    
3805        private StackValue genCmpWithNull(KtExpression exp, IElementType opToken) {
3806            return StackValue.compareWithNull(gen(exp), (KtTokens.EQEQ == opToken || KtTokens.EQEQEQ == opToken) ? IFNONNULL : IFNULL);
3807        }
3808    
3809        private StackValue generateElvis(@NotNull final KtBinaryExpression expression) {
3810            KtExpression left = expression.getLeft();
3811    
3812            final Type exprType = expressionType(expression);
3813            final Type leftType = expressionType(left);
3814    
3815            final Label ifNull = new Label();
3816    
3817    
3818            assert left != null : "left expression in elvis should be not null: " + expression.getText();
3819            final StackValue value = generateExpressionWithNullFallback(left, ifNull);
3820    
3821            if (isPrimitive(leftType)) {
3822                return value;
3823            }
3824    
3825            return StackValue.operation(exprType, new Function1<InstructionAdapter, Unit>() {
3826                @Override
3827                public Unit invoke(InstructionAdapter v) {
3828                    value.put(value.type, v);
3829                    v.dup();
3830    
3831                    v.ifnull(ifNull);
3832                    StackValue.onStack(leftType).put(exprType, v);
3833    
3834                    Label end = new Label();
3835                    v.goTo(end);
3836    
3837                    v.mark(ifNull);
3838                    v.pop();
3839                    gen(expression.getRight(), exprType);
3840                    v.mark(end);
3841                    return null;
3842                }
3843            });
3844        }
3845    
3846        private StackValue generateComparison(KtBinaryExpression expression, StackValue receiver) {
3847            ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
3848    
3849            KtExpression left = expression.getLeft();
3850            KtExpression right = expression.getRight();
3851    
3852            Type type;
3853            StackValue leftValue;
3854            StackValue rightValue;
3855            Type leftType = expressionType(left);
3856            Type rightType = expressionType(right);
3857            TypeAndNullability left754Type = calcTypeForIEEE754ArithmeticIfNeeded(left);
3858            TypeAndNullability right754Type = calcTypeForIEEE754ArithmeticIfNeeded(right);
3859            Callable callable = resolveToCallable((FunctionDescriptor) resolvedCall.getResultingDescriptor(), false, resolvedCall);
3860            boolean is754Arithmetic = left754Type != null && right754Type != null && left754Type.type.equals(right754Type.type);
3861            if (callable instanceof IntrinsicCallable && ((isPrimitive(leftType) && isPrimitive(rightType)) || is754Arithmetic)) {
3862                type = is754Arithmetic ? left754Type.type : comparisonOperandType(leftType, rightType);
3863                leftValue = gen(left);
3864                rightValue = gen(right);
3865            }
3866            else {
3867                type = Type.INT_TYPE;
3868                leftValue = invokeFunction(resolvedCall, receiver);
3869                rightValue = StackValue.constant(0, type);
3870            }
3871            return StackValue.cmp(expression.getOperationToken(), type, leftValue, rightValue);
3872        }
3873    
3874        private TypeAndNullability calcTypeForIEEE754ArithmeticIfNeeded(@Nullable KtExpression expression) {
3875            return CodegenUtilKt.calcTypeForIEEE754ArithmeticIfNeeded(expression, bindingContext, context.getFunctionDescriptor());
3876        }
3877    
3878        private StackValue generateAssignmentExpression(final KtBinaryExpression expression) {
3879            return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
3880                @Override
3881                public Unit invoke(InstructionAdapter adapter) {
3882                    StackValue stackValue = gen(expression.getLeft());
3883                    KtExpression right = expression.getRight();
3884                    assert right != null : expression.getText();
3885                    stackValue.store(gen(right), v);
3886    
3887                    return Unit.INSTANCE;
3888                }
3889            });
3890        }
3891    
3892        private StackValue generateAugmentedAssignment(final KtBinaryExpression expression) {
3893            return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
3894                @Override
3895                public Unit invoke(InstructionAdapter adapter) {
3896                    ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
3897                    FunctionDescriptor descriptor = accessibleFunctionDescriptor(resolvedCall);
3898                    Callable callable = resolveToCallable(descriptor, false, resolvedCall);
3899                    KtExpression lhs = expression.getLeft();
3900                    Type lhsType = expressionType(lhs);
3901    
3902                    boolean keepReturnValue = Boolean.TRUE.equals(bindingContext.get(VARIABLE_REASSIGNMENT, expression))
3903                                              || !KotlinBuiltIns.isUnit(descriptor.getReturnType());
3904    
3905                    putCallAugAssignMethod(expression, resolvedCall, callable, lhsType, keepReturnValue);
3906    
3907                    return Unit.INSTANCE;
3908                }
3909            });
3910        }
3911    
3912        private void putCallAugAssignMethod(
3913                @NotNull KtBinaryExpression expression,
3914                @NotNull ResolvedCall<?> resolvedCall,
3915                @NotNull Callable callable,
3916                @NotNull Type lhsType,
3917                boolean keepReturnValue
3918        ) {
3919            StackValue value = gen(expression.getLeft());
3920            if (keepReturnValue) {
3921                value = StackValue.complexWriteReadReceiver(value);
3922            }
3923            value.put(lhsType, v);
3924            StackValue receiver = StackValue.onStack(lhsType);
3925    
3926            callable.invokeMethodWithArguments(resolvedCall, receiver, this).put(callable.getReturnType(), v);
3927    
3928            if (keepReturnValue) {
3929                value.store(StackValue.onStack(callable.getReturnType()), v, true);
3930            }
3931        }
3932    
3933        public void invokeAppend(KtExpression expr) {
3934            ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expr, bindingContext, state.getShouldInlineConstVals());
3935    
3936            if (compileTimeConstant == null && expr instanceof KtBinaryExpression) {
3937                KtBinaryExpression binaryExpression = (KtBinaryExpression) expr;
3938                if (binaryExpression.getOperationToken() == KtTokens.PLUS) {
3939                    KtExpression left = binaryExpression.getLeft();
3940                    KtExpression right = binaryExpression.getRight();
3941                    Type leftType = expressionType(left);
3942    
3943                    if (leftType.equals(JAVA_STRING_TYPE)) {
3944                        invokeAppend(left);
3945                        invokeAppend(right);
3946                        return;
3947                    }
3948                }
3949            }
3950    
3951            Type exprType = expressionType(expr);
3952            if (compileTimeConstant != null) {
3953                StackValue.constant(compileTimeConstant.getValue(), exprType).put(exprType, v);
3954            } else {
3955                gen(expr, exprType);
3956            }
3957            genInvokeAppendMethod(v, exprType.getSort() == Type.ARRAY ? OBJECT_TYPE : exprType);
3958        }
3959    
3960        @Nullable
3961        private static KtSimpleNameExpression targetLabel(KtExpression expression) {
3962            if (expression.getParent() instanceof KtLabeledExpression) {
3963                return ((KtLabeledExpression) expression.getParent()).getTargetLabel();
3964            }
3965            return null;
3966        }
3967    
3968        @Override
3969        public StackValue visitLabeledExpression(
3970                @NotNull KtLabeledExpression expression, StackValue receiver
3971        ) {
3972            return genQualified(receiver, expression.getBaseExpression());
3973        }
3974    
3975        @Override
3976        public StackValue visitPrefixExpression(@NotNull KtPrefixExpression expression, @NotNull StackValue receiver) {
3977            ConstantValue<?> compileTimeConstant = getPrimitiveOrStringCompileTimeConstant(expression, bindingContext, state.getShouldInlineConstVals());
3978            if (compileTimeConstant != null) {
3979                return StackValue.constant(compileTimeConstant.getValue(), expressionType(expression));
3980            }
3981    
3982            DeclarationDescriptor originalOperation = bindingContext.get(REFERENCE_TARGET, expression.getOperationReference());
3983            ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
3984            CallableDescriptor op = resolvedCall.getResultingDescriptor();
3985    
3986            assert op instanceof FunctionDescriptor || originalOperation == null : String.valueOf(op);
3987            String operationName = originalOperation == null ? "" : originalOperation.getName().asString();
3988            if (!(operationName.equals("inc") || operationName.equals("dec"))) {
3989                return invokeFunction(resolvedCall, receiver);
3990            }
3991    
3992            int increment = operationName.equals("inc") ? 1 : -1;
3993            Type type = expressionType(expression.getBaseExpression());
3994            StackValue value = gen(expression.getBaseExpression());
3995            return StackValue.preIncrement(type, value, increment, resolvedCall, this);
3996        }
3997    
3998        @Override
3999        public StackValue visitPostfixExpression(@NotNull final KtPostfixExpression expression, StackValue receiver) {
4000            if (expression.getOperationReference().getReferencedNameElementType() == KtTokens.EXCLEXCL) {
4001                final StackValue base = genQualified(receiver, expression.getBaseExpression());
4002                if (isPrimitive(base.type)) {
4003                    return base;
4004                } else {
4005                    return StackValue.operation(base.type, new Function1<InstructionAdapter, Unit>() {
4006                        @Override
4007                        public Unit invoke(InstructionAdapter v) {
4008                            base.put(base.type, v);
4009                            v.dup();
4010                            Label ok = new Label();
4011                            v.ifnonnull(ok);
4012                            v.invokestatic(IntrinsicMethods.INTRINSICS_CLASS_NAME, "throwNpe", "()V", false);
4013                            v.mark(ok);
4014                            return null;
4015                        }
4016                    });
4017                }
4018            }
4019    
4020            DeclarationDescriptor originalOperation = bindingContext.get(REFERENCE_TARGET, expression.getOperationReference());
4021            String originalOperationName = originalOperation != null ? originalOperation.getName().asString() : null;
4022            final ResolvedCall<?> resolvedCall = CallUtilKt.getResolvedCallWithAssert(expression, bindingContext);
4023            DeclarationDescriptor op = resolvedCall.getResultingDescriptor();
4024            if (!(op instanceof FunctionDescriptor) || originalOperation == null) {
4025                throw new UnsupportedOperationException("Don't know how to generate this postfix expression: " + originalOperationName + " " + op);
4026            }
4027    
4028    
4029            final Type asmResultType = expressionType(expression);
4030            final Type asmBaseType = expressionType(expression.getBaseExpression());
4031    
4032            DeclarationDescriptor cls = op.getContainingDeclaration();
4033    
4034            final int increment;
4035            if (originalOperationName.equals("inc")) {
4036                increment = 1;
4037            }
4038            else if (originalOperationName.equals("dec")) {
4039                increment = -1;
4040            }
4041            else {
4042                throw new UnsupportedOperationException("Unsupported postfix operation: " + originalOperationName + " " + op);
4043            }
4044    
4045            final boolean isPrimitiveNumberClassDescriptor = isPrimitiveNumberClassDescriptor(cls);
4046            if (isPrimitiveNumberClassDescriptor && AsmUtil.isPrimitive(asmBaseType)) {
4047                KtExpression operand = expression.getBaseExpression();
4048                // Optimization for j = i++, when j and i are Int without any smart cast: we just work with primitive int
4049                if (operand instanceof KtReferenceExpression && asmResultType == Type.INT_TYPE &&
4050                    bindingContext.get(BindingContext.SMARTCAST, operand) == null) {
4051                    int index = indexOfLocalNotDelegated((KtReferenceExpression) operand);
4052                    if (index >= 0) {
4053                        return StackValue.postIncrement(index, increment);
4054                    }
4055                }
4056            }
4057    
4058            return StackValue.operation(asmBaseType, new Function1<InstructionAdapter, Unit>() {
4059                @Override
4060                public Unit invoke(InstructionAdapter v) {
4061                    StackValue value = StackValue.complexWriteReadReceiver(gen(expression.getBaseExpression()));
4062    
4063                    value.put(asmBaseType, v);
4064                    AsmUtil.dup(v, asmBaseType);
4065    
4066                    StackValue previousValue = StackValue.local(myFrameMap.enterTemp(asmBaseType), asmBaseType);
4067                    previousValue.store(StackValue.onStack(asmBaseType), v);
4068    
4069                    Type storeType;
4070                    if (isPrimitiveNumberClassDescriptor && AsmUtil.isPrimitive(asmBaseType)) {
4071                        genIncrement(asmBaseType, increment, v);
4072                        storeType = asmBaseType;
4073                    }
4074                    else {
4075                        StackValue result = invokeFunction(resolvedCall, StackValue.onStack(asmBaseType));
4076                        result.put(result.type, v);
4077                        storeType = result.type;
4078                    }
4079    
4080                    value.store(StackValue.onStack(storeType), v, true);
4081    
4082                    previousValue.put(asmBaseType, v);
4083    
4084                    myFrameMap.leaveTemp(asmBaseType);
4085    
4086                    return Unit.INSTANCE;
4087                }
4088            });
4089        }
4090    
4091        @Override
4092        public StackValue visitProperty(@NotNull KtProperty property, StackValue receiver) {
4093            KtExpression initializer = property.getInitializer();
4094            KtExpression delegateExpression = property.getDelegateExpression();
4095    
4096            if (initializer != null) {
4097                assert delegateExpression == null : PsiUtilsKt.getElementTextWithContext(property);
4098                initializeLocalVariable(property, gen(initializer));
4099            }
4100            else if (delegateExpression != null) {
4101                initializeLocalVariable(property, gen(delegateExpression));
4102            }
4103    
4104            return StackValue.none();
4105        }
4106    
4107        @Override
4108        public StackValue visitDestructuringDeclaration(@NotNull KtDestructuringDeclaration multiDeclaration, StackValue receiver) {
4109            KtExpression initializer = multiDeclaration.getInitializer();
4110            if (initializer == null) return StackValue.none();
4111    
4112            KotlinType initializerType = bindingContext.getType(initializer);
4113            assert initializerType != null;
4114    
4115            Type initializerAsmType = asmType(initializerType);
4116    
4117            TransientReceiver initializerAsReceiver = new TransientReceiver(initializerType);
4118    
4119            int tempVarIndex = myFrameMap.enterTemp(initializerAsmType);
4120    
4121            gen(initializer, initializerAsmType);
4122            v.store(tempVarIndex, initializerAsmType);
4123            StackValue.Local local = StackValue.local(tempVarIndex, initializerAsmType);
4124    
4125            initializeDestructuringDeclarationVariables(multiDeclaration, initializerAsReceiver, local);
4126    
4127            if (initializerAsmType.getSort() == Type.OBJECT || initializerAsmType.getSort() == Type.ARRAY) {
4128                v.aconst(null);
4129                v.store(tempVarIndex, initializerAsmType);
4130            }
4131            myFrameMap.leaveTemp(initializerAsmType);
4132    
4133            return StackValue.none();
4134        }
4135    
4136        public void initializeDestructuringDeclarationVariables(
4137                @NotNull KtDestructuringDeclaration destructuringDeclaration,
4138                @NotNull ReceiverValue receiver,
4139                @NotNull StackValue receiverStackValue
4140        ) {
4141            for (KtDestructuringDeclarationEntry variableDeclaration : destructuringDeclaration.getEntries()) {
4142                ResolvedCall<FunctionDescriptor> resolvedCall = bindingContext.get(COMPONENT_RESOLVED_CALL, variableDeclaration);
4143                assert resolvedCall != null : "Resolved call is null for " + variableDeclaration.getText();
4144                Call call = makeFakeCall(receiver);
4145    
4146                VariableDescriptor variableDescriptor = getVariableDescriptorNotNull(variableDeclaration);
4147    
4148                // Do not call `componentX` for destructuring entry called _
4149                if (variableDescriptor.getName().isSpecial()) continue;
4150    
4151                initializeLocalVariable(variableDeclaration, invokeFunction(call, resolvedCall, receiverStackValue));
4152            }
4153        }
4154    
4155        @NotNull
4156        private StackValue getVariableMetadataValue(VariableDescriptor variableDescriptor) {
4157            StackValue value = findLocalOrCapturedValue(getDelegatedLocalVariableMetadata(variableDescriptor, bindingContext));
4158            assert value != null : "Can't find stack value for local delegated variable metadata: " + variableDescriptor;
4159            return value;
4160        }
4161    
4162        @NotNull
4163        private StackValue adjustVariableValue(@NotNull StackValue varValue, DeclarationDescriptor descriptor) {
4164            if (!isDelegatedLocalVariable(descriptor)) return varValue;
4165    
4166            VariableDescriptorWithAccessors variableDescriptor = (VariableDescriptorWithAccessors) descriptor;
4167            StackValue metadataValue = getVariableMetadataValue(variableDescriptor);
4168            return delegatedVariableValue(varValue, metadataValue, variableDescriptor, typeMapper);
4169        }
4170    
4171        private void initializeLocalVariable(
4172                @NotNull KtVariableDeclaration variableDeclaration,
4173                @NotNull StackValue initializer
4174        ) {
4175            LocalVariableDescriptor variableDescriptor = (LocalVariableDescriptor) getVariableDescriptorNotNull(variableDeclaration);
4176    
4177            if (KtPsiUtil.isScriptDeclaration(variableDeclaration)) {
4178                return;
4179            }
4180            int index = lookupLocalIndex(variableDescriptor);
4181    
4182            if (index < 0) {
4183                throw new IllegalStateException("Local variable not found for " + variableDescriptor);
4184            }
4185    
4186            Type sharedVarType = typeMapper.getSharedVarType(variableDescriptor);
4187    
4188            Type varType = getVariableTypeNoSharing(variableDescriptor);
4189    
4190            StackValue storeTo = sharedVarType == null ? StackValue.local(index, varType) : StackValue.shared(index, varType);
4191    
4192            storeTo.putReceiver(v, false);
4193            initializer.put(initializer.type, v);
4194    
4195            markLineNumber(variableDeclaration, false);
4196            Type resultType = initializer.type;
4197    
4198            if (isDelegatedLocalVariable(variableDescriptor)) {
4199                StackValue metadataValue = getVariableMetadataValue(variableDescriptor);
4200                initializePropertyMetadata((KtProperty) variableDeclaration, variableDescriptor, metadataValue);
4201    
4202                ResolvedCall<FunctionDescriptor> provideDelegateResolvedCall = bindingContext.get(PROVIDE_DELEGATE_RESOLVED_CALL, variableDescriptor);
4203                if (provideDelegateResolvedCall != null) {
4204                    resultType = generateProvideDelegateCallForLocalVariable(initializer, metadataValue, provideDelegateResolvedCall);
4205                }
4206            }
4207    
4208            storeTo.storeSelector(resultType, v);
4209    
4210        }
4211    
4212        @NotNull
4213        private Type generateProvideDelegateCallForLocalVariable(
4214                @NotNull StackValue initializer,
4215                final StackValue metadataValue,
4216                ResolvedCall<FunctionDescriptor> provideDelegateResolvedCall
4217        ) {
4218            StackValue provideDelegateReceiver = StackValue.onStack(initializer.type);
4219    
4220            List<? extends ValueArgument> arguments = provideDelegateResolvedCall.getCall().getValueArguments();
4221            assert arguments.size() == 2 :
4222                    "Resolved call for '" +
4223                    OperatorNameConventions.PROVIDE_DELEGATE.asString() +
4224                    "' should have exactly 2 value parameters";
4225    
4226            tempVariables.put(arguments.get(0).asElement(), StackValue.constant(null, AsmTypes.OBJECT_TYPE));
4227            tempVariables.put(
4228                    arguments.get(1).asElement(),
4229                    new StackValue(K_PROPERTY_TYPE) {
4230                        @Override
4231                        public void putSelector(@NotNull Type type, @NotNull InstructionAdapter v) {
4232                            metadataValue.put(type, v);
4233                        }
4234                    }
4235            );
4236    
4237            StackValue result = invokeFunction(provideDelegateResolvedCall, provideDelegateReceiver);
4238            result.put(result.type, v);
4239            tempVariables.remove(arguments.get(0).asElement());
4240            tempVariables.remove(arguments.get(1).asElement());
4241            return result.type;
4242        }
4243    
4244        @NotNull
4245        private VariableDescriptor getVariableDescriptorNotNull(@NotNull KtElement declaration) {
4246            VariableDescriptor descriptor = bindingContext.get(VARIABLE, declaration);
4247            assert descriptor != null :  "Couldn't find variable declaration in binding context " + declaration.getText();
4248            return descriptor;
4249        }
4250    
4251        private void initializePropertyMetadata(
4252                @NotNull KtProperty variable,
4253                @NotNull LocalVariableDescriptor variableDescriptor,
4254                @NotNull StackValue metadataVar
4255        ) {
4256            //noinspection ConstantConditions
4257            StackValue value = generatePropertyReference(variable.getDelegate(), variableDescriptor, variableDescriptor, null, null);
4258            value.put(K_PROPERTY0_TYPE, v);
4259            metadataVar.storeSelector(K_PROPERTY0_TYPE, v);
4260        }
4261    
4262        @NotNull
4263        private StackValue generateNewCall(@NotNull KtCallExpression expression, @NotNull ResolvedCall<?> resolvedCall) {
4264            Type type = expressionType(expression);
4265            if (type.getSort() == Type.ARRAY) {
4266                //noinspection ConstantConditions
4267                return generateNewArray(expression, bindingContext.getType(expression), resolvedCall);
4268            }
4269    
4270            return generateConstructorCall(resolvedCall, type);
4271        }
4272    
4273        @NotNull
4274        public ClassConstructorDescriptor getConstructorDescriptor(@NotNull ResolvedCall<?> resolvedCall) {
4275            FunctionDescriptor accessibleDescriptor = accessibleFunctionDescriptor(resolvedCall);
4276            assert accessibleDescriptor instanceof ClassConstructorDescriptor :
4277                    "getConstructorDescriptor must be called only for constructors: " + accessibleDescriptor;
4278            return (ClassConstructorDescriptor) accessibleDescriptor;
4279        }
4280    
4281        @Nullable
4282        private static ReceiverValue getConstructorReceiver(@NotNull ResolvedCall<?> resolvedCall) {
4283            CallableDescriptor constructor = resolvedCall.getResultingDescriptor();
4284            if (constructor.getExtensionReceiverParameter() != null) {
4285                assert constructor instanceof TypeAliasConstructorDescriptor :
4286                        "Only type alias constructor can have an extension receiver: " + constructor;
4287                return resolvedCall.getExtensionReceiver();
4288            }
4289            else if (constructor.getDispatchReceiverParameter() != null) {
4290                return resolvedCall.getDispatchReceiver();
4291            }
4292            else {
4293                return null;
4294            }
4295        }
4296    
4297        @NotNull
4298        public StackValue generateConstructorCall(@NotNull final ResolvedCall<?> resolvedCall, @NotNull final Type objectType) {
4299            return StackValue.functionCall(objectType, new Function1<InstructionAdapter, Unit>() {
4300                @Override
4301                public Unit invoke(InstructionAdapter v) {
4302                    v.anew(objectType);
4303                    v.dup();
4304    
4305                    ClassConstructorDescriptor constructor = getConstructorDescriptor(resolvedCall);
4306    
4307                    ReceiverParameterDescriptor dispatchReceiver = constructor.getDispatchReceiverParameter();
4308                    ClassDescriptor containingDeclaration = constructor.getContainingDeclaration();
4309                    if (dispatchReceiver != null) {
4310                        Type receiverType = typeMapper.mapType(dispatchReceiver.getType());
4311                        ReceiverValue receiver = getConstructorReceiver(resolvedCall);
4312                        boolean callSuper = containingDeclaration.isInner() && receiver instanceof ImplicitClassReceiver;
4313                        generateReceiverValue(receiver, callSuper).put(receiverType, v);
4314                    }
4315    
4316                    // Resolved call to local class constructor doesn't have dispatchReceiver, so we need to generate closure on stack
4317                    // See StackValue.receiver for more info
4318                    pushClosureOnStack(
4319                            containingDeclaration, dispatchReceiver == null, defaultCallGenerator, /* functionReferenceReceiver = */ null
4320                    );
4321    
4322                    constructor = SamCodegenUtil.resolveSamAdapter(constructor);
4323                    CallableMethod method = typeMapper.mapToCallableMethod(constructor, false);
4324                    invokeMethodWithArguments(method, resolvedCall, StackValue.none());
4325    
4326                    return Unit.INSTANCE;
4327                }
4328            });
4329        }
4330    
4331        public StackValue generateNewArray(
4332                @NotNull KtCallExpression expression, @NotNull final KotlinType arrayType, @NotNull ResolvedCall<?> resolvedCall
4333        ) {
4334            List<KtValueArgument> args = expression.getValueArguments();
4335            assert args.size() == 1 || args.size() == 2 : "Unknown constructor called: " + args.size() + " arguments";
4336    
4337            if (args.size() == 1) {
4338                final KtExpression sizeExpression = args.get(0).getArgumentExpression();
4339                return StackValue.operation(typeMapper.mapType(arrayType), new Function1<InstructionAdapter, Unit>() {
4340                    @Override
4341                    public Unit invoke(InstructionAdapter v) {
4342                        gen(sizeExpression, Type.INT_TYPE);
4343                        newArrayInstruction(arrayType);
4344                        return Unit.INSTANCE;
4345                    }
4346                });
4347            }
4348    
4349            return invokeFunction(resolvedCall, StackValue.none());
4350        }
4351    
4352        public void newArrayInstruction(@NotNull KotlinType arrayType) {
4353            if (KotlinBuiltIns.isArray(arrayType)) {
4354                KotlinType elementJetType = arrayType.getArguments().get(0).getType();
4355                putReifiedOperationMarkerIfTypeIsReifiedParameter(
4356                        elementJetType,
4357                        ReifiedTypeInliner.OperationKind.NEW_ARRAY
4358                );
4359                v.newarray(boxType(asmType(elementJetType)));
4360            }
4361            else {
4362                Type type = typeMapper.mapType(arrayType);
4363                v.newarray(correctElementType(type));
4364            }
4365        }
4366    
4367        @Override
4368        public StackValue visitArrayAccessExpression(@NotNull KtArrayAccessExpression expression, StackValue receiver) {
4369            KtExpression array = expression.getArrayExpression();
4370            KotlinType type = array != null ? bindingContext.getType(array) : null;
4371            Type arrayType = expressionType(array);
4372            List<KtExpression> indices = expression.getIndexExpressions();
4373            FunctionDescriptor operationDescriptor = (FunctionDescriptor) bindingContext.get(REFERENCE_TARGET, expression);
4374            assert operationDescriptor != null;
4375            if (arrayType.getSort() == Type.ARRAY &&
4376                indices.size() == 1 &&
4377                isInt(operationDescriptor.getValueParameters().get(0).getType())) {
4378                assert type != null;
4379                Type elementType;
4380                if (KotlinBuiltIns.isArray(type)) {
4381                    KotlinType jetElementType = type.getArguments().get(0).getType();
4382                    elementType = boxType(asmType(jetElementType));
4383                }
4384                else {
4385                    elementType = correctElementType(arrayType);
4386                }
4387                StackValue arrayValue = genLazy(array, arrayType);
4388                StackValue index = genLazy(indices.get(0), Type.INT_TYPE);
4389    
4390                return StackValue.arrayElement(elementType, arrayValue, index);
4391            }
4392            else {
4393                ResolvedCall<FunctionDescriptor> resolvedSetCall = bindingContext.get(INDEXED_LVALUE_SET, expression);
4394                ResolvedCall<FunctionDescriptor> resolvedGetCall = bindingContext.get(INDEXED_LVALUE_GET, expression);
4395    
4396                boolean isGetter = OperatorNameConventions.GET.equals(operationDescriptor.getName());
4397    
4398                Callable callable = resolveToCallable(operationDescriptor, false, isGetter ? resolvedGetCall : resolvedSetCall);
4399                Callable callableMethod = resolveToCallableMethod(operationDescriptor, false);
4400                Type[] argumentTypes = callableMethod.getParameterTypes();
4401    
4402                StackValue.CollectionElementReceiver collectionElementReceiver = createCollectionElementReceiver(
4403                        expression, receiver, operationDescriptor, isGetter, resolvedGetCall, resolvedSetCall, callable
4404                );
4405    
4406                Type elementType = isGetter ? callableMethod.getReturnType() : ArrayUtil.getLastElement(argumentTypes);
4407                return StackValue.collectionElement(collectionElementReceiver, elementType, resolvedGetCall, resolvedSetCall, this);
4408            }
4409        }
4410    
4411        @NotNull
4412        private StackValue.CollectionElementReceiver createCollectionElementReceiver(
4413                @NotNull KtArrayAccessExpression expression,
4414                @NotNull StackValue receiver,
4415                @NotNull FunctionDescriptor operationDescriptor,
4416                boolean isGetter,
4417                ResolvedCall<FunctionDescriptor> resolvedGetCall,
4418                ResolvedCall<FunctionDescriptor> resolvedSetCall,
4419                @NotNull Callable callable
4420        ) {
4421            ResolvedCall<FunctionDescriptor> resolvedCall = isGetter ? resolvedGetCall : resolvedSetCall;
4422            assert resolvedCall != null : "couldn't find resolved call: " + expression.getText();
4423    
4424            List<ResolvedValueArgument> valueArguments = resolvedCall.getValueArgumentsByIndex();
4425            assert valueArguments != null : "Failed to arrange value arguments by index: " + operationDescriptor;
4426    
4427            if (!isGetter) {
4428                assert valueArguments.size() >= 2 : "Setter call should have at least 2 arguments: " + operationDescriptor;
4429                // Skip generation of the right hand side of an indexed assignment, which is the last value argument
4430                valueArguments.remove(valueArguments.size() - 1);
4431            }
4432    
4433            return new StackValue.CollectionElementReceiver(
4434                    callable, receiver, resolvedGetCall, resolvedSetCall, isGetter, this, valueArguments
4435            );
4436        }
4437    
4438        @Override
4439        public StackValue visitThrowExpression(@NotNull final KtThrowExpression expression, StackValue receiver) {
4440            return StackValue.operation(Type.VOID_TYPE, new Function1<InstructionAdapter, Unit>() {
4441                @Override
4442                public Unit invoke(InstructionAdapter adapter) {
4443                    gen(expression.getThrownExpression(), JAVA_THROWABLE_TYPE);
4444                    v.athrow();
4445                    return Unit.INSTANCE;
4446                }
4447            });
4448        }
4449    
4450        @Override
4451        public StackValue visitThisExpression(@NotNull KtThisExpression expression, StackValue receiver) {
4452            DeclarationDescriptor descriptor = bindingContext.get(REFERENCE_TARGET, expression.getInstanceReference());
4453            if (descriptor instanceof ClassDescriptor) {
4454                //TODO rewrite with context.lookupInContext()
4455                return StackValue.thisOrOuter(this, (ClassDescriptor) descriptor, false, true);
4456            }
4457            if (descriptor instanceof CallableDescriptor) {
4458                return generateExtensionReceiver((CallableDescriptor) descriptor);
4459            }
4460            throw new UnsupportedOperationException("Neither this nor receiver: " + descriptor + expression.getParent().getContainingFile().getText());
4461        }
4462    
4463        @Override
4464        public StackValue visitTryExpression(@NotNull KtTryExpression expression, StackValue receiver) {
4465            return generateTryExpression(expression, false);
4466        }
4467    
4468        public StackValue generateTryExpression(final KtTryExpression expression, final boolean isStatement) {
4469            /*
4470    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
4471    (or blocks).
4472             */
4473    
4474            final Type expectedAsmType = isStatement ? Type.VOID_TYPE : expressionTypeForBranchingOperation(expression);
4475    
4476            return StackValue.operation(expectedAsmType, new Function1<InstructionAdapter, Unit>() {
4477                @Override
4478                public Unit invoke(InstructionAdapter v) {
4479                    KtFinallySection finallyBlock = expression.getFinallyBlock();
4480                    FinallyBlockStackElement finallyBlockStackElement = null;
4481                    if (finallyBlock != null) {
4482                        finallyBlockStackElement = new FinallyBlockStackElement(expression);
4483                        blockStackElements.push(finallyBlockStackElement);
4484                    }
4485    
4486                    //PseudoInsnsPackage.saveStackBeforeTryExpr(v);
4487    
4488                    Label tryStart = new Label();
4489                    v.mark(tryStart);
4490                    v.nop(); // prevent verify error on empty try
4491    
4492                    gen(expression.getTryBlock(), expectedAsmType);
4493    
4494                    int savedValue = -1;
4495                    if (!isStatement) {
4496                        savedValue = myFrameMap.enterTemp(expectedAsmType);
4497                        v.store(savedValue, expectedAsmType);
4498                    }
4499    
4500                    Label tryEnd = new Label();
4501                    v.mark(tryEnd);
4502    
4503                    //do it before finally block generation
4504                    List<Label> tryBlockRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, tryEnd);
4505    
4506                    Label end = new Label();
4507    
4508                    genFinallyBlockOrGoto(finallyBlockStackElement, end, null);
4509    
4510                    List<KtCatchClause> clauses = expression.getCatchClauses();
4511                    for (int i = 0, size = clauses.size(); i < size; i++) {
4512                        KtCatchClause clause = clauses.get(i);
4513    
4514                        Label clauseStart = new Label();
4515                        v.mark(clauseStart);
4516    
4517                        KtExpression catchBody = clause.getCatchBody();
4518                        if (catchBody != null) {
4519                            markLineNumber(catchBody, false);
4520                        }
4521    
4522                        VariableDescriptor descriptor = bindingContext.get(VALUE_PARAMETER, clause.getCatchParameter());
4523                        assert descriptor != null;
4524                        Type descriptorType = asmType(descriptor.getType());
4525                        myFrameMap.enter(descriptor, descriptorType);
4526                        int index = lookupLocalIndex(descriptor);
4527                        v.store(index, descriptorType);
4528    
4529                        Label catchVariableStart = new Label();
4530                        v.mark(catchVariableStart);
4531    
4532                        gen(catchBody, expectedAsmType);
4533    
4534                        if (!isStatement) {
4535                            v.store(savedValue, expectedAsmType);
4536                        }
4537    
4538                        myFrameMap.leave(descriptor);
4539    
4540                        Label clauseEnd = new Label();
4541                        v.mark(clauseEnd);
4542    
4543                        v.visitLocalVariable(descriptor.getName().asString(), descriptorType.getDescriptor(), null,
4544                                             catchVariableStart, clauseEnd, index);
4545    
4546                        genFinallyBlockOrGoto(finallyBlockStackElement, i != size - 1 || finallyBlock != null ? end : null, null);
4547    
4548                        generateExceptionTable(clauseStart, tryBlockRegions, descriptorType.getInternalName());
4549                    }
4550    
4551    
4552                    //for default catch clause
4553                    if (finallyBlock != null) {
4554                        Label defaultCatchStart = new Label();
4555                        v.mark(defaultCatchStart);
4556                        int savedException = myFrameMap.enterTemp(JAVA_THROWABLE_TYPE);
4557                        v.store(savedException, JAVA_THROWABLE_TYPE);
4558    
4559                        Label defaultCatchEnd = new Label();
4560                        v.mark(defaultCatchEnd);
4561    
4562                        //do it before finally block generation
4563                        //javac also generates entry in exception table for default catch clause too!!!! so defaultCatchEnd as end parameter
4564                        List<Label> defaultCatchRegions = getCurrentCatchIntervals(finallyBlockStackElement, tryStart, defaultCatchEnd);
4565    
4566    
4567                        genFinallyBlockOrGoto(finallyBlockStackElement, null, null);
4568    
4569                        v.load(savedException, JAVA_THROWABLE_TYPE);
4570                        myFrameMap.leaveTemp(JAVA_THROWABLE_TYPE);
4571    
4572                        v.athrow();
4573    
4574                        generateExceptionTable(defaultCatchStart, defaultCatchRegions, null);
4575                    }
4576    
4577                    markLineNumber(expression, isStatement);
4578                    v.mark(end);
4579    
4580                    if (!isStatement) {
4581                        v.load(savedValue, expectedAsmType);
4582                        myFrameMap.leaveTemp(expectedAsmType);
4583                    }
4584    
4585                    if (finallyBlock != null) {
4586                        blockStackElements.pop();
4587                    }
4588                    return Unit.INSTANCE;
4589                }
4590            });
4591        }
4592    
4593        private void generateExceptionTable(@NotNull Label catchStart, @NotNull List<Label> catchedRegions, @Nullable String exception) {
4594            for (int i = 0; i < catchedRegions.size(); i += 2) {
4595                Label startRegion = catchedRegions.get(i);
4596                Label endRegion = catchedRegions.get(i+1);
4597                v.visitTryCatchBlock(startRegion, endRegion, catchStart, exception);
4598            }
4599        }
4600    
4601        @NotNull
4602        private static List<Label> getCurrentCatchIntervals(
4603                @Nullable FinallyBlockStackElement finallyBlockStackElement,
4604                @NotNull Label blockStart,
4605                @NotNull Label blockEnd
4606        ) {
4607            List<Label> gapsInBlock =
4608                    finallyBlockStackElement != null ? new ArrayList<Label>(finallyBlockStackElement.gaps) : Collections.<Label>emptyList();
4609            assert gapsInBlock.size() % 2 == 0;
4610            List<Label> blockRegions = new ArrayList<Label>(gapsInBlock.size() + 2);
4611            blockRegions.add(blockStart);
4612            blockRegions.addAll(gapsInBlock);
4613            blockRegions.add(blockEnd);
4614            return blockRegions;
4615        }
4616    
4617        @Override
4618        public StackValue visitBinaryWithTypeRHSExpression(@NotNull KtBinaryExpressionWithTypeRHS expression, StackValue receiver) {
4619            KtExpression left = expression.getLeft();
4620            final IElementType opToken = expression.getOperationReference().getReferencedNameElementType();
4621    
4622            final KotlinType rightType = bindingContext.get(TYPE, expression.getRight());
4623            assert rightType != null;
4624    
4625            final StackValue value = genQualified(receiver, left);
4626    
4627            return StackValue.operation(boxType(asmType(rightType)), new Function1<InstructionAdapter, Unit>() {
4628                @Override
4629                public Unit invoke(InstructionAdapter v) {
4630                    value.put(boxType(value.type), v);
4631    
4632                    if (value.type == Type.VOID_TYPE) {
4633                        StackValue.putUnitInstance(v);
4634                    }
4635    
4636                    boolean safeAs = opToken == KtTokens.AS_SAFE;
4637                    Type type = boxType(asmType(rightType));
4638                    if (TypeUtils.isReifiedTypeParameter(rightType)) {
4639                        putReifiedOperationMarkerIfTypeIsReifiedParameter(rightType,
4640                                                                          safeAs ? ReifiedTypeInliner.OperationKind.SAFE_AS
4641                                                                                 : ReifiedTypeInliner.OperationKind.AS);
4642                        v.checkcast(type);
4643                        return Unit.INSTANCE;
4644                    }
4645    
4646                    CodegenUtilKt.generateAsCast(v, rightType, type, safeAs);
4647    
4648                    return Unit.INSTANCE;
4649                }
4650            });
4651        }
4652    
4653        @Override
4654        public StackValue visitIsExpression(@NotNull KtIsExpression expression, StackValue receiver) {
4655            StackValue match = StackValue.expression(OBJECT_TYPE, expression.getLeftHandSide(), this);
4656            return generateIsCheck(match, expression.getTypeReference(), expression.isNegated());
4657        }
4658    
4659        private StackValue generateExpressionMatch(StackValue expressionToMatch, KtExpression subjectExpression, KtExpression patternExpression) {
4660            if (expressionToMatch != null) {
4661                Type subjectType = expressionToMatch.type;
4662                markStartLineNumber(patternExpression);
4663                KotlinType condJetType = bindingContext.getType(patternExpression);
4664                Type condType;
4665                if (isNumberPrimitiveOrBoolean(subjectType)) {
4666                    assert condJetType != null;
4667                    condType = asmType(condJetType);
4668                    if (!isNumberPrimitiveOrBoolean(condType)) {
4669                        subjectType = boxType(subjectType);
4670                    }
4671                }
4672                else {
4673                    condType = OBJECT_TYPE;
4674                }
4675    
4676                return genEqualsForExpressionsPreferIEEE754Arithmetic(subjectExpression, patternExpression, KtTokens.EQEQ, subjectType, condType, expressionToMatch);
4677            }
4678            else {
4679                return gen(patternExpression);
4680            }
4681        }
4682    
4683        private StackValue generateIsCheck(StackValue expressionToMatch, KtTypeReference typeReference, boolean negated) {
4684            KotlinType jetType = bindingContext.get(TYPE, typeReference);
4685            markStartLineNumber(typeReference);
4686            StackValue value = generateIsCheck(expressionToMatch, jetType, false);
4687            return negated ? StackValue.not(value) : value;
4688        }
4689    
4690        private StackValue generateIsCheck(final StackValue expressionToGen, final KotlinType kotlinType, final boolean leaveExpressionOnStack) {
4691            return StackValue.operation(Type.BOOLEAN_TYPE, new Function1<InstructionAdapter, Unit>() {
4692                @Override
4693                public Unit invoke(InstructionAdapter v) {
4694                    expressionToGen.put(OBJECT_TYPE, v);
4695                    if (leaveExpressionOnStack) {
4696                        v.dup();
4697                    }
4698    
4699                    Type type = boxType(asmType(kotlinType));
4700                    if (TypeUtils.isReifiedTypeParameter(kotlinType)) {
4701                        putReifiedOperationMarkerIfTypeIsReifiedParameter(kotlinType, ReifiedTypeInliner.OperationKind.IS);
4702                        v.instanceOf(type);
4703                        return null;
4704                    }
4705    
4706                    CodegenUtilKt.generateIsCheck(v, kotlinType, type);
4707                    return null;
4708                }
4709            });
4710        }
4711    
4712        public void putReifiedOperationMarkerIfTypeIsReifiedParameter(
4713                @NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind
4714        ) {
4715            putReifiedOperationMarkerIfTypeIsReifiedParameter(type, operationKind, v);
4716        }
4717    
4718        public void putReifiedOperationMarkerIfTypeIsReifiedParameter(
4719                @NotNull KotlinType type, @NotNull ReifiedTypeInliner.OperationKind operationKind, @NotNull InstructionAdapter v
4720        ) {
4721            Pair<TypeParameterDescriptor, ReificationArgument> typeParameterAndReificationArgument = extractReificationArgument(type);
4722            if (typeParameterAndReificationArgument != null && typeParameterAndReificationArgument.getFirst().isReified()) {
4723                TypeParameterDescriptor typeParameterDescriptor = typeParameterAndReificationArgument.getFirst();
4724                if (typeParameterDescriptor.getContainingDeclaration() != context.getContextDescriptor()) {
4725                    parentCodegen.getReifiedTypeParametersUsages().
4726                            addUsedReifiedParameter(typeParameterDescriptor.getName().asString());
4727                }
4728                v.iconst(operationKind.getId());
4729                v.visitLdcInsn(typeParameterAndReificationArgument.getSecond().asString());
4730                v.invokestatic(
4731                        IntrinsicMethods.INTRINSICS_CLASS_NAME, ReifiedTypeInliner.REIFIED_OPERATION_MARKER_METHOD_NAME,
4732                        Type.getMethodDescriptor(Type.VOID_TYPE, Type.INT_TYPE, Type.getType(String.class)), false
4733                );
4734            }
4735        }
4736    
4737        public void propagateChildReifiedTypeParametersUsages(@NotNull ReifiedTypeParametersUsages usages) {
4738            parentCodegen.getReifiedTypeParametersUsages().propagateChildUsagesWithinContext(usages, context);
4739        }
4740    
4741        @Override
4742        public StackValue visitWhenExpression(@NotNull KtWhenExpression expression, StackValue receiver) {
4743            return generateWhenExpression(expression, false);
4744        }
4745    
4746        public StackValue generateWhenExpression(final KtWhenExpression expression, final boolean isStatement) {
4747            final KtExpression expr = expression.getSubjectExpression();
4748            final Type subjectType = expressionType(expr);
4749    
4750            final Type resultType = isStatement ? Type.VOID_TYPE : expressionTypeForBranchingOperation(expression);
4751    
4752            return StackValue.operation(resultType, new Function1<InstructionAdapter, Unit>() {
4753                @Override
4754                public Unit invoke(InstructionAdapter v) {
4755                    SwitchCodegen switchCodegen = SwitchCodegenUtil.buildAppropriateSwitchCodegenIfPossible(
4756                            expression, isStatement, CodegenUtil.isExhaustive(bindingContext, expression, isStatement),
4757                            ExpressionCodegen.this
4758                    );
4759                    if (switchCodegen != null) {
4760                        switchCodegen.generate();
4761                        return Unit.INSTANCE;
4762                    }
4763    
4764                    int subjectLocal = expr != null ? myFrameMap.enterTemp(subjectType) : -1;
4765                    if (subjectLocal != -1) {
4766                        gen(expr, subjectType);
4767                        tempVariables.put(expr, StackValue.local(subjectLocal, subjectType));
4768                        v.store(subjectLocal, subjectType);
4769                    }
4770    
4771                    Label end = new Label();
4772                    boolean hasElse = KtPsiUtil.checkWhenExpressionHasSingleElse(expression);
4773    
4774                    Label nextCondition = null;
4775                    for (KtWhenEntry whenEntry : expression.getEntries()) {
4776                        if (nextCondition != null) {
4777                            v.mark(nextCondition);
4778                        }
4779                        nextCondition = new Label();
4780                        FrameMap.Mark mark = myFrameMap.mark();
4781                        Label thisEntry = new Label();
4782                        if (!whenEntry.isElse()) {
4783                            KtWhenCondition[] conditions = whenEntry.getConditions();
4784                            for (int i = 0; i < conditions.length; i++) {
4785                                StackValue conditionValue = generateWhenCondition(expr, subjectType, subjectLocal, conditions[i]);
4786                                BranchedValue.Companion.condJump(conditionValue, nextCondition, true, v);
4787                                if (i < conditions.length - 1) {
4788                                    v.goTo(thisEntry);
4789                                    v.mark(nextCondition);
4790                                    nextCondition = new Label();
4791                                }
4792                            }
4793                        }
4794    
4795                        v.visitLabel(thisEntry);
4796                        gen(whenEntry.getExpression(), resultType);
4797                        mark.dropTo();
4798                        if (!whenEntry.isElse()) {
4799                            v.goTo(end);
4800                        }
4801                    }
4802                    if (!hasElse && nextCondition != null) {
4803                        v.mark(nextCondition);
4804                        putUnitInstanceOntoStackForNonExhaustiveWhen(expression, isStatement);
4805                    }
4806    
4807                    markLineNumber(expression, isStatement);
4808                    v.mark(end);
4809    
4810                    myFrameMap.leaveTemp(subjectType);
4811                    tempVariables.remove(expr);
4812                    return null;
4813                }
4814            });
4815        }
4816    
4817        public void putUnitInstanceOntoStackForNonExhaustiveWhen(
4818                @NotNull KtWhenExpression whenExpression,
4819                boolean isStatement
4820        ) {
4821            if (CodegenUtil.isExhaustive(bindingContext, whenExpression, isStatement)) {
4822                // when() is supposed to be exhaustive
4823                genThrow(v, "kotlin/NoWhenBranchMatchedException", null);
4824            }
4825            else if (!isStatement) {
4826                // non-exhaustive when() with no else -> Unit must be expected
4827                StackValue.putUnitInstance(v);
4828            }
4829        }
4830    
4831        private StackValue generateWhenCondition(KtExpression subjectExpression, Type subjectType, int subjectLocal, KtWhenCondition condition) {
4832            if (condition instanceof KtWhenConditionInRange) {
4833                KtWhenConditionInRange conditionInRange = (KtWhenConditionInRange) condition;
4834                return generateIn(StackValue.local(subjectLocal, subjectType),
4835                                  conditionInRange.getRangeExpression(),
4836                                  conditionInRange.getOperationReference());
4837            }
4838            StackValue.Local match = subjectLocal == -1 ? null : StackValue.local(subjectLocal, subjectType);
4839            if (condition instanceof KtWhenConditionIsPattern) {
4840                KtWhenConditionIsPattern patternCondition = (KtWhenConditionIsPattern) condition;
4841                return generateIsCheck(match, patternCondition.getTypeReference(), patternCondition.isNegated());
4842            }
4843            else if (condition instanceof KtWhenConditionWithExpression) {
4844                KtExpression patternExpression = ((KtWhenConditionWithExpression) condition).getExpression();
4845                return generateExpressionMatch(match, subjectExpression, patternExpression);
4846            }
4847            else {
4848                throw new UnsupportedOperationException("unsupported kind of when condition");
4849            }
4850        }
4851    
4852        private Call makeFakeCall(ReceiverValue initializerAsReceiver) {
4853            KtSimpleNameExpression fake = KtPsiFactoryKt.KtPsiFactory(state.getProject()).createSimpleName("fake");
4854            return CallMaker.makeCall(fake, initializerAsReceiver);
4855        }
4856    
4857        @Override
4858        public String toString() {
4859            return context.getContextDescriptor().toString();
4860        }
4861    
4862        @NotNull
4863        public FrameMap getFrameMap() {
4864            return myFrameMap;
4865        }
4866    
4867        @NotNull
4868        public MethodContext getContext() {
4869            return context;
4870        }
4871    
4872        @NotNull
4873        public NameGenerator getInlineNameGenerator() {
4874            NameGenerator nameGenerator = getParentCodegen().getInlineNameGenerator();
4875            Name name = context.getContextDescriptor().getName();
4876            String inlinedName = name.isSpecial() ? InlineCodegenUtil.SPECIAL_TRANSFORMATION_NAME : name.asString();
4877            return nameGenerator.subGenerator(inlinedName + InlineCodegenUtil.INLINE_CALL_TRANSFORMATION_SUFFIX);
4878        }
4879    
4880        public Type getReturnType() {
4881            return returnType;
4882        }
4883    
4884        public Stack<BlockStackElement> getBlockStackElements() {
4885            return new Stack<BlockStackElement>(blockStackElements);
4886        }
4887    
4888        public void addBlockStackElementsForNonLocalReturns(@NotNull Stack<BlockStackElement> elements, int finallyDepth) {
4889            blockStackElements.addAll(elements);
4890            this.finallyDepth = finallyDepth;
4891        }
4892    
4893        private static class NonLocalReturnInfo {
4894    
4895            private final Type returnType;
4896    
4897            private final String labelName;
4898    
4899            private NonLocalReturnInfo(@NotNull Type type, @NotNull String name) {
4900                returnType = type;
4901                labelName = name;
4902            }
4903        }
4904    
4905        @NotNull
4906        private StackValue.Delegate delegatedVariableValue(
4907                @NotNull StackValue delegateValue,
4908                @NotNull StackValue metadataValue,
4909                @NotNull VariableDescriptorWithAccessors variableDescriptor,
4910                @NotNull KotlinTypeMapper typeMapper
4911        ) {
4912            return StackValue.delegate(typeMapper.mapType(variableDescriptor.getType()), delegateValue, metadataValue, variableDescriptor, this);
4913        }
4914    }