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