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