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