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