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