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