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.PackageClassUtils;
034    import org.jetbrains.kotlin.name.ClassId;
035    import org.jetbrains.kotlin.psi.*;
036    import org.jetbrains.kotlin.renderer.DescriptorRenderer;
037    import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
038    import org.jetbrains.kotlin.resolve.DescriptorUtils;
039    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
040    import org.jetbrains.kotlin.resolve.inline.InlineStrategy;
041    import org.jetbrains.kotlin.resolve.inline.InlineUtil;
042    import org.jetbrains.kotlin.resolve.jvm.AsmTypes;
043    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterKind;
044    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodParameterSignature;
045    import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
046    import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor;
047    import org.jetbrains.org.objectweb.asm.Label;
048    import org.jetbrains.org.objectweb.asm.MethodVisitor;
049    import org.jetbrains.org.objectweb.asm.Opcodes;
050    import org.jetbrains.org.objectweb.asm.Type;
051    import org.jetbrains.org.objectweb.asm.commons.Method;
052    import org.jetbrains.org.objectweb.asm.tree.AbstractInsnNode;
053    import org.jetbrains.org.objectweb.asm.tree.LabelNode;
054    import org.jetbrains.org.objectweb.asm.tree.MethodNode;
055    
056    import java.io.IOException;
057    import java.util.*;
058    
059    import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags;
060    import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
061    import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.CLASS_FOR_SCRIPT;
062    import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
063    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionLiteral;
064    import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCallWithAssert;
065    
066    public class InlineCodegen extends CallGenerator {
067        private final GenerationState state;
068        private final JetTypeMapper typeMapper;
069    
070        private final SimpleFunctionDescriptor functionDescriptor;
071        private final JvmMethodSignature jvmSignature;
072        private final JetElement callElement;
073        private final MethodContext context;
074        private final ExpressionCodegen codegen;
075    
076        private final boolean asFunctionInline;
077        private final int initialFrameSize;
078        private final boolean isSameModule;
079    
080        protected final ParametersBuilder invocationParamBuilder = ParametersBuilder.newBuilder();
081        protected final Map<Integer, LambdaInfo> expressionMap = new HashMap<Integer, LambdaInfo>();
082    
083        private final ReifiedTypeInliner reifiedTypeInliner;
084    
085        private LambdaInfo activeLambda;
086    
087        private final SourceMapper sourceMapper;
088    
089        public InlineCodegen(
090                @NotNull ExpressionCodegen codegen,
091                @NotNull GenerationState state,
092                @NotNull SimpleFunctionDescriptor functionDescriptor,
093                @NotNull JetElement callElement,
094                @Nullable ReifiedTypeParameterMappings typeParameterMappings
095        ) {
096            assert InlineUtil.isInline(functionDescriptor) : "InlineCodegen could inline only inline function: " + functionDescriptor;
097    
098            this.state = state;
099            this.typeMapper = state.getTypeMapper();
100            this.codegen = codegen;
101            this.callElement = callElement;
102            this.functionDescriptor = functionDescriptor.getOriginal();
103    
104            reifiedTypeInliner = new ReifiedTypeInliner(typeParameterMappings);
105    
106            initialFrameSize = codegen.getFrameMap().getCurrentSize();
107    
108            context = (MethodContext) getContext(functionDescriptor, state);
109            jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind());
110    
111            // TODO: implement AS_FUNCTION inline strategy
112            InlineStrategy inlineStrategy = InlineUtil.getInlineStrategy(functionDescriptor);
113            this.asFunctionInline = false;
114    
115            isSameModule = JvmCodegenUtil.isCallInsideSameModuleAsDeclared(functionDescriptor, codegen.getContext(), state.getOutDirectory());
116    
117            sourceMapper = codegen.getParentCodegen().getOrCreateSourceMapper();
118        }
119    
120        @Override
121        public void genCallWithoutAssertions(
122                @NotNull CallableMethod callableMethod, @NotNull ExpressionCodegen codegen
123        ) {
124            genCall(callableMethod, null, false, codegen);
125        }
126    
127        @Override
128        public void genCallInner(@NotNull Callable callableMethod, @Nullable ResolvedCall<?> resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen) {
129            SMAPAndMethodNode nodeAndSmap = null;
130            if (!state.getInlineCycleReporter().enterIntoInlining(resolvedCall)) {
131                generateStub(resolvedCall, codegen);
132                return;
133            }
134    
135            try {
136                nodeAndSmap = createMethodNode(callDefault);
137                endCall(inlineCall(nodeAndSmap));
138            }
139            catch (CompilationException e) {
140                throw e;
141            }
142            catch (Exception e) {
143                boolean generateNodeText = !(e instanceof InlineException);
144                PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(this.codegen.getContext().getContextDescriptor());
145                throw new CompilationException("Couldn't inline method call '" +
146                                           functionDescriptor.getName() +
147                                           "' into \n" + (element != null ? element.getText() : "null psi element " + this.codegen.getContext().getContextDescriptor()) +
148                                           (generateNodeText ? ("\ncause: " + InlineCodegenUtil.getNodeText(nodeAndSmap != null ? nodeAndSmap.getNode(): null)) : ""),
149                                           e, callElement);
150            }
151            finally {
152                state.getInlineCycleReporter().exitFromInliningOf(resolvedCall);
153            }
154        }
155    
156        protected void generateStub(@Nullable ResolvedCall<?> resolvedCall, @NotNull ExpressionCodegen codegen) {
157            leaveTemps();
158            assert resolvedCall != null;
159            String message = "Call is part of inline cycle: " + resolvedCall.getCall().getCallElement().getText();
160            AsmUtil.genThrow(codegen.v, "java/lang/UnsupportedOperationException", message);
161        }
162    
163        private void endCall(@NotNull InlineResult result) {
164            leaveTemps();
165    
166            codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages());
167    
168            state.getFactory().removeInlinedClasses(result.getClassesToRemove());
169    
170            codegen.markLineNumberAfterInlineIfNeeded();
171        }
172    
173        @NotNull
174        private SMAPAndMethodNode createMethodNode(boolean callDefault) throws ClassNotFoundException, IOException {
175            JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind());
176    
177            Method asmMethod;
178            if (callDefault) {
179                asmMethod = typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind(), context);
180            }
181            else {
182                asmMethod = jvmSignature.getAsmMethod();
183            }
184    
185            SMAPAndMethodNode nodeAndSMAP;
186            if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) {
187                ClassId containerClassId = InlineCodegenUtil.getContainerClassIdForInlineCallable(
188                        (DeserializedSimpleFunctionDescriptor) functionDescriptor);
189    
190                VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containerClassId, state);
191                if (functionDescriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor) {
192                    /*use facade class*/
193                    containerClassId = PackageClassUtils.getPackageClassId(containerClassId.getPackageFqName());
194                }
195                nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(),
196                                                              asmMethod.getName(),
197                                                              asmMethod.getDescriptor(),
198                                                              containerClassId);
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 JetNamedFunction)) {
208                    throw new RuntimeException("Couldn't find declaration for function " + descriptorName(functionDescriptor));
209                }
210                JetNamedFunction inliningFunction = (JetNamedFunction) 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 ownerType = typeMapper.mapOwner(functionDescriptor, false/*use facade class*/);
226                    FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction,
227                                                                            (FieldOwnerContext) methodContext.getParentContext(),
228                                                                            ownerType.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.totalSize() + 1).value).index);
291    
292            adapter.accept(new InliningInstructionAdapter(codegen.v));
293    
294            addInlineMarker(codegen.v, false);
295    
296            return result;
297        }
298    
299        private void generateClosuresBodies() {
300            for (LambdaInfo info : expressionMap.values()) {
301                info.setNode(generateLambdaBody(info));
302            }
303        }
304    
305        private SMAPAndMethodNode generateLambdaBody(LambdaInfo info) {
306            JetExpression declaration = info.getFunctionWithBodyOrCallableReference();
307            FunctionDescriptor descriptor = info.getFunctionDescriptor();
308    
309            MethodContext parentContext = codegen.getContext();
310    
311            MethodContext context = parentContext.intoClosure(descriptor, codegen, typeMapper).intoInlinedLambda(descriptor);
312    
313            JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(descriptor);
314            Method asmMethod = jvmMethodSignature.getAsmMethod();
315            MethodNode methodNode = new MethodNode(InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), jvmMethodSignature.getGenericsSignature(), null);
316    
317            MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
318    
319            SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true);
320            adapter.visitMaxs(-1, -1);
321            return new SMAPAndMethodNode(methodNode, smap);
322        }
323    
324        private SMAP generateMethodBody(
325                @NotNull MethodVisitor adapter,
326                @NotNull FunctionDescriptor descriptor,
327                @NotNull MethodContext context,
328                @NotNull JetExpression expression,
329                @NotNull JvmMethodSignature jvmMethodSignature,
330                boolean isLambda
331        ) {
332            FakeMemberCodegen parentCodegen =
333                    new FakeMemberCodegen(codegen.getParentCodegen(), expression,
334                                          (FieldOwnerContext) context.getParentContext(),
335                                          isLambda ? codegen.getParentCodegen().getClassName() : typeMapper.mapOwner(descriptor, false).getInternalName());
336    
337            FunctionGenerationStrategy strategy =
338                    expression instanceof JetCallableReferenceExpression ?
339                    new FunctionReferenceGenerationStrategy(
340                            state,
341                            descriptor,
342                            getResolvedCallWithAssert(((JetCallableReferenceExpression) expression).getCallableReference(),
343                                                      codegen.getBindingContext()
344                            )) :
345                    new FunctionGenerationStrategy.FunctionDefault(state, descriptor, (JetDeclarationWithBody) expression);
346    
347            FunctionCodegen.generateMethodBody(
348                    adapter, descriptor, context, jvmMethodSignature,
349                    strategy,
350                    // Wrapping for preventing marking actual parent codegen as containing reifier markers
351                    parentCodegen
352            );
353    
354            return createSMAPWithDefaultMapping(expression, parentCodegen.getOrCreateSourceMapper().getResultMappings());
355        }
356    
357        private static SMAP createSMAPWithDefaultMapping(
358                @NotNull JetExpression declaration,
359                @NotNull List<FileMapping> mappings
360        ) {
361            PsiFile containingFile = declaration.getContainingFile();
362            Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true);
363            assert lineNumbers != null : "Couldn't extract line count in " + containingFile;
364    
365            return new SMAP(mappings);
366        }
367    
368        private static class FakeMemberCodegen extends MemberCodegen {
369    
370            private final MemberCodegen delegate;
371            @NotNull private final String className;
372    
373            public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull JetElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) {
374                super(wrapped, declaration, codegenContext);
375                delegate = wrapped;
376                this.className = className;
377            }
378    
379            @Override
380            protected void generateDeclaration() {
381                throw new IllegalStateException();
382            }
383    
384            @Override
385            protected void generateBody() {
386                throw new IllegalStateException();
387            }
388    
389            @Override
390            protected void generateKotlinAnnotation() {
391                throw new IllegalStateException();
392            }
393    
394            @NotNull
395            @Override
396            public NameGenerator getInlineNameGenerator() {
397                return delegate.getInlineNameGenerator();
398            }
399    
400            @NotNull
401            @Override
402            //TODO: obtain name from context
403            public String getClassName() {
404                return className;
405            }
406        }
407    
408        @Override
409        public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor) {
410            putCapturedInLocal(type, stackValue, valueParameterDescriptor, -1);
411        }
412    
413        private void putCapturedInLocal(
414                @NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor, int capturedParamIndex
415        ) {
416            if (!asFunctionInline && Type.VOID_TYPE != type) {
417                //TODO remap only inlinable closure => otherwise we could get a lot of problem
418                boolean couldBeRemapped = !shouldPutValue(type, stackValue, valueParameterDescriptor);
419                StackValue remappedIndex = couldBeRemapped ? stackValue : null;
420    
421                ParameterInfo info;
422                if (capturedParamIndex >= 0) {
423                    CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex);
424                    info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName());
425                    info.setRemapValue(remappedIndex);
426                }
427                else {
428                    info = invocationParamBuilder.addNextParameter(type, false, remappedIndex);
429                }
430    
431                putParameterOnStack(info);
432            }
433        }
434    
435        /*descriptor is null for captured vars*/
436        public boolean shouldPutValue(
437                @NotNull Type type,
438                @Nullable StackValue stackValue,
439                @Nullable ValueParameterDescriptor descriptor
440        ) {
441    
442            if (stackValue == null) {
443                //default or vararg
444                return true;
445            }
446    
447            //remap only inline functions (and maybe non primitives)
448            //TODO - clean asserion and remapping logic
449            if (isPrimitive(type) != isPrimitive(stackValue.type)) {
450                //don't remap boxing/unboxing primitives - lost identity and perfomance
451                return true;
452            }
453    
454            if (stackValue instanceof StackValue.Local) {
455                return false;
456            }
457    
458            StackValue field = stackValue;
459            if (stackValue instanceof StackValue.FieldForSharedVar) {
460                field = ((StackValue.FieldForSharedVar) stackValue).receiver;
461            }
462    
463            //check that value corresponds to captured inlining parameter
464            if (field instanceof StackValue.Field) {
465                DeclarationDescriptor varDescriptor = ((StackValue.Field) field).descriptor;
466                //check that variable is inline function parameter
467                return !(varDescriptor instanceof ParameterDescriptor &&
468                         InlineUtil.isInlineLambdaParameter((ParameterDescriptor) varDescriptor) &&
469                         InlineUtil.isInline(varDescriptor.getContainingDeclaration()));
470            }
471    
472            return true;
473        }
474    
475        private void putParameterOnStack(ParameterInfo... infos) {
476            int[] index = new int[infos.length];
477            for (int i = 0; i < infos.length; i++) {
478                ParameterInfo info = infos[i];
479                if (!info.isSkippedOrRemapped()) {
480                    index[i] = codegen.getFrameMap().enterTemp(info.getType());
481                }
482                else {
483                    index[i] = -1;
484                }
485            }
486    
487            for (int i = infos.length - 1; i >= 0; i--) {
488                ParameterInfo info = infos[i];
489                if (!info.isSkippedOrRemapped()) {
490                    Type type = info.type;
491                    StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v);
492                }
493            }
494        }
495    
496        @Override
497        public void putHiddenParams() {
498            List<JvmMethodParameterSignature> valueParameters = jvmSignature.getValueParameters();
499    
500            if (!isStaticMethod(functionDescriptor, context)) {
501                invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null);
502            }
503    
504            for (JvmMethodParameterSignature param : valueParameters) {
505                if (param.getKind() == JvmMethodParameterKind.VALUE) {
506                    break;
507                }
508                invocationParamBuilder.addNextParameter(param.getAsmType(), false, null);
509            }
510    
511            List<ParameterInfo> infos = invocationParamBuilder.listNotCaptured();
512            putParameterOnStack(infos.toArray(new ParameterInfo[infos.size()]));
513        }
514    
515        public void leaveTemps() {
516            FrameMap frameMap = codegen.getFrameMap();
517            List<ParameterInfo> infos = invocationParamBuilder.listAllParams();
518            for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) {
519                ParameterInfo param = iterator.previous();
520                if (!param.isSkippedOrRemapped()) {
521                    frameMap.leaveTemp(param.type);
522                }
523            }
524        }
525    
526        /*lambda or callable reference*/
527        public static boolean isInliningParameter(JetExpression expression, ValueParameterDescriptor valueParameterDescriptor) {
528            //TODO deparenthisise typed
529            JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression);
530            return InlineUtil.isInlineLambdaParameter(valueParameterDescriptor) &&
531                   isInlinableParameterExpression(deparenthesized);
532        }
533    
534        protected static boolean isInlinableParameterExpression(JetExpression deparenthesized) {
535            return deparenthesized instanceof JetFunctionLiteralExpression ||
536                   deparenthesized instanceof JetNamedFunction ||
537                   deparenthesized instanceof JetCallableReferenceExpression;
538        }
539    
540        public void rememberClosure(JetExpression expression, Type type) {
541            JetExpression lambda = JetPsiUtil.deparenthesize(expression);
542            assert isInlinableParameterExpression(lambda) : "Couldn't find inline expression in " + expression.getText();
543    
544            LambdaInfo info = new LambdaInfo(lambda, typeMapper);
545    
546            ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null);
547            closureInfo.setLambda(info);
548            expressionMap.put(closureInfo.getIndex(), info);
549        }
550    
551        @NotNull
552        protected static Set<String> getDeclarationLabels(@Nullable PsiElement lambdaOrFun, @NotNull DeclarationDescriptor descriptor) {
553            Set<String> result = new HashSet<String>();
554            if (lambdaOrFun != null) {
555                PsiElement parent = lambdaOrFun.getParent();
556                if (parent instanceof JetLabeledExpression) {
557                    String labelName = ((JetLabeledExpression) parent).getLabelName();
558                    assert labelName != null : "Labeled expression should have not nul label " + parent.getText();
559                    result.add(labelName);
560                }
561            }
562            if (!isFunctionLiteral(descriptor)) {
563                if (!descriptor.getName().isSpecial()) {
564                    result.add(descriptor.getName().asString());
565                }
566                result.add(InlineCodegenUtil.FIRST_FUN_LABEL);
567            }
568            return result;
569        }
570    
571        private void putClosureParametersOnStack() {
572            for (LambdaInfo next : expressionMap.values()) {
573                activeLambda = next;
574                codegen.pushClosureOnStack(next.getClassDescriptor(), true, this);
575            }
576            activeLambda = null;
577        }
578    
579        public static CodegenContext getContext(DeclarationDescriptor descriptor, GenerationState state) {
580            if (descriptor instanceof PackageFragmentDescriptor) {
581                return new PackageContext((PackageFragmentDescriptor) descriptor, null, null);
582            }
583    
584            CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state);
585    
586            if (descriptor instanceof ClassDescriptor) {
587                OwnerKind kind = DescriptorUtils.isTrait(descriptor) ? OwnerKind.TRAIT_IMPL : OwnerKind.IMPLEMENTATION;
588                return parent.intoClass((ClassDescriptor) descriptor, kind, state);
589            }
590            else if (descriptor instanceof ScriptDescriptor) {
591                ClassDescriptor classDescriptorForScript = state.getBindingContext().get(CLASS_FOR_SCRIPT, (ScriptDescriptor) descriptor);
592                assert classDescriptorForScript != null : "Can't find class for script: " + descriptor;
593                List<ScriptDescriptor> earlierScripts = state.getEarlierScriptsForReplInterpreter();
594                return parent.intoScript((ScriptDescriptor) descriptor,
595                                         earlierScripts == null ? Collections.emptyList() : earlierScripts,
596                                         classDescriptorForScript);
597            }
598            else if (descriptor instanceof FunctionDescriptor) {
599                return parent.intoFunction((FunctionDescriptor) descriptor);
600            }
601    
602            throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor));
603        }
604    
605        private static boolean isStaticMethod(FunctionDescriptor functionDescriptor, MethodContext context) {
606            return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0;
607        }
608    
609        private static String descriptorName(DeclarationDescriptor descriptor) {
610            return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
611        }
612    
613        @Override
614        public void genValueAndPut(
615                @NotNull ValueParameterDescriptor valueParameterDescriptor,
616                @NotNull JetExpression argumentExpression,
617                @NotNull Type parameterType
618        ) {
619            if (isInliningParameter(argumentExpression, valueParameterDescriptor)) {
620                rememberClosure(argumentExpression, parameterType);
621            }
622            else {
623                StackValue value = codegen.gen(argumentExpression);
624                putValueIfNeeded(valueParameterDescriptor, parameterType, value);
625            }
626        }
627    
628        @Override
629        public void putValueIfNeeded(@Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value) {
630            if (shouldPutValue(parameterType, value, valueParameterDescriptor)) {
631                value.put(parameterType, codegen.v);
632            }
633            afterParameterPut(parameterType, value, valueParameterDescriptor);
634        }
635    
636        @Override
637        public void putCapturedValueOnStack(
638                @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex
639        ) {
640            if (shouldPutValue(stackValue.type, stackValue, null)) {
641                stackValue.put(stackValue.type, codegen.v);
642            }
643            putCapturedInLocal(stackValue.type, stackValue, null, paramIndex);
644        }
645    
646    
647        public void generateAndInsertFinallyBlocks(
648                MethodNode intoNode,
649                List<MethodInliner.PointForExternalFinallyBlocks> insertPoints,
650                int offsetForFinallyLocalVar
651        ) {
652            if (!codegen.hasFinallyBlocks()) return;
653    
654            Map<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks> extensionPoints =
655                    new HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>();
656            for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) {
657                extensionPoints.put(insertPoint.beforeIns, insertPoint);
658            }
659    
660            DefaultProcessor processor = new DefaultProcessor(intoNode, offsetForFinallyLocalVar);
661    
662            AbstractInsnNode curInstr = intoNode.instructions.getFirst();
663            while (curInstr != null) {
664                processor.processInstruction(curInstr, true);
665    
666                MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
667                if (extension != null) {
668                    Label start = new Label();
669                    Label end = new Label();
670    
671                    MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode();
672                    finallyNode.visitLabel(start);
673    
674                    ExpressionCodegen finallyCodegen =
675                            new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(),
676                                                  codegen.getContext(), codegen.getState(), codegen.getParentCodegen());
677                    finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements());
678    
679                    FrameMap frameMap = finallyCodegen.getFrameMap();
680                    FrameMap.Mark mark = frameMap.mark();
681                    while (frameMap.getCurrentSize() < processor.getNextFreeLocalIndex()) {
682                        frameMap.enterTemp(Type.INT_TYPE);
683                    }
684    
685                    finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType);
686                    finallyNode.visitLabel(end);
687                    //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
688                    InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr);
689    
690                    SimpleInterval splitBy = new SimpleInterval((LabelNode) start.info, (LabelNode) end.info);
691                    processor.getTryBlocksMetaInfo().splitCurrentIntervals(splitBy, false);
692    
693                    processor.getLocalVarsMetaInfo().splitCurrentIntervals(splitBy, false);
694    
695                    mark.dropTo();
696                }
697    
698                curInstr = curInstr.getNext();
699            }
700    
701            processor.substituteTryBlockNodes(intoNode);
702    
703            //processor.substituteLocalVarTable(intoNode);
704        }
705    
706        private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) {
707            return new NestedSourceMapper(sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
708        }
709    
710    }