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