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                if (callDefault) {
191                    FunctionCodegen.generateDefaultImplBody(
192                            methodContext, functionDescriptor, maxCalcAdapter, DefaultParameterValueLoader.DEFAULT,
193                            (JetNamedFunction) element, codegen.getParentCodegen()
194                    );
195                }
196                else {
197                    generateMethodBody(maxCalcAdapter, functionDescriptor, methodContext, (JetDeclarationWithBody) element, jvmSignature);
198                }
199                maxCalcAdapter.visitMaxs(-1, -1);
200                maxCalcAdapter.visitEnd();
201            }
202            return node;
203        }
204    
205        private InlineResult inlineCall(MethodNode node) {
206            ReifiedTypeParametersUsages reificationResult = reifiedTypeInliner.reifyInstructions(node.instructions);
207            generateClosuresBodies();
208    
209            //through generation captured parameters will be added to invocationParamBuilder
210            putClosureParametersOnStack();
211    
212            addInlineMarker(codegen.v, true);
213    
214            Parameters parameters = invocationParamBuilder.buildParameters();
215    
216            InliningContext info = new RootInliningContext(expressionMap,
217                                                           state,
218                                                           codegen.getInlineNameGenerator()
219                                                                   .subGenerator(functionDescriptor.getName().asString()),
220                                                           codegen.getContext(),
221                                                           callElement,
222                                                           codegen.getParentCodegen().getClassName(), reifiedTypeInliner);
223    
224            MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule, "Method inlining " + callElement.getText()); //with captured
225    
226            LocalVarRemapper remapper = new LocalVarRemapper(parameters, initialFrameSize);
227    
228    
229            MethodNode adapter = InlineCodegenUtil.createEmptyMethodNode();
230            InlineResult result = inliner.doInline(adapter, remapper, true, LabelOwner.SKIP_ALL);
231            result.getReifiedTypeParametersUsages().mergeAll(reificationResult);
232    
233            LabelOwner labelOwner = new LabelOwner() {
234    
235                final CallableMemberDescriptor descriptor = codegen.getContext().getContextDescriptor();
236    
237                final boolean isLambda = CodegenBinding.isLocalFunOrLambda(descriptor) && descriptor.getName().isSpecial();
238    
239                @Override
240                public boolean isMyLabel(@NotNull String name) {
241                    if (InlineCodegenUtil.ROOT_LABEL.equals(name)) {
242                        return !isLambda;
243                    }
244                    else {
245                        return descriptor.getName().asString().equals(name);
246                    }
247                }
248            };
249            List<MethodInliner.PointForExternalFinallyBlocks> infos = MethodInliner.processReturns(adapter, labelOwner, true, null);
250            generateAndInsertFinallyBlocks(adapter, infos);
251    
252            adapter.accept(new InliningInstructionAdapter(codegen.v));
253    
254            addInlineMarker(codegen.v, false);
255    
256            return result;
257        }
258    
259        private void generateClosuresBodies() {
260            for (LambdaInfo info : expressionMap.values()) {
261                info.setNode(generateLambdaBody(info));
262            }
263        }
264    
265        private MethodNode generateLambdaBody(LambdaInfo info) {
266            JetFunctionLiteral declaration = info.getFunctionLiteral();
267            FunctionDescriptor descriptor = info.getFunctionDescriptor();
268    
269            MethodContext parentContext = codegen.getContext();
270    
271            MethodContext context = parentContext.intoClosure(descriptor, codegen, typeMapper).intoInlinedLambda(descriptor);
272    
273            JvmMethodSignature jvmMethodSignature = typeMapper.mapSignature(descriptor);
274            Method asmMethod = jvmMethodSignature.getAsmMethod();
275            MethodNode methodNode = new MethodNode(InlineCodegenUtil.API, getMethodAsmFlags(descriptor, context.getContextKind()), asmMethod.getName(), asmMethod.getDescriptor(), jvmMethodSignature.getGenericsSignature(), null);
276    
277            MethodVisitor adapter = InlineCodegenUtil.wrapWithMaxLocalCalc(methodNode);
278    
279            generateMethodBody(adapter, descriptor, context, declaration, jvmMethodSignature);
280            adapter.visitMaxs(-1, -1);
281    
282            return methodNode;
283        }
284    
285        private void generateMethodBody(
286                @NotNull MethodVisitor adapter,
287                @NotNull FunctionDescriptor descriptor,
288                @NotNull MethodContext context,
289                @NotNull JetDeclarationWithBody declaration,
290                @NotNull JvmMethodSignature jvmMethodSignature
291        ) {
292            FunctionCodegen.generateMethodBody(
293                adapter, descriptor, context, jvmMethodSignature,
294                new FunctionGenerationStrategy.FunctionDefault(state, descriptor, declaration),
295                // Wrapping for preventing marking actual parent codegen as containing reifier markers
296                new FakeMemberCodegen(codegen.getParentCodegen())
297            );
298        }
299    
300        private static class FakeMemberCodegen extends MemberCodegen {
301            private final MemberCodegen delegate;
302            public FakeMemberCodegen(@NotNull MemberCodegen wrapped) {
303                super(wrapped);
304                delegate = wrapped;
305            }
306    
307            @Override
308            protected void generateDeclaration() {
309                throw new IllegalStateException();
310            }
311    
312            @Override
313            protected void generateBody() {
314                throw new IllegalStateException();
315            }
316    
317            @Override
318            protected void generateKotlinAnnotation() {
319                throw new IllegalStateException();
320            }
321    
322            @NotNull
323            @Override
324            public NameGenerator getInlineNameGenerator() {
325                return delegate.getInlineNameGenerator();
326            }
327        }
328    
329        @Override
330        public void afterParameterPut(@NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor) {
331            putCapturedInLocal(type, stackValue, valueParameterDescriptor, -1);
332        }
333    
334        private void putCapturedInLocal(
335                @NotNull Type type, @Nullable StackValue stackValue, @Nullable ValueParameterDescriptor valueParameterDescriptor, int capturedParamIndex
336        ) {
337            if (!asFunctionInline && Type.VOID_TYPE != type) {
338                //TODO remap only inlinable closure => otherwise we could get a lot of problem
339                boolean couldBeRemapped = !shouldPutValue(type, stackValue, valueParameterDescriptor);
340                StackValue remappedIndex = couldBeRemapped ? stackValue : null;
341    
342                ParameterInfo info;
343                if (capturedParamIndex >= 0) {
344                    CapturedParamDesc capturedParamInfoInLambda = activeLambda.getCapturedVars().get(capturedParamIndex);
345                    info = invocationParamBuilder.addCapturedParam(capturedParamInfoInLambda, capturedParamInfoInLambda.getFieldName());
346                    info.setRemapValue(remappedIndex);
347                }
348                else {
349                    info = invocationParamBuilder.addNextParameter(type, false, remappedIndex);
350                }
351    
352                putParameterOnStack(info);
353            }
354        }
355    
356        /*descriptor is null for captured vars*/
357        public boolean shouldPutValue(
358                @NotNull Type type,
359                @Nullable StackValue stackValue,
360                @Nullable ValueParameterDescriptor descriptor
361        ) {
362    
363            if (stackValue == null) {
364                //default or vararg
365                return true;
366            }
367    
368            //remap only inline functions (and maybe non primitives)
369            //TODO - clean asserion and remapping logic
370            if (isPrimitive(type) != isPrimitive(stackValue.type)) {
371                //don't remap boxing/unboxing primitives - lost identity and perfomance
372                return true;
373            }
374    
375            if (stackValue instanceof StackValue.Local) {
376                return false;
377            }
378    
379            //skip direct capturing fields
380            StackValue receiver = null;
381            if (stackValue instanceof StackValue.Field) {
382                receiver = ((StackValue.Field) stackValue).receiver;
383            }
384            else if (stackValue instanceof StackValue.FieldForSharedVar) {
385                receiver = ((StackValue.Field) ((StackValue.FieldForSharedVar) stackValue).receiver).receiver;
386            }
387    
388            if (!(receiver instanceof StackValue.Local)) {
389                return true;
390            }
391    
392            //TODO: check type of context
393            return !(codegen.getContext().isInliningLambda() && descriptor != null && !InlineUtil.hasNoinlineAnnotation(descriptor));
394        }
395    
396        private void putParameterOnStack(ParameterInfo... infos) {
397            int[] index = new int[infos.length];
398            for (int i = 0; i < infos.length; i++) {
399                ParameterInfo info = infos[i];
400                if (!info.isSkippedOrRemapped()) {
401                    index[i] = codegen.getFrameMap().enterTemp(info.getType());
402                }
403                else {
404                    index[i] = -1;
405                }
406            }
407    
408            for (int i = infos.length - 1; i >= 0; i--) {
409                ParameterInfo info = infos[i];
410                if (!info.isSkippedOrRemapped()) {
411                    Type type = info.type;
412                    StackValue.local(index[i], type).store(StackValue.onStack(type), codegen.v);
413                }
414            }
415        }
416    
417        @Override
418        public void putHiddenParams() {
419            List<JvmMethodParameterSignature> valueParameters = jvmSignature.getValueParameters();
420    
421            if (!isStaticMethod(functionDescriptor, context)) {
422                invocationParamBuilder.addNextParameter(AsmTypes.OBJECT_TYPE, false, null);
423            }
424    
425            for (JvmMethodParameterSignature param : valueParameters) {
426                if (param.getKind() == JvmMethodParameterKind.VALUE) {
427                    break;
428                }
429                invocationParamBuilder.addNextParameter(param.getAsmType(), false, null);
430            }
431    
432            List<ParameterInfo> infos = invocationParamBuilder.listNotCaptured();
433            putParameterOnStack(infos.toArray(new ParameterInfo[infos.size()]));
434        }
435    
436        public void leaveTemps() {
437            FrameMap frameMap = codegen.getFrameMap();
438            List<ParameterInfo> infos = invocationParamBuilder.listAllParams();
439            for (ListIterator<? extends ParameterInfo> iterator = infos.listIterator(infos.size()); iterator.hasPrevious(); ) {
440                ParameterInfo param = iterator.previous();
441                if (!param.isSkippedOrRemapped()) {
442                    frameMap.leaveTemp(param.type);
443                }
444            }
445        }
446    
447        public static boolean isInliningClosure(JetExpression expression, ValueParameterDescriptor valueParameterDescriptora) {
448            //TODO deparenthisise typed
449            JetExpression deparenthesize = JetPsiUtil.deparenthesize(expression);
450            return deparenthesize instanceof JetFunctionLiteralExpression &&
451                   !InlineUtil.hasNoinlineAnnotation(valueParameterDescriptora);
452        }
453    
454        public void rememberClosure(JetExpression expression, Type type) {
455            JetFunctionLiteralExpression lambda = (JetFunctionLiteralExpression) JetPsiUtil.deparenthesize(expression);
456            assert lambda != null : "Couldn't find lambda in " + expression.getText();
457    
458            String labelNameIfPresent = null;
459            PsiElement parent = lambda.getParent();
460            if (parent instanceof JetLabeledExpression) {
461                labelNameIfPresent = ((JetLabeledExpression) parent).getLabelName();
462            }
463            LambdaInfo info = new LambdaInfo(lambda, typeMapper, labelNameIfPresent);
464    
465            ParameterInfo closureInfo = invocationParamBuilder.addNextParameter(type, true, null);
466            closureInfo.setLambda(info);
467            expressionMap.put(closureInfo.getIndex(), info);
468        }
469    
470        private void putClosureParametersOnStack() {
471            for (LambdaInfo next : expressionMap.values()) {
472                activeLambda = next;
473                codegen.pushClosureOnStack(next.getClassDescriptor(), true, this);
474            }
475            activeLambda = null;
476        }
477    
478        public static CodegenContext getContext(DeclarationDescriptor descriptor, GenerationState state) {
479            if (descriptor instanceof PackageFragmentDescriptor) {
480                return new PackageContext((PackageFragmentDescriptor) descriptor, null, null);
481            }
482    
483            CodegenContext parent = getContext(descriptor.getContainingDeclaration(), state);
484    
485            if (descriptor instanceof ClassDescriptor) {
486                OwnerKind kind = DescriptorUtils.isTrait(descriptor) ? OwnerKind.TRAIT_IMPL : OwnerKind.IMPLEMENTATION;
487                return parent.intoClass((ClassDescriptor) descriptor, kind, state);
488            }
489            else if (descriptor instanceof FunctionDescriptor) {
490                return parent.intoFunction((FunctionDescriptor) descriptor);
491            }
492    
493            throw new IllegalStateException("Couldn't build context for " + descriptorName(descriptor));
494        }
495    
496        private static boolean isStaticMethod(FunctionDescriptor functionDescriptor, MethodContext context) {
497            return (getMethodAsmFlags(functionDescriptor, context.getContextKind()) & Opcodes.ACC_STATIC) != 0;
498        }
499    
500        private static String descriptorName(DeclarationDescriptor descriptor) {
501            return DescriptorRenderer.SHORT_NAMES_IN_TYPES.render(descriptor);
502        }
503    
504        @Override
505        public void genValueAndPut(
506                @NotNull ValueParameterDescriptor valueParameterDescriptor,
507                @NotNull JetExpression argumentExpression,
508                @NotNull Type parameterType
509        ) {
510            //TODO deparenthisise
511            if (isInliningClosure(argumentExpression, valueParameterDescriptor)) {
512                rememberClosure(argumentExpression, parameterType);
513            } else {
514                StackValue value = codegen.gen(argumentExpression);
515                putValueIfNeeded(valueParameterDescriptor, parameterType, value);
516            }
517        }
518    
519        @Override
520        public void putValueIfNeeded(@Nullable ValueParameterDescriptor valueParameterDescriptor, @NotNull Type parameterType, @NotNull StackValue value) {
521            if (shouldPutValue(parameterType, value, valueParameterDescriptor)) {
522                value.put(parameterType, codegen.v);
523            }
524            afterParameterPut(parameterType, value, valueParameterDescriptor);
525        }
526    
527        @Override
528        public void putCapturedValueOnStack(
529                @NotNull StackValue stackValue, @NotNull Type valueType, int paramIndex
530        ) {
531            if (shouldPutValue(stackValue.type, stackValue, null)) {
532                stackValue.put(stackValue.type, codegen.v);
533            }
534            putCapturedInLocal(stackValue.type, stackValue, null, paramIndex);
535        }
536    
537    
538        public void generateAndInsertFinallyBlocks(MethodNode intoNode, List<MethodInliner.PointForExternalFinallyBlocks> insertPoints) {
539            if (!codegen.hasFinallyBlocks()) return;
540    
541            Map<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks> extensionPoints =
542                    new HashMap<AbstractInsnNode, MethodInliner.PointForExternalFinallyBlocks>();
543            for (MethodInliner.PointForExternalFinallyBlocks insertPoint : insertPoints) {
544                extensionPoints.put(insertPoint.beforeIns, insertPoint);
545            }
546    
547            DefaultProcessor processor = new DefaultProcessor(intoNode);
548    
549            AbstractInsnNode curInstr = intoNode.instructions.getFirst();
550            while (curInstr != null) {
551                processor.updateCoveringTryBlocks(curInstr, true);
552    
553                MethodInliner.PointForExternalFinallyBlocks extension = extensionPoints.get(curInstr);
554                if (extension != null) {
555                    Label start = new Label();
556                    Label end = new Label();
557    
558                    MethodNode finallyNode = InlineCodegenUtil.createEmptyMethodNode();
559                    finallyNode.visitLabel(start);
560    
561                    ExpressionCodegen finallyCodegen =
562                            new ExpressionCodegen(finallyNode, codegen.getFrameMap(), codegen.getReturnType(),
563                                                  codegen.getContext(), codegen.getState(), codegen.getParentCodegen());
564                    finallyCodegen.addBlockStackElementsForNonLocalReturns(codegen.getBlockStackElements());
565    
566                    finallyCodegen.generateFinallyBlocksIfNeeded(extension.returnType);
567                    finallyNode.visitLabel(end);
568    
569                    //Exception table for external try/catch/finally blocks will be generated in original codegen after exiting this method
570                    InlineCodegenUtil.insertNodeBefore(finallyNode, intoNode, curInstr);
571    
572                    List<TryCatchBlockNodeWrapper> blocks = processor.getCoveringFromInnermost();
573                    ListIterator<TryCatchBlockNodeWrapper> iterator = blocks.listIterator(blocks.size());
574                    while (iterator.hasPrevious()) {
575                        TryCatchBlockNodeWrapper previous = iterator.previous();
576                        LabelNode oldStart = previous.getStartLabel();
577                        TryCatchBlockNode node = previous.getNode();
578                        node.start = (LabelNode) end.info;
579                        processor.remapStartLabel(oldStart, previous);
580    
581                        TryCatchBlockNode additionalNode = new TryCatchBlockNode(oldStart, (LabelNode) start.info, node.handler, node.type);
582                        processor.addNode(additionalNode);
583                    }
584                }
585    
586                curInstr = curInstr.getNext();
587            }
588    
589            processor.sortTryCatchBlocks();
590            Iterable<TryCatchBlockNodeWrapper> nodes = processor.getNonEmptyNodes();
591            intoNode.tryCatchBlocks.clear();
592            for (TryCatchBlockNodeWrapper node : nodes) {
593                intoNode.tryCatchBlocks.add(node.getNode());
594            }
595        }
596    
597    }