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