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