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