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.builtins.InlineStrategy;
026    import org.jetbrains.kotlin.builtins.InlineUtil;
027    import org.jetbrains.kotlin.codegen.*;
028    import org.jetbrains.kotlin.codegen.context.CodegenContext;
029    import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
030    import org.jetbrains.kotlin.codegen.context.MethodContext;
031    import org.jetbrains.kotlin.codegen.context.PackageContext;
032    import org.jetbrains.kotlin.codegen.state.GenerationState;
033    import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
034    import org.jetbrains.kotlin.descriptors.*;
035    import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
036    import org.jetbrains.kotlin.name.ClassId;
037    import org.jetbrains.kotlin.psi.*;
038    import org.jetbrains.kotlin.renderer.DescriptorRenderer;
039    import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
040    import org.jetbrains.kotlin.resolve.DescriptorUtils;
041    import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
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    import org.jetbrains.org.objectweb.asm.tree.TryCatchBlockNode;
056    
057    import java.io.IOException;
058    import java.util.*;
059    
060    import static org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags;
061    import static org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive;
062    import static org.jetbrains.kotlin.codegen.inline.InlineCodegenUtil.addInlineMarker;
063    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionExpression;
064    import static org.jetbrains.kotlin.resolve.DescriptorUtils.isFunctionLiteral;
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 functionDescriptor.getInlineStrategy().isInline() : "InlineCodegen could inline only inline function but " + 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            InlineStrategy inlineStrategy =
112                    codegen.getContext().isInlineFunction() ? InlineStrategy.IN_PLACE : functionDescriptor.getInlineStrategy();
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 CallableMethod callableMethod, @Nullable ResolvedCall<?> resolvedCall, boolean callDefault, @NotNull ExpressionCodegen codegen) {
129            SMAPAndMethodNode nodeAndSmap = null;
130    
131            try {
132                nodeAndSmap = createMethodNode(callDefault);
133                endCall(inlineCall(nodeAndSmap));
134            }
135            catch (CompilationException e) {
136                throw e;
137            }
138            catch (Exception e) {
139                boolean generateNodeText = !(e instanceof InlineException);
140                PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(this.codegen.getContext().getContextDescriptor());
141                throw new CompilationException("Couldn't inline method call '" +
142                                           functionDescriptor.getName() +
143                                           "' into \n" + (element != null ? element.getText() : "null psi element " + this.codegen.getContext().getContextDescriptor()) +
144                                           (generateNodeText ? ("\ncause: " + InlineCodegenUtil.getNodeText(nodeAndSmap != null ? nodeAndSmap.getNode(): null)) : ""),
145                                           e, callElement);
146            }
147    
148    
149        }
150    
151        private void endCall(@NotNull InlineResult result) {
152            leaveTemps();
153    
154            codegen.propagateChildReifiedTypeParametersUsages(result.getReifiedTypeParametersUsages());
155    
156            state.getFactory().removeInlinedClasses(result.getClassesToRemove());
157        }
158    
159        @NotNull
160        private SMAPAndMethodNode createMethodNode(boolean callDefault) throws ClassNotFoundException, IOException {
161            JvmMethodSignature jvmSignature = typeMapper.mapSignature(functionDescriptor, context.getContextKind());
162    
163            Method asmMethod;
164            if (callDefault) {
165                asmMethod = typeMapper.mapDefaultMethod(functionDescriptor, context.getContextKind(), context);
166            }
167            else {
168                asmMethod = jvmSignature.getAsmMethod();
169            }
170    
171            SMAPAndMethodNode nodeAndSMAP;
172            if (functionDescriptor instanceof DeserializedSimpleFunctionDescriptor) {
173                ClassId containerClassId = InlineCodegenUtil.getContainerClassIdForInlineCallable(
174                        (DeserializedSimpleFunctionDescriptor) functionDescriptor);
175    
176                VirtualFile file = InlineCodegenUtil.getVirtualFileForCallable(containerClassId, state);
177                if (functionDescriptor.getContainingDeclaration() instanceof PackageFragmentDescriptor) {
178                    /*use facade class*/
179                    containerClassId = PackageClassUtils.getPackageClassId(containerClassId.getPackageFqName());
180                }
181                nodeAndSMAP = InlineCodegenUtil.getMethodNode(file.contentsToByteArray(),
182                                                              asmMethod.getName(),
183                                                              asmMethod.getDescriptor(),
184                                                              containerClassId);
185    
186                if (nodeAndSMAP == null) {
187                    throw new RuntimeException("Couldn't obtain compiled function body for " + descriptorName(functionDescriptor));
188                }
189            }
190            else {
191                PsiElement element = DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor);
192    
193                if (element == null || !(element instanceof JetNamedFunction)) {
194                    throw new RuntimeException("Couldn't find declaration for function " + descriptorName(functionDescriptor));
195                }
196                JetNamedFunction inliningFunction = (JetNamedFunction) element;
197    
198                MethodNode node = new MethodNode(InlineCodegenUtil.API,
199                                               getMethodAsmFlags(functionDescriptor, context.getContextKind()) | (callDefault ? Opcodes.ACC_STATIC : 0),
200                                               asmMethod.getName(),
201                                               asmMethod.getDescriptor(),
202                                               jvmSignature.getGenericsSignature(),
203                                               null);
204    
205                //for maxLocals calculation
206                MethodVisitor maxCalcAdapter = InlineCodegenUtil.wrapWithMaxLocalCalc(node);
207                MethodContext methodContext = context.getParentContext().intoFunction(functionDescriptor);
208    
209                SMAP smap;
210                if (callDefault) {
211                    Type ownerType = typeMapper.mapOwner(functionDescriptor, false/*use facade class*/);
212                    FakeMemberCodegen parentCodegen = new FakeMemberCodegen(codegen.getParentCodegen(), inliningFunction,
213                                                                            (FieldOwnerContext) methodContext.getParentContext(),
214                                                                            ownerType.getInternalName());
215                    FunctionCodegen.generateDefaultImplBody(
216                            methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
217                            inliningFunction, parentCodegen
218                    );
219                    smap = createSMAPWithDefaultMapping(inliningFunction, parentCodegen.getOrCreateSourceMapper().getResultMappings());
220                }
221                else {
222                    smap = generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, inliningFunction, jvmSignature, false);
223                }
224    
225                nodeAndSMAP = new SMAPAndMethodNode(node, smap);
226                maxCalcAdapter.visitMaxs(-1, -1);
227                maxCalcAdapter.visitEnd();
228            }
229            return nodeAndSMAP;
230        }
231    
232        private InlineResult inlineCall(SMAPAndMethodNode nodeAndSmap) {
233            MethodNode node = nodeAndSmap.getNode();
234            ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node.instructions);
235            generateClosuresBodies();
236    
237            //through generation captured parameters will be added to invocationParamBuilder
238            putClosureParametersOnStack();
239    
240            addInlineMarker(codegen.v, true);
241    
242            Parameters parameters = invocationParamBuilder.buildParameters();
243    
244            InliningContext info = new RootInliningContext(expressionMap,
245                                                           state,
246                                                           codegen.getInlineNameGenerator()
247                                                                   .subGenerator(functionDescriptor.getName().asString()),
248                                                           codegen.getContext(),
249                                                           callElement,
250                                                           codegen.getParentCodegen().getClassName(), reifiedTypeInliner);
251    
252            MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule,
253                                                      "Method inlining " + callElement.getText(),
254                                                      createNestedSourceMapper(nodeAndSmap)); //with captured
255    
256            LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize);
257    
258    
259            MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode();
260            //hack to keep linenumber info, otherwise jdi will skip begin of linenumber chain
261            adapter.visitInsn(Opcodes.NOP);
262    
263            InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL);
264            result.getReifiedTypeParametersUsages().mergeAll(reificationResult);
265    
266            LabelOwner labelOwner = new LabelOwner() {
267    
268                final CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor();
269    
270                final boolean isLambda = isFunctionExpression(descriptor) || isFunctionLiteral(descriptor);
271    
272                @Override
273                public boolean isMyLabel(@NotNull String name) {
274                    if (InlineCodegenUtil.ROOT_LABEL.equals(name)) {
275                        return !isLambda;
276                    }
277                    else {
278                        return descriptor.getName().asString().equals(name);
279                    }
280                }
281            };
282            List<MethodInliner.PointForExternalFinallyBlocks> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
283            generateAndInsertFinallyBlocks(adapter, infos);
284    
285            adapter.accept(new InliningInstructionAdapter(codegen.v));
286    
287            addInlineMarker(codegen.v, false);
288    
289            return result;
290        }
291    
292        private void generateClosuresBodies() {
293            for (LambdaInfo info : expressionMap.values()) {
294                info.setNode(generateLambdaBody(info));
295            }
296        }
297    
298        private SMAPAndMethodNode generateLambdaBody(LambdaInfo info) {
299            JetFunctionLiteral declaration = info.getFunctionLiteral();
300            FunctionDescriptor descriptor = info.getFunctionDescriptor();
301    
302            MethodContext parentContext = codegen.getContext();
303    
304            MethodContext context = parentContext.intoClosure(descriptor, codegen, typeMapper).intoInlinedLambda(descriptor);
305    
306            JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(descriptor);
307            Method asmMethod = jvmMethodSignature.getAsmMethod();
308            MethodNode methodNode = new MethodNode(InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), jvmMethodSignature.getGenericsSignature(), null);
309    
310            MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
311    
312            SMAP smap = generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature, true);
313            adapter.visitMaxs(-1, -1);
314            return new SMAPAndMethodNode(methodNode, smap);
315        }
316    
317        private SMAP generateMethodBody(
318                @NotNull MethodVisitor adapter,
319                @NotNull FunctionDescriptor descriptor,
320                @NotNull MethodContext context,
321                @NotNull JetDeclarationWithBody declaration,
322                @NotNull JvmMethodSignature jvmMethodSignature,
323                boolean isLambda
324        ) {
325            FakeMemberCodegen parentCodegen =
326                    new FakeMemberCodegen(codegen.getParentCodegen(), declaration,
327                                          (FieldOwnerContext) context.getParentContext(),
328                                          isLambda ? codegen.getParentCodegen().getClassName() : typeMapper.mapOwner(descriptor, false).getInternalName());
329    
330            FunctionCodegen.generateMethodBody(
331                    adapter, descriptor, context, jvmMethodSignature,
332                    new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration),
333                    // Wrapping for preventing marking actual parent codegen as containing reifier markers
334                    parentCodegen
335            );
336    
337            return createSMAPWithDefaultMapping(declaration, parentCodegen.getOrCreateSourceMapper().getResultMappings());
338        }
339    
340        private static SMAP createSMAPWithDefaultMapping(
341                @NotNull JetDeclarationWithBody declaration,
342                @NotNull List<FileMapping> mappings
343        ) {
344            PsiFile containingFile = declaration.getContainingFile();
345            Integer lineNumbers = CodegenUtil.getLineNumberForElement(containingFile, true);
346            assert lineNumbers != null : "Couldn't extract line count in " + containingFile;
347    
348            return new SMAP(mappings);
349        }
350    
351        private static class FakeMemberCodegen extends MemberCodegen {
352    
353            private final MemberCodegen delegate;
354            @NotNull private final String className;
355    
356            public FakeMemberCodegen(@NotNull MemberCodegen wrapped, @NotNull JetElement declaration, @NotNull FieldOwnerContext codegenContext, @NotNull String className) {
357                super(wrapped, declaration, codegenContext);
358                delegate = wrapped;
359                this.className = className;
360            }
361    
362            @Override
363            protected void generateDeclaration() {
364                throw new IllegalStateException();
365            }
366    
367            @Override
368            protected void generateBody() {
369                throw new IllegalStateException();
370            }
371    
372            @Override
373            protected void generateKotlinAnnotation() {
374                throw new IllegalStateException();
375            }
376    
377            @NotNull
378            @Override
379            public NameGenerator getInlineNameGenerator() {
380                return delegate.getInlineNameGenerator();
381            }
382    
383            @NotNull
384            @Override
385            //TODO: obtain name from context
386            public String getClassName() {
387                return className;
388            }
389        }
390    
391        @Override
392        public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor) {
393            putCapturedInLocal(type, stackValue, valueParameterDescriptor, -1);
394        }
395    
396        private void putCapturedInLocal(
397                @NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor, int capturedParamIndex
398        ) {
399            if (!asFunctionInline && Type.VOID_TYPE != type) {
400                //TODO remap only inlinable closure => otherwise we could get a lot of problem
401                boolean couldBeRemapped = !shouldPutValue(type, stackValue, valueParameterDescriptor);
402                StackValue remappedIndex = couldBeRemapped ? stackValue : null;
403    
404                ParameterInfo info;
405                if (capturedParamIndex >= 0) {
406                    CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex);
407                    info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName());
408                    info.setRemapValue(remappedIndex);
409                }
410                else {
411                    info = invocationParamBuilder.addNextParameter(type, false, remappedIndex);
412                }
413    
414                putParameterOnStack(info);
415            }
416        }
417    
418        /*descriptor is null for captured vars*/
419        public boolean shouldPutValue(
420                @NotNull Type type,
421                @Nullable StackValue stackValue,
422                @Nullable ValueParameterDescriptor descriptor
423        ) {
424    
425            if (stackValue == null) {
426                //default or vararg
427                return true;
428            }
429    
430            //remap only inline functions (and maybe non primitives)
431            //TODO - clean asserion and remapping logic
432            if (isPrimitive(type) != isPrimitive(stackValue.type)) {
433                //don't remap boxing/unboxing primitives - lost identity and perfomance
434                return true;
435            }
436    
437            if (stackValue instanceof StackValue.Local) {
438                return false;
439            }
440    
441            //skip direct capturing fields
442            StackValue receiver = null;
443            if (stackValue instanceof StackValue.Field) {
444                receiver = ((StackValue.Field) stackValue).receiver;
445            }
446            else if (stackValue instanceof StackValue.FieldForSharedVar) {
447                receiver = ((StackValue.Field) ((StackValue.FieldForSharedVar) stackValue).receiver).receiver;
448            }
449    
450            if (!(receiver instanceof StackValue.Local)) {
451                return true;
452            }
453    
454            //TODO: check type of context
455            return !(codegen.getContext().isInliningLambda() && descriptor != null && !InlineUtil.hasNoinlineAnnotation(descriptor));
456        }
457    
458        private void putParameterOnStack(ParameterInfo... infos) {
459            int[] index = new int[infos.length];
460            for (int i = 0; i < infos.length; i++) {
461                ParameterInfo info = infos[i];
462                if (!info.isSkippedOrRemapped()) {
463                    index[i] = codegen.getFrameMap().enterTemp(info.getType());
464                }
465                else {
466                    index[i] = -1;
467                }
468            }
469    
470            for (int i = infos.length - 1; i >= 0; i--) {
471                ParameterInfo info = infos[i];
472                if (!info.isSkippedOrRemapped()) {
473                    Type type = info.type;
474                    StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v);
475                }
476            }
477        }
478    
479        @Override
480        public void putHiddenParams() {
481            List<JvmMethodParameterSignature> valueParameters = jvmSignature.getValueParameters();
482    
483            if (!isStaticMethod(functionDescriptor, context)) {
484                invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null);
485            }
486    
487            for (JvmMethodParameterSignature param : valueParameters) {
488                if (param.getKind() == JvmMethodParameterKind.VALUE) {
489                    break;
490                }
491                invocationParamBuilder.addNextParameter(param.getAsmType(), false, null);
492            }
493    
494            List<ParameterInfo> infos = invocationParamBuilder.listNotCaptured();
495            putParameterOnStack(infos.toArray(new ParameterInfo[infos.size()]));
496        }
497    
498        public void leaveTemps() {
499            FrameMap frameMap = codegen.getFrameMap();
500            List<ParameterInfo> infos = invocationParamBuilder.listAllParams();
501            for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) {
502                ParameterInfo param = iterator.previous();
503                if (!param.isSkippedOrRemapped()) {
504                    frameMap.leaveTemp(param.type);
505                }
506            }
507        }
508    
509        public static boolean isInliningClosure(JetExpression expression, ValueParameterDescriptor valueParameterDescriptora) {
510            //TODO deparenthisise typed
511            JetExpression deparenthesize = JetPsiUtil.deparenthesize(expression);
512            return deparenthesize instanceof JetFunctionLiteralExpression &&
513                   !InlineUtil.hasNoinlineAnnotation(valueParameterDescriptora);
514        }
515    
516        public void rememberClosure(JetExpression expression, Type type) {
517            JetFunctionLiteralExpression lambda = (JetFunctionLiteralExpression) JetPsiUtil.deparenthesize(expression);
518            assert lambda != null : "Couldn't find lambda in " + expression.getText();
519    
520            String labelNameIfPresent = null;
521            PsiElement parent = lambda.getParent();
522            if (parent instanceof JetLabeledExpression) {
523                labelNameIfPresent = ((JetLabeledExpression) parent).getLabelName();
524            }
525            LambdaInfo info = new LambdaInfo(lambda, typeMapper, labelNameIfPresent);
526    
527            ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null);
528            closureInfo.setLambda(info);
529            expressionMap.put(closureInfo.getIndex(), info);
530        }
531    
532        private void putClosureParametersOnStack() {
533            for (LambdaInfo next : expressionMap.values()) {
534                activeLambda = next;
535                codegen.pushClosureOnStack(next.getClassDescriptor(), true, this);
536            }
537            activeLambda = null;
538        }
539    
540        public static CodegenContext getContext(DeclarationDescriptor descriptor, GenerationState state) {
541            if (descriptor instanceof PackageFragmentDescriptor) {
542                return new PackageContext((PackageFragmentDescriptor) descriptor, null, null);
543            }
544    
545            CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state);
546    
547            if (descriptor instanceof ClassDescriptor) {
548                OwnerKind kind = DescriptorUtils.isTrait(descriptor) ? OwnerKind.TRAIT_IMPL : OwnerKind.IMPLEMENTATION;
549                return parent.intoClass((ClassDescriptor) descriptor, kind, state);
550            }
551            else if (descriptor instanceof FunctionDescriptor) {
552                return parent.intoFunction((FunctionDescriptor) descriptor);
553            }
554    
555            throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor));
556        }
557    
558        private static boolean isStaticMethod(FunctionDescriptor functionDescriptor, MethodContext context) {
559            return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0;
560        }
561    
562        private static String descriptorName(DeclarationDescriptor descriptor) {
563            return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
564        }
565    
566        @Override
567        public void genValueAndPut(
568                @NotNull ValueParameterDescriptor valueParameterDescriptor,
569                @NotNull JetExpression argumentExpression,
570                @NotNull Type parameterType
571        ) {
572            //TODO deparenthisise
573            if (isInliningClosure(argumentExpression, valueParameterDescriptor)) {
574                rememberClosure(argumentExpression, parameterType);
575            } else {
576                StackValue value = codegen.gen(argumentExpression);
577                putValueIfNeeded(valueParameterDescriptor, parameterType, value);
578            }
579        }
580    
581        @Override
582        public void putValueIfNeeded(@Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value) {
583            if (shouldPutValue(parameterType, value, valueParameterDescriptor)) {
584                value.put(parameterType, codegen.v);
585            }
586            afterParameterPut(parameterType, value, valueParameterDescriptor);
587        }
588    
589        @Override
590        public void putCapturedValueOnStack(
591                @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex
592        ) {
593            if (shouldPutValue(stackValue.type, stackValue, null)) {
594                stackValue.put(stackValue.type, codegen.v);
595            }
596            putCapturedInLocal(stackValue.type, stackValue, null, paramIndex);
597        }
598    
599    
600        public void generateAndInsertFinallyBlocks(MethodNode intoNode, List<MethodInliner.PointForExternalFinallyBlocks> insertPoints) {
601            if (!codegen.hasFinallyBlocks()) return;
602    
603            Map<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks> extensionPoints =
604                    new HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>();
605            for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) {
606                extensionPoints.put(insertPoint.beforeIns, insertPoint);
607            }
608    
609            DefaultProcessor processor = new DefaultProcessor(intoNode);
610    
611            AbstractInsnNode curInstr = intoNode.instructions.getFirst();
612            while (curInstr != null) {
613                processor.updateCoveringTryBlocks(curInstr, true);
614    
615                MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
616                if (extension != null) {
617                    Label start = new Label();
618                    Label end = new Label();
619    
620                    MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode();
621                    finallyNode.visitLabel(start);
622    
623                    ExpressionCodegen finallyCodegen =
624                            new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(),
625                                                  codegen.getContext(), codegen.getState(), codegen.getParentCodegen());
626                    finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements());
627    
628                    finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType);
629                    finallyNode.visitLabel(end);
630    
631                    //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
632                    InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr);
633    
634                    List<TryCatchBlockNodeWrapper> blocks = processor.getCoveringFromInnermost();
635                    ListIterator<TryCatchBlockNodeWrapper> iterator = blocks.listIterator(blocks.size());
636                    while (iterator.hasPrevious()) {
637                        TryCatchBlockNodeWrapper previous = iterator.previous();
638                        LabelNode oldStart = previous.getStartLabel();
639                        TryCatchBlockNode node = previous.getNode();
640                        node.start = (LabelNode) end.info;
641                        processor.remapStartLabel(oldStart, previous);
642    
643                        TryCatchBlockNode additionalNode = new TryCatchBlockNode(oldStart, (LabelNode) start.info, node.handler, node.type);
644                        processor.addNode(additionalNode);
645                    }
646                }
647    
648                curInstr = curInstr.getNext();
649            }
650    
651            processor.sortTryCatchBlocks();
652            Iterable<TryCatchBlockNodeWrapper> nodes = processor.getNonEmptyNodes();
653            intoNode.tryCatchBlocks.clear();
654            for (TryCatchBlockNodeWrapper node : nodes) {
655                intoNode.tryCatchBlocks.add(node.getNode());
656            }
657        }
658    
659        private SourceMapper createNestedSourceMapper(@NotNull SMAPAndMethodNode nodeAndSmap) {
660            return new NestedSourceMapper(sourceMapper, nodeAndSmap.getRanges(), nodeAndSmap.getClassSMAP().getSourceInfo());
661        }
662    
663    }