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.inline;
018    
019    import com.intellij.openapi.vfs.VirtualFile;
020    import com.intellij.psi.PsiElement;
021    import com.intellij.psi.PsiFile;
022    import org.jetbrains.annotations.NotNull;
023    import org.jetbrains.annotations.Nullable;
024    import org.jetbrains.kotlin.backend.common.CodegenUtil;
025    import org.jetbrains.kotlin.codegen.*;
026    import org.jetbrains.kotlin.codegen.context.CodegenContext;
027    import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
028    import org.jetbrains.kotlin.codegen.context.MethodContext;
029    import org.jetbrains.kotlin.codegen.context.PackageContext;
030    import org.jetbrains.kotlin.codegen.state.GenerationState;
031    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
032    import org.jetbrains.kotlin.descriptors.*;
033    import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCache;
034    import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents;
035    import org.jetbrains.kotlin.modules.TargetId;
036    import org.jetbrains.kotlin.name.Name;
037    import org.jetbrains.kotlin.psi.*;
038    import org.jetbrains.kotlin.renderer.DescriptorRenderer;
039    import org.jetbrains.kotlin.resolve.BindingContext;
040    import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
041    import org.jetbrains.kotlin.resolve.DescriptorUtils;
042    import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilKt;
043    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
044    import org.jetbrains.kotlin.resolve.inline.InlineUtil;
045    import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
046    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
047    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
048    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
049    import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor;
050    import org.jetbrains.kotlin.types.expressions.LabelResolver;
051    import org.jetbrains.org.objectweb.asm.Label;
052    import org.jetbrains.org.objectweb.asm.MethodVisitor;
053    import org.jetbrains.org.objectweb.asm.Opcodes;
054    import org.jetbrains.org.objectweb.asm.Type;
055    import org.jetbrains.org.objectweb.asm.commons.Method;
056    import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
057    import org.jetbrains.org.objectweb.asm.tree.InsnList;
058    import org.jetbrains.org.objectweb.asm.tree.LabelNode;
059    import org.jetbrains.org.objectweb.asm.tree.MethodNode;
060    
061    import java.io.IOException;
062    import java.util.*;
063    
064    import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags;
065    import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
066    import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
067    import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.getConstant;
068    import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral;
069    
070    public class InlineCodegen extends CallGenerator {
071        private final GenerationState state;
072        private final JetTypeMapper typeMapper;
073    
074        private final SimpleFunctionDescriptor functionDescriptor;
075        private final JvmMethodSignature jvmSignature;
076        private final KtElement callElement;
077        private final MethodContext context;
078        private final ExpressionCodegen codegen;
079    
080        private final boolean asFunctionInline;
081        private final int initialFrameSize;
082        private final boolean isSameModule;
083    
084        private final ParametersBuilder invocationParamBuilder = ParametersBuilder.newBuilder();
085        private final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>();
086    
087        private final ReifiedTypeInliner reifiedTypeInliner;
088    
089        private LambdaInfo activeLambda;
090    
091        private final SourceMapper sourceMapper;
092    
093        public InlineCodegen(
094                @NotNull ExpressionCodegen codegen,
095                @NotNull GenerationState state,
096                @NotNull SimpleFunctionDescriptor functionDescriptor,
097                @NotNull KtElement callElement,
098                @Nullable ReifiedTypeParameterMappings typeParameterMappings
099        ) {
100            assert InlineUtil.isInline(functionDescriptor) : "InlineCodegen could inline only inline function: " + functionDescriptor;
101    
102            this.state = state;
103            this.typeMapper = state.getTypeMapper();
104            this.codegen = codegen;
105            this.callElement = callElement;
106            this.functionDescriptor = functionDescriptor.getOriginal();
107    
108            reifiedTypeInliner = new ReifiedTypeInliner(typeParameterMappings);
109    
110            initialFrameSize = codegen.getFrameMap().getCurrentSize();
111    
112            PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);
113            context = (MethodContext) getContext(functionDescriptor, state, element != null ? (KtFile) element.getContainingFile() : null);
114            jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind());
115    
116            // TODO: implement AS_FUNCTION inline strategy
117            this.asFunctionInline = false;
118    
119            isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.getOutDirectory());
120    
121            sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper();
122            reportIncrementalInfo(functionDescriptor, codegen.getContext().getFunctionDescriptor().getOriginal());
123        }
124    
125        @Override
126        public void genCallWithoutAssertions(
127                @NotNull CallableMethod callableMethod, @NotNull ExpressionCodegen codegen
128        ) {
129            genCall(callableMethod, null, false, codegen);
130        }
131    
132        @Override
133        public void genCallInner(@NotNull Callable callableMethod, @Nullable ResolvedCall<?> resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen) {
134            SMAPAndMethodNode nodeAndSmap = null;
135            if (!state.getInlineCycleReporter().enterIntoInlining(resolvedCall)) {
136                generateStub(resolvedCall, codegen);
137                return;
138            }
139    
140            try {
141                nodeAndSmap = createMethodNode(callDefault);
142                endCall(inlineCall(nodeAndSmap));
143            }
144            catch (CompilationException e) {
145                throw e;
146            }
147            catch (Exception e) {
148                boolean generateNodeText = !(e instanceof InlineException);
149                PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(this.codegen.getContext().getContextDescriptor());
150                throw new CompilationException("Couldn't inline method call '" +
151                                           functionDescriptor.getName() +
152                                           "' into \n" + (element != null ? element.getText() : "null psi element " + this.codegen.getContext().getContextDescriptor()) +
153                                           (generateNodeText ? ("\ncause: " + InlineCodegenUtil.getNodeText(nodeAndSmap != null ? nodeAndSmap.getNode(): null)) : ""),
154                                           e, callElement);
155            }
156            finally {
157                state.getInlineCycleReporter().exitFromInliningOf(resolvedCall);
158            }
159        }
160    
161        protected void generateStub(@Nullable ResolvedCall<?> resolvedCall, @NotNull ExpressionCodegen codegen) {
162            leaveTemps();
163            assert resolvedCall != null;
164            String message = "Call is part of inline cycle: " + resolvedCall.getCall().getCallElement().getText();
165            AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", message);
166        }
167    
168        private void endCall(@NotNull InlineResult result) {
169            leaveTemps();
170    
171            codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages());
172    
173            state.getFactory().removeClasses(result.getClassesToRemove());
174    
175            codegen.markLineNumberAfterInlineIfNeeded();
176        }
177    
178        @NotNull
179        private SMAPAndMethodNode createMethodNode(boolean callDefault) throws ClassNotFoundException, IOException {
180            JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind());
181    
182            Method asmMethod;
183            if (callDefault) {
184                asmMethod = typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind());
185            }
186            else {
187                asmMethod = jvmSignature.getAsmMethod();
188            }
189    
190            SMAPAndMethodNode nodeAndSMAP;
191            if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) {
192                JetTypeMapper.ContainingClassesInfo containingClasses = typeMapper.getContainingClassesForDeserializedCallable(
193                        (DeserializedSimpleFunctionDescriptor) functionDescriptor);
194    
195                VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containingClasses.getImplClassId(), state);
196                nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(),
197                                                              asmMethod.getName(),
198                                                              asmMethod.getDescriptor(),
199                                                              containingClasses.getFacadeClassId());
200    
201                if (nodeAndSMAP == null) {
202                    throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
203                }
204            }
205            else {
206                PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);
207    
208                if (element == null || !(element instanceof KtNamedFunction)) {
209                    throw new RuntimeException("Couldn't find declaration for function " + descriptorName(functionDescriptor));
210                }
211                KtNamedFunction inliningFunction = (KtNamedFunction) element;
212    
213                MethodNode node = new MethodNode(InlineCodegenUtil.API,
214                                               getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0),
215                                               asmMethod.getName(),
216                                               asmMethod.getDescriptor(),
217                                               jvmSignature.getGenericsSignature(),
218                                               null);
219    
220                //for maxLocals calculation
221                MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node);
222                MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor);
223    
224                SMAP smap;
225                if (callDefault) {
226                    Type implementationOwner = typeMapper.mapOwner(functionDescriptor);
227                    FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction,
228                                                                            (FieldOwnerContext) methodContext.getParentContext(),
229                                                                            implementationOwner.getInternalName());
230                    FunctionCodegen.generateDefaultImplBody(
231                            methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
232                            inliningFunction, parentCodegen
233                    );
234                    smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings());
235                }
236                else {
237                    smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false);
238                }
239    
240                nodeAndSMAP = new SMAPAndMethodNode(node, smap);
241                maxCalcAdapter.visitMaxs(-1, -1);
242                maxCalcAdapter.visitEnd();
243            }
244            return nodeAndSMAP;
245        }
246    
247        private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) {
248            MethodNode node = nodeAndSmap.getNode();
249            ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node);
250            generateClosuresBodies();
251    
252            //through generation captured parameters will be added to invocationParamBuilder
253            putClosureParametersOnStack();
254    
255            addInlineMarker(codegen.v, true);
256    
257            Parameters parameters = invocationParamBuilder.buildParameters();
258    
259            InliningContext info = new RootInliningContext(expressionMap,
260                                                           state,
261                                                           codegen.getInlineNameGenerator()
262                                                                   .subGenerator(functionDescriptor.getName().asString()),
263                                                           codegen.getContext(),
264                                                           callElement,
265                                                           codegen.getParentCodegen().getClassName(), reifiedTypeInliner);
266    
267            MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule,
268                                                      "Method inlining " + callElement.getText(),
269                                                      createNestedSourceMapper(nodeAndSmap)); //with captured
270    
271            LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize);
272    
273    
274            MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode();
275            //hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain
276            adapter.visitInsn(Opcodes.NOP);
277    
278            InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL);
279            result.getReifiedTypeParametersUsages().mergeAll(reificationResult);
280    
281            CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor();
282            final Set<String> labels = getDeclarationLabels(DescriptorToSourceUtils.descriptorToDeclaration(descriptor), descriptor);
283            LabelOwner labelOwner = new LabelOwner() {
284                @Override
285                public boolean isMyLabel(@NotNull String name) {
286                    return labels.contains(name);
287                }
288            };
289    
290            List<MethodInliner.PointForExternalFinallyBlocks> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
291            generateAndInsertFinallyBlocks(adapter, infos, ((StackValue.Local)remapper.remap(parameters.getArgsSizeOnStack() + 1).value).index);
292            removeFinallyMarkers(adapter);
293    
294            adapter.accept(new InliningInstructionAdapter(codegen.v));
295    
296            addInlineMarker(codegen.v, false);
297    
298            return result;
299        }
300    
301        private void generateClosuresBodies() {
302            for (LambdaInfo info : expressionMap.values()) {
303                info.setNode(generateLambdaBody(info));
304            }
305        }
306    
307        private SMAPAndMethodNode generateLambdaBody(LambdaInfo info) {
308            KtExpression declaration = info.getFunctionWithBodyOrCallableReference();
309            FunctionDescriptor descriptor = info.getFunctionDescriptor();
310    
311            MethodContext parentContext = codegen.getContext();
312    
313            MethodContext context = parentContext.intoClosure(descriptor, codegen, typeMapper).intoInlinedLambda(descriptor, info.isCrossInline);
314    
315            JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(descriptor);
316            Method asmMethod = jvmMethodSignature.getAsmMethod();
317            MethodNode methodNode = new MethodNode(InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), jvmMethodSignature.getGenericsSignature(), null);
318    
319            MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
320    
321            SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true);
322            adapter.visitMaxs(-1, -1);
323            return new SMAPAndMethodNode(methodNode, smap);
324        }
325    
326        private SMAP generateMethodBody(
327                @NotNull MethodVisitor adapter,
328                @NotNull FunctionDescriptor descriptor,
329                @NotNull MethodContext context,
330                @NotNull KtExpression expression,
331                @NotNull JvmMethodSignature jvmMethodSignature,
332                boolean isLambda
333        ) {
334            FakeMemberCodegen parentCodegen =
335                    new FakeMemberCodegen(codegen.getParentCodegen(), expression,
336                                          (FieldOwnerContext) context.getParentContext(),
337                                          isLambda ? codegen.getParentCodegen().getClassName()
338                                                   : typeMapper.mapOwner(descriptor).getInternalName());
339    
340            FunctionGenerationStrategy strategy =
341                    expression instanceof KtCallableReferenceExpression ?
342                    new FunctionReferenceGenerationStrategy(
343                            state,
344                            descriptor,
345                            CallUtilKt.getResolvedCallWithAssert(((KtCallableReferenceExpression) expression).getCallableReference(),
346                                                                 codegen.getBindingContext()
347                            )) :
348                    new FunctionGenerationStrategy.FunctionDefault(state, descriptor, (KtDeclarationWithBody) expression);
349    
350            FunctionCodegen.generateMethodBody(
351                    adapter, descriptor, context, jvmMethodSignature,
352                    strategy,
353                    // Wrapping for preventing marking actual parent codegen as containing reifier markers
354                    parentCodegen
355            );
356    
357            if (isLambda) {
358                codegen.propagateChildReifiedTypeParametersUsages(parentCodegen.getReifiedTypeParametersUsages());
359            }
360    
361            return createSMAPWithDefaultMapping(expression, parentCodegen.getOrCreateSourceMapper().getResultMappings());
362        }
363    
364        private static SMAP createSMAPWithDefaultMapping(
365                @NotNull KtExpression declaration,
366                @NotNull List<FileMapping> mappings
367        ) {
368            PsiFile containingFile = declaration.getContainingFile();
369            Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true);
370            assert lineNumbers != null : "Couldn't extract line count in " + containingFile;
371    
372            return new SMAP(mappings);
373        }
374    
375        private static class FakeMemberCodegen extends MemberCodegen {
376    
377            private final MemberCodegen delegate;
378            @NotNull private final String className;
379    
380            public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull KtElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) {
381                super(wrapped, declaration, codegenContext);
382                delegate = wrapped;
383                this.className = className;
384            }
385    
386            @Override
387            protected void generateDeclaration() {
388                throw new IllegalStateException();
389            }
390    
391            @Override
392            protected void generateBody() {
393                throw new IllegalStateException();
394            }
395    
396            @Override
397            protected void generateKotlinAnnotation() {
398                throw new IllegalStateException();
399            }
400    
401            @NotNull
402            @Override
403            public NameGenerator getInlineNameGenerator() {
404                return delegate.getInlineNameGenerator();
405            }
406    
407            @NotNull
408            @Override
409            //TODO: obtain name from context
410            public String getClassName() {
411                return className;
412            }
413        }
414    
415        @Override
416        public void afterParameterPut(
417                @NotNull Type type,
418                @Nullable StackValue stackValue,
419                @Nullable ValueParameterDescriptor valueParameterDescriptor,
420                int parameterIndex
421        ) {
422            putArgumentOrCapturedToLocalVal(type, stackValue, -1, parameterIndex);
423        }
424    
425        private void putArgumentOrCapturedToLocalVal(
426                @NotNull Type type,
427                @Nullable StackValue stackValue,
428                int capturedParamIndex,
429                int parameterIndex
430        ) {
431            if (!asFunctionInline && Type.VOID_TYPE != type) {
432                //TODO remap only inlinable closure => otherwise we could get a lot of problem
433                boolean couldBeRemapped = !shouldPutValue(type, stackValue);
434                StackValue remappedIndex = couldBeRemapped ? stackValue : null;
435    
436                ParameterInfo info;
437                if (capturedParamIndex >= 0) {
438                    CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex);
439                    info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName());
440                    info.setRemapValue(remappedIndex);
441                }
442                else {
443                    info = invocationParamBuilder.addNextValueParameter(type, false, remappedIndex, parameterIndex);
444                }
445    
446                recordParameterValueInLocalVal(info);
447            }
448        }
449    
450        /*descriptor is null for captured vars*/
451        public static boolean shouldPutValue(
452                @NotNull Type type,
453                @Nullable StackValue stackValue
454        ) {
455    
456            if (stackValue == null) {
457                //default or vararg
458                return true;
459            }
460    
461            //remap only inline functions (and maybe non primitives)
462            //TODO - clean asserion and remapping logic
463            if (isPrimitive(type) != isPrimitive(stackValue.type)) {
464                //don't remap boxing/unboxing primitives - lost identity and perfomance
465                return true;
466            }
467    
468            if (stackValue instanceof StackValue.Local) {
469                return false;
470            }
471    
472            StackValue field = stackValue;
473            if (stackValue instanceof StackValue.FieldForSharedVar) {
474                field = ((StackValue.FieldForSharedVar) stackValue).receiver;
475            }
476    
477            //check that value corresponds to captured inlining parameter
478            if (field instanceof StackValue.Field) {
479                DeclarationDescriptor varDescriptor = ((StackValue.Field) field).descriptor;
480                //check that variable is inline function parameter
481                return !(varDescriptor instanceof ParameterDescriptor &&
482                         InlineUtil.isInlineLambdaParameter((ParameterDescriptor) varDescriptor) &&
483                         InlineUtil.isInline(varDescriptor.getContainingDeclaration()));
484            }
485    
486            return true;
487        }
488    
489        private void recordParameterValueInLocalVal(ParameterInfo... infos) {
490            int[] index = new int[infos.length];
491            for (int i = 0; i < infos.length; i++) {
492                ParameterInfo info = infos[i];
493                if (!info.isSkippedOrRemapped()) {
494                    index[i] = codegen.getFrameMap().enterTemp(info.getType());
495                }
496                else {
497                    index[i] = -1;
498                }
499            }
500    
501            for (int i = infos.length - 1; i >= 0; i--) {
502                ParameterInfo info = infos[i];
503                if (!info.isSkippedOrRemapped()) {
504                    Type type = info.type;
505                    StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v);
506                }
507            }
508        }
509    
510        @Override
511        public void putHiddenParams() {
512            List<JvmMethodParameterSignature> valueParameters = jvmSignature.getValueParameters();
513    
514            if (!isStaticMethod(functionDescriptor, context)) {
515                invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null);
516            }
517    
518            for (JvmMethodParameterSignature param : valueParameters) {
519                if (param.getKind() == JvmMethodParameterKind.VALUE) {
520                    break;
521                }
522                invocationParamBuilder.addNextParameter(param.getAsmType(), false, null);
523            }
524    
525            invocationParamBuilder.markValueParametesStart();
526            List<ParameterInfo> hiddenParameters = invocationParamBuilder.buildParameters().getReal();
527            recordParameterValueInLocalVal(hiddenParameters.toArray(new ParameterInfo[hiddenParameters.size()]));
528        }
529    
530        public void leaveTemps() {
531            FrameMap frameMap = codegen.getFrameMap();
532            List<ParameterInfo> infos = invocationParamBuilder.listAllParams();
533            for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) {
534                ParameterInfo param = iterator.previous();
535                if (!param.isSkippedOrRemapped()) {
536                    frameMap.leaveTemp(param.type);
537                }
538            }
539        }
540    
541        /*lambda or callable reference*/
542        public boolean isInliningParameter(KtExpression expression, ValueParameterDescriptor valueParameterDescriptor) {
543            //TODO deparenthisise typed
544            KtExpression deparenthesized = KtPsiUtil.deparenthesize(expression);
545    
546            if (deparenthesized instanceof KtCallableReferenceExpression) {
547                // TODO: support inline of property references passed to inlinable function parameters
548                SimpleFunctionDescriptor functionReference = state.getBindingContext().get(BindingContext.FUNCTION, deparenthesized);
549                if (functionReference == null) return false;
550            }
551    
552            return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) &&
553                   isInlinableParameterExpression(deparenthesized);
554        }
555    
556        protected static boolean isInlinableParameterExpression(KtExpression deparenthesized) {
557            return deparenthesized instanceof KtLambdaExpression ||
558                   deparenthesized instanceof KtNamedFunction ||
559                   deparenthesized instanceof KtCallableReferenceExpression;
560        }
561    
562        public void rememberClosure(KtExpression expression, Type type, ValueParameterDescriptor parameter) {
563            KtExpression lambda = KtPsiUtil.deparenthesize(expression);
564            assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText();
565    
566    
567            LambdaInfo info = new LambdaInfo(lambda, typeMapper, parameter.isCrossinline());
568    
569            ParameterInfo closureInfo = invocationParamBuilder.addNextValueParameter(type, true, null, parameter.getIndex());
570            closureInfo.setLambda(info);
571            expressionMap.put(closureInfo.getIndex(), info);
572        }
573    
574        @NotNull
575        protected static Set<String> getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) {
576            Set<String> result = new HashSet<String>();
577    
578            if (lambdaOrFun != null) {
579                Name label = LabelResolver.INSTANCE.getLabelNameIfAny(lambdaOrFun);
580                if (label != null) {
581                    result.add(label.asString());
582                }
583            }
584    
585            if (!isFunctionLiteral(descriptor)) {
586                if (!descriptor.getName().isSpecial()) {
587                    result.add(descriptor.getName().asString());
588                }
589                result.add(InlineCodegenUtil.FIRST_FUN_LABEL);
590            }
591            return result;
592        }
593    
594        private void putClosureParametersOnStack() {
595            for (LambdaInfo next : expressionMap.values()) {
596                activeLambda = next;
597                codegen.pushClosureOnStack(next.getClassDescriptor(), true, this);
598            }
599            activeLambda = null;
600        }
601    
602        public static CodegenContext getContext(@NotNull DeclarationDescriptor descriptor, @NotNull GenerationState state, @Nullable KtFile sourceFile) {
603            if (descriptor instanceof PackageFragmentDescriptor) {
604                return new PackageContext((PackageFragmentDescriptor) descriptor, state.getRootContext(), null, sourceFile);
605            }
606    
607            CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state, sourceFile);
608    
609            if (descriptor instanceof ScriptDescriptor) {
610                List<ScriptDescriptor> earlierScripts = state.getReplSpecific().getEarlierScriptsForReplInterpreter();
611                return parent.intoScript((ScriptDescriptor) descriptor,
612                                         earlierScripts == null ? Collections.emptyList() : earlierScripts,
613                                         (ClassDescriptor) descriptor, state.getTypeMapper());
614            }
615            else if (descriptor instanceof ClassDescriptor) {
616                OwnerKind kind = DescriptorUtils.isInterface(descriptor) ? OwnerKind.DEFAULT_IMPLS : OwnerKind.IMPLEMENTATION;
617                return parent.intoClass((ClassDescriptor) descriptor, kind, state);
618            }
619            else if (descriptor instanceof FunctionDescriptor) {
620                return parent.intoFunction((FunctionDescriptor) descriptor);
621            }
622    
623            throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor));
624        }
625    
626        private static boolean isStaticMethod(FunctionDescriptor functionDescriptor, MethodContext context) {
627            return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0;
628        }
629    
630        private static String descriptorName(DeclarationDescriptor descriptor) {
631            return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
632        }
633    
634        @Override
635        public void genValueAndPut(
636                @NotNull ValueParameterDescriptor valueParameterDescriptor,
637                @NotNull KtExpression argumentExpression,
638                @NotNull Type parameterType,
639                int parameterIndex
640        ) {
641            if (isInliningParameter(argumentExpression, valueParameterDescriptor)) {
642                rememberClosure(argumentExpression, parameterType, valueParameterDescriptor);
643            }
644            else {
645                StackValue value = codegen.gen(argumentExpression);
646                putValueIfNeeded(valueParameterDescriptor, parameterType, value, valueParameterDescriptor.getIndex());
647            }
648        }
649    
650        @Override
651        public void putValueIfNeeded(
652                @Nullable ValueParameterDescriptor valueParameterDescriptor,
653                @NotNull Type parameterType,
654                @NotNull StackValue value
655        ) {
656            putValueIfNeeded(valueParameterDescriptor, parameterType, value, -1);
657        }
658    
659        private void putValueIfNeeded(
660                @Nullable ValueParameterDescriptor valueParameterDescriptor,
661                @NotNull Type parameterType,
662                @NotNull StackValue value,
663                int index
664        ) {
665            if (shouldPutValue(parameterType, value)) {
666                value.put(parameterType, codegen.v);
667            }
668            afterParameterPut(parameterType, value, valueParameterDescriptor, index);
669        }
670    
671        @Override
672        public void putCapturedValueOnStack(
673                @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex
674        ) {
675            if (shouldPutValue(stackValue.type, stackValue)) {
676                stackValue.put(stackValue.type, codegen.v);
677            }
678            putArgumentOrCapturedToLocalVal(stackValue.type, stackValue, paramIndex, paramIndex);
679        }
680    
681    
682        public void generateAndInsertFinallyBlocks(
683                @NotNull MethodNode intoNode,
684                @NotNull List<MethodInliner.PointForExternalFinallyBlocks> insertPoints,
685                int offsetForFinallyLocalVar
686        ) {
687            if (!codegen.hasFinallyBlocks()) return;
688    
689            Map<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks> extensionPoints =
690                    new HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>();
691            for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) {
692                extensionPoints.put(insertPoint.beforeIns, insertPoint);
693            }
694    
695            DefaultProcessor processor = new DefaultProcessor(intoNode, offsetForFinallyLocalVar);
696    
697            int curFinallyDepth = 0;
698            AbstractInsnNode curInstr = intoNode.instructions.getFirst();
699            while (curInstr != null) {
700                processor.processInstruction(curInstr, true);
701                if (InlineCodegenUtil.isFinallyStart(curInstr)) {
702                    //TODO depth index calc could be more precise
703                    curFinallyDepth = getConstant(curInstr.getPrevious());
704                }
705    
706                MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
707                if (extension != null) {
708                    Label start = new Label();
709    
710                    MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode();
711                    finallyNode.visitLabel(start);
712    
713                    ExpressionCodegen finallyCodegen =
714                            new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(),
715                                                  codegen.getContext(), codegen.getState(), codegen.getParentCodegen());
716                    finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements(), curFinallyDepth);
717    
718                    FrameMap frameMap = finallyCodegen.getFrameMap();
719                    FrameMap.Mark mark = frameMap.mark();
720                    int marker = -1;
721                    Set<LocalVarNodeWrapper> intervals = processor.getLocalVarsMetaInfo().getCurrentIntervals();
722                    for (LocalVarNodeWrapper interval : intervals) {
723                        marker = Math.max(interval.getNode().index + 1, marker);
724                    }
725                    while (frameMap.getCurrentSize() < Math.max(processor.getNextFreeLocalIndex(), offsetForFinallyLocalVar + marker)) {
726                        frameMap.enterTemp(Type.INT_TYPE);
727                    }
728    
729                    finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType, extension.finallyIntervalEnd.getLabel());
730    
731                    //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
732                    InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr);
733    
734                    SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, extension.finallyIntervalEnd);
735                    processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, true);
736    
737                    //processor.getLocalVarsMetaInfo().splitAndRemoveIntervalsFromCurrents(splitBy);
738    
739                    mark.dropTo();
740                }
741    
742                curInstr = curInstr.getNext();
743            }
744    
745            processor.substituteTryBlockNodes(intoNode);
746    
747            //processor.substituteLocalVarTable(intoNode);
748        }
749    
750        public void removeFinallyMarkers(@NotNull MethodNode intoNode) {
751            if (InlineCodegenUtil.isFinallyMarkerRequired(codegen.getContext())) return;
752    
753            InsnList instructions = intoNode.instructions;
754            AbstractInsnNode curInstr = instructions.getFirst();
755            while (curInstr != null) {
756                if (InlineCodegenUtil.isFinallyMarker(curInstr)) {
757                    AbstractInsnNode marker = curInstr;
758                    //just to assert
759                    getConstant(marker.getPrevious());
760                    curInstr = curInstr.getNext();
761                    instructions.remove(marker.getPrevious());
762                    instructions.remove(marker);
763                    continue;
764                }
765                curInstr = curInstr.getNext();
766            }
767        }
768    
769        private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) {
770            return new NestedSourceMapper(sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
771        }
772    
773        private void reportIncrementalInfo(
774                @NotNull FunctionDescriptor sourceDescriptor,
775                @NotNull FunctionDescriptor targetDescriptor
776        ) {
777            IncrementalCompilationComponents incrementalCompilationComponents = state.getIncrementalCompilationComponents();
778            TargetId targetId = state.getTargetId();
779    
780            if (incrementalCompilationComponents == null || targetId == null) return;
781    
782            IncrementalCache incrementalCache = incrementalCompilationComponents.getIncrementalCache(targetId);
783            String classFilePath = InlineCodegenUtilsKt.getClassFilePath(sourceDescriptor, typeMapper, incrementalCache);
784            String sourceFilePath = InlineCodegenUtilsKt.getSourceFilePath(targetDescriptor);
785            incrementalCache.registerInline(classFilePath, jvmSignature.toString(), sourceFilePath);
786        }
787    
788        @Override
789        public void reorderArgumentsIfNeeded(
790                @NotNull List<ArgumentAndDeclIndex> actualArgsWithDeclIndex, @NotNull List<? extends Type> valueParameterTypes
791        ) {
792    
793        }
794    }