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