MethodDefinition.java revision 16a911620ccf7b530b873fb71cf13e8dcb88ad28
1/*
2 * [The "BSD licence"]
3 * Copyright (c) 2009 Ben Gruver
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 *    derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29package org.jf.baksmali.Adaptors;
30
31import org.jf.baksmali.Adaptors.Format.*;
32import org.jf.baksmali.baksmali;
33import org.jf.dexlib.*;
34import org.jf.dexlib.Debug.DebugInstructionIterator;
35import org.jf.dexlib.Code.Format.*;
36import org.jf.dexlib.Code.Instruction;
37import org.jf.dexlib.Code.Opcode;
38import org.jf.dexlib.Code.OffsetInstruction;
39import org.jf.dexlib.Util.AccessFlags;
40import org.antlr.stringtemplate.StringTemplateGroup;
41import org.antlr.stringtemplate.StringTemplate;
42
43import java.util.*;
44
45public class MethodDefinition {
46    public static StringTemplate createTemplate(StringTemplateGroup stg, ClassDataItem.EncodedMethod encodedMethod,
47                                              AnnotationSetItem annotationSet,
48                                              AnnotationSetRefList parameterAnnotations) {
49
50        CodeItem codeItem = encodedMethod.codeItem;
51
52        StringTemplate template = stg.getInstanceOf("method");
53
54        template.setAttribute("AccessFlags", getAccessFlags(encodedMethod));
55        template.setAttribute("MethodName", encodedMethod.method.getMethodName().getStringValue());
56        template.setAttribute("Prototype", encodedMethod.method.getPrototype().getPrototypeString());
57        template.setAttribute("HasCode", codeItem != null);
58        template.setAttribute("RegistersDirective", baksmali.useLocalsDirective?".locals":".registers");
59        template.setAttribute("RegisterCount", codeItem==null?"0":Integer.toString(getRegisterCount(encodedMethod)));
60        template.setAttribute("Parameters", getParameters(stg, codeItem, parameterAnnotations));
61        template.setAttribute("Annotations", getAnnotations(stg, annotationSet));
62        template.setAttribute("MethodItems", getMethodItems(encodedMethod.method.getDexFile(), stg, codeItem));
63
64        return template;
65    }
66
67    private static int getRegisterCount(ClassDataItem.EncodedMethod encodedMethod)
68    {
69        int totalRegisters = encodedMethod.codeItem.getRegisterCount();
70        if (baksmali.useLocalsDirective) {
71            int parameterRegisters = encodedMethod.method.getPrototype().getParameterRegisterCount();
72            if ((encodedMethod.accessFlags & AccessFlags.STATIC.getValue()) == 0) {
73                parameterRegisters++;
74            }
75            return totalRegisters - parameterRegisters;
76        }
77        return totalRegisters;
78    }
79
80    private static List<String> getAccessFlags(ClassDataItem.EncodedMethod encodedMethod) {
81        List<String> accessFlags = new ArrayList<String>();
82
83        for (AccessFlags accessFlag: AccessFlags.getAccessFlagsForMethod(encodedMethod.accessFlags)) {
84            accessFlags.add(accessFlag.toString());
85        }
86
87        return accessFlags;
88    }
89
90    private static List<StringTemplate> getParameters(StringTemplateGroup stg, CodeItem codeItem,
91                                                               AnnotationSetRefList parameterAnnotations) {
92        DebugInfoItem debugInfoItem = null;
93        if (baksmali.outputDebugInfo && codeItem != null) {
94            debugInfoItem = codeItem.getDebugInfo();
95        }
96
97        int parameterCount = 0;
98
99        List<AnnotationSetItem> annotations = new ArrayList<AnnotationSetItem>();
100        if (parameterAnnotations != null) {
101            AnnotationSetItem[] _annotations = parameterAnnotations.getAnnotationSets();
102            if (_annotations != null) {
103                annotations.addAll(Arrays.asList(_annotations));
104            }
105
106            parameterCount = annotations.size();
107        }
108
109        List<String> parameterNames = new ArrayList<String>();
110        if (debugInfoItem != null) {
111            StringIdItem[] _parameterNames = debugInfoItem.getParameterNames();
112            if (_parameterNames != null) {
113                for (StringIdItem parameterName: _parameterNames) {
114                    parameterNames.add(parameterName==null?null:parameterName.getStringValue());
115                }
116            }
117
118            if (parameterCount < parameterNames.size()) {
119                parameterCount = parameterNames.size();
120            }
121        }
122
123        List<StringTemplate> parameters = new ArrayList<StringTemplate>();
124        for (int i=0; i<parameterCount; i++) {
125            AnnotationSetItem annotationSet = null;
126            if (i < annotations.size()) {
127                annotationSet = annotations.get(i);
128            }
129
130            String parameterName = null;
131            if (i < parameterNames.size()) {
132                parameterName = parameterNames.get(i);
133            }
134
135            parameters.add(ParameterAdaptor.createTemplate(stg, parameterName, annotationSet));
136        }
137
138        return parameters;
139    }
140
141    private static List<StringTemplate> getAnnotations(StringTemplateGroup stg, AnnotationSetItem annotationSet) {
142        if (annotationSet == null) {
143            return null;
144        }
145
146        List<StringTemplate> annotationAdaptors = new ArrayList<StringTemplate>();
147
148        for (AnnotationItem annotationItem: annotationSet.getAnnotations()) {
149            annotationAdaptors.add(AnnotationAdaptor.createTemplate(stg, annotationItem));
150        }
151        return annotationAdaptors;
152    }
153
154    private static List<MethodItem> getMethodItems(DexFile dexFile, StringTemplateGroup stg, CodeItem codeItem) {
155        List<MethodItem> methodItems = new ArrayList<MethodItem>();
156
157        MethodItemList methodItemList = new MethodItemList(dexFile, stg, codeItem);
158        methodItemList.generateMethodItemList();
159
160        for (LabelMethodItem labelMethodItem: methodItemList.labels.getLabels()) {
161            if (labelMethodItem.isCommentedOut()) {
162                methodItems.add(new CommentedOutMethodItem(stg, labelMethodItem));
163            } else {
164                methodItems.add(labelMethodItem);
165            }
166        }
167
168        methodItems.addAll(methodItemList.instructions);
169        methodItems.addAll(methodItemList.blanks);
170        methodItems.addAll(methodItemList.catches);
171        if (baksmali.outputDebugInfo) {
172            methodItems.addAll(methodItemList.debugItems);
173        }
174        Collections.sort(methodItems);
175
176        return methodItems;
177    }
178
179
180    private static class MethodItemList {
181        private final DexFile dexFile;
182        private final StringTemplateGroup stg;
183        private final CodeItem codeItem;
184
185        public LabelCache labels = new LabelCache();
186
187        public List<MethodItem> instructions = new ArrayList<MethodItem>();
188        public List<BlankMethodItem> blanks = new ArrayList<BlankMethodItem>();
189        public List<CatchMethodItem> catches = new ArrayList<CatchMethodItem>();
190        public List<MethodItem> debugItems = new ArrayList<MethodItem>();
191
192        private HashMap<Integer, Integer> packedSwitchMap = new HashMap<Integer, Integer>();
193        private HashMap<Integer, Integer> sparseSwitchMap = new HashMap<Integer, Integer>();
194
195        public MethodItemList(DexFile dexFile, StringTemplateGroup stg, CodeItem codeItem) {
196            this.dexFile = dexFile;
197            this.stg = stg;
198            this.codeItem = codeItem;
199        }
200
201        public void generateMethodItemList() {
202            if (codeItem == null) {
203                return;
204            }
205
206            if (baksmali.deodexUtil != null && dexFile.isOdex()) {
207                List<Instruction> instructions = baksmali.deodexUtil.deodexerizeCode(codeItem);
208
209                int currentCodeAddress = 0;
210                for (Instruction instruction: instructions) {
211                    if (instruction.opcode == Opcode.PACKED_SWITCH) {
212                        Instruction31t ins = (Instruction31t)instruction;
213                        packedSwitchMap.put(currentCodeAddress + ins.getTargetAddressOffset(), currentCodeAddress);
214                    } else if (instruction.opcode == Opcode.SPARSE_SWITCH) {
215                        Instruction31t ins = (Instruction31t)instruction;
216                        sparseSwitchMap.put(currentCodeAddress + ins.getTargetAddressOffset(), currentCodeAddress);
217                    }
218
219                    currentCodeAddress += instruction.getSize(currentCodeAddress);
220                }
221
222                currentCodeAddress = 0;
223                for (Instruction instruction: instructions) {
224                    addMethodItemsForInstruction(currentCodeAddress, instruction, false);
225                    blanks.add(new BlankMethodItem(stg, currentCodeAddress));
226
227                    currentCodeAddress += instruction.getSize(currentCodeAddress);
228                }
229
230                /*
231                 * Look for the last uncommented instruction. If it is an UnresolvedNullReference,
232                 * then set IsLastInstruction, so a goto will be added after it, to avoid validation
233                 * issues
234                 */
235                for (int i=this.instructions.size()-1; i>=0; i--) {
236                    MethodItem ins = this.instructions.get(i);
237                    if (ins instanceof UnresolvedNullReferenceMethodItem) {
238                        ((UnresolvedNullReferenceMethodItem)ins).setIsLastInstruction(true);
239                        break;
240                    }
241
242                    if (!(ins instanceof CommentedOutMethodItem)) {
243                        break;
244                    }
245                }
246            } else {
247                int currentCodeAddress = 0;
248                for (Instruction instruction: codeItem.getInstructions()) {
249                    if (instruction.opcode == Opcode.PACKED_SWITCH) {
250                        OffsetInstruction offsetInstruction = (OffsetInstruction)instruction;
251                        packedSwitchMap.put(currentCodeAddress + offsetInstruction.getTargetAddressOffset(), currentCodeAddress);
252                    } else if (instruction.opcode == Opcode.SPARSE_SWITCH) {
253                        OffsetInstruction offsetInstruction = (OffsetInstruction)instruction;
254                        sparseSwitchMap.put(currentCodeAddress + offsetInstruction.getTargetAddressOffset(), currentCodeAddress);
255                    }
256
257                    currentCodeAddress += instruction.getSize(currentCodeAddress);
258                }
259
260                currentCodeAddress = 0;
261                for (Instruction instruction: codeItem.getInstructions()) {
262                    addMethodItemsForInstruction(currentCodeAddress, instruction, false);
263                    blanks.add(new BlankMethodItem(stg, currentCodeAddress));
264                    currentCodeAddress += instruction.getSize(currentCodeAddress);
265                }
266
267            }
268
269            blanks.remove(blanks.size()-1);
270
271            addTries();
272
273            addDebugInfo();
274
275            if (baksmali.useSequentialLabels) {
276                setLabelSequentialNumbers();
277            }
278        }
279
280        private void addOffsetInstructionMethodItem(OffsetInstructionFormatMethodItem methodItem,
281                                                    boolean commentedOut) {
282            if (commentedOut) {
283                instructions.add(new CommentedOutMethodItem(stg, methodItem));
284            } else {
285                instructions.add(methodItem);
286                LabelMethodItem label = methodItem.getLabel();
287                label.setUncommented();
288            }
289        }
290
291
292        private void addInstructionMethodItem(InstructionFormatMethodItem methodItem, boolean commentedOut) {
293            if (commentedOut) {
294                instructions.add(new CommentedOutMethodItem(stg, methodItem));
295            } else {
296                instructions.add(methodItem);
297            }
298        }
299
300        private void addMethodItemsForInstruction(int codeAddress, Instruction instruction, boolean commentedOut) {
301            switch (instruction.getFormat()) {
302                case Format10t:
303                    addOffsetInstructionMethodItem(
304                            new Instruction10tMethodItem(labels, codeItem, codeAddress, stg,(Instruction10t)instruction),
305                            commentedOut);
306                    return;
307                case Format10x:
308                    addInstructionMethodItem(
309                            new Instruction10xMethodItem(codeItem, codeAddress, stg, (Instruction10x)instruction),
310                            commentedOut);
311                    return;
312                case Format11n:
313                    addInstructionMethodItem(
314                            new Instruction11nMethodItem(codeItem, codeAddress, stg, (Instruction11n)instruction),
315                            commentedOut);
316                    return;
317                case Format11x:
318                    addInstructionMethodItem(
319                            new Instruction11xMethodItem(codeItem, codeAddress, stg, (Instruction11x)instruction),
320                            commentedOut);
321                    return;
322                case Format12x:
323                    addInstructionMethodItem(
324                            new Instruction12xMethodItem(codeItem, codeAddress, stg, (Instruction12x)instruction),
325                            commentedOut);
326                    return;
327                case Format20t:
328                    addOffsetInstructionMethodItem(
329                            new Instruction20tMethodItem(labels, codeItem, codeAddress, stg, (Instruction20t)instruction),
330                            commentedOut);
331                    return;
332                case Format21c:
333                    addInstructionMethodItem(
334                            new Instruction21cMethodItem(codeItem, codeAddress, stg, (Instruction21c)instruction),
335                            commentedOut);
336                    return;
337                case Format21h:
338                    addInstructionMethodItem(
339                            new Instruction21hMethodItem(codeItem, codeAddress, stg, (Instruction21h)instruction),
340                            commentedOut);
341                    return;
342                case Format21s:
343                    addInstructionMethodItem(
344                            new Instruction21sMethodItem(codeItem, codeAddress, stg, (Instruction21s)instruction),
345                            commentedOut);
346                    return;
347                case Format21t:
348                    addOffsetInstructionMethodItem(
349                            new Instruction21tMethodItem(labels, codeItem, codeAddress, stg, (Instruction21t)instruction),
350                            commentedOut);
351                    return;
352                case Format22b:
353                    addInstructionMethodItem(
354                            new Instruction22bMethodItem(codeItem, codeAddress, stg, (Instruction22b)instruction),
355                            commentedOut);
356                    return;
357                case Format22c:
358                    addInstructionMethodItem(
359                            new Instruction22cMethodItem(codeItem, codeAddress, stg, (Instruction22c)instruction),
360                            commentedOut);
361                    return;
362                case Format22cs:
363                    addInstructionMethodItem(
364                            new Instruction22csMethodItem(codeItem, codeAddress, stg, (Instruction22cs)instruction),
365                            commentedOut);
366                    return;
367                case Format22csf:
368                    addInstructionMethodItem(
369                            new Instruction22csfMethodItem(codeItem, codeAddress, stg, (Instruction22csf)instruction),
370                            commentedOut);
371                    return;
372                case Format22s:
373                    addInstructionMethodItem(
374                            new Instruction22sMethodItem(codeItem, codeAddress, stg, (Instruction22s)instruction),
375                            commentedOut);
376                    return;
377                case Format22t:
378                    addOffsetInstructionMethodItem(
379                            new Instruction22tMethodItem(labels, codeItem, codeAddress, stg, (Instruction22t)instruction),
380                            commentedOut);
381                    return;
382                case Format22x:
383                    addInstructionMethodItem(
384                            new Instruction22xMethodItem(codeItem, codeAddress, stg, (Instruction22x)instruction),
385                            commentedOut);
386                    return;
387                case Format23x:
388                    addInstructionMethodItem(
389                            new Instruction23xMethodItem(codeItem, codeAddress, stg, (Instruction23x)instruction),
390                            commentedOut);
391                    return;
392                case Format30t:
393                    addOffsetInstructionMethodItem(
394                            new Instruction30tMethodItem(labels, codeItem, codeAddress, stg, (Instruction30t)instruction),
395                            commentedOut);
396                    return;
397                case Format31c:
398                    addInstructionMethodItem(
399                            new Instruction31cMethodItem(codeItem, codeAddress, stg, (Instruction31c)instruction),
400                            commentedOut);
401                    return;
402                case Format31i:
403                    addInstructionMethodItem(
404                            new Instruction31iMethodItem(codeItem, codeAddress, stg, (Instruction31i)instruction),
405                            commentedOut);
406                    return;
407                case Format31t:
408                    addOffsetInstructionMethodItem(
409                            new Instruction31tMethodItem(labels, codeItem, codeAddress, stg, (Instruction31t)instruction),
410                            commentedOut);
411                    return;
412                case Format32x:
413                    addInstructionMethodItem(
414                            new Instruction32xMethodItem(codeItem, codeAddress, stg, (Instruction32x)instruction),
415                            commentedOut);
416                    return;
417                case Format35c:
418                    addInstructionMethodItem(
419                            new Instruction35cMethodItem(codeItem, codeAddress, stg, (Instruction35c)instruction),
420                            commentedOut);
421                    return;
422                case Format35s:
423                    addInstructionMethodItem(
424                            new Instruction35sMethodItem(codeItem, codeAddress, stg, (Instruction35s)instruction),
425                            commentedOut);
426                    return;
427                case Format35sf:
428                    addInstructionMethodItem(
429                            new Instruction35sfMethodItem(codeItem, codeAddress, stg, (Instruction35sf)instruction),
430                            commentedOut);
431                    return;
432                case Format35ms:
433                    addInstructionMethodItem(
434                            new Instruction35msMethodItem(codeItem, codeAddress, stg, (Instruction35ms)instruction),
435                            commentedOut);
436                    return;
437                case Format35msf:
438                    addInstructionMethodItem(
439                            new Instruction35msfMethodItem(codeItem, codeAddress, stg, (Instruction35msf)instruction),
440                            commentedOut);
441                    return;
442                case Format3rc:
443                    addInstructionMethodItem(
444                            new Instruction3rcMethodItem(codeItem, codeAddress, stg, (Instruction3rc)instruction),
445                            commentedOut);
446                    return;
447                case Format3rms:
448                    addInstructionMethodItem(
449                            new Instruction3rmsMethodItem(codeItem, codeAddress, stg, (Instruction3rms)instruction),
450                            commentedOut);
451                    return;
452                case Format3rmsf:
453                    addInstructionMethodItem(
454                            new Instruction3rmsfMethodItem(codeItem, codeAddress, stg, (Instruction3rmsf)instruction),
455                            commentedOut);
456                    return;
457                case Format51l:
458                    addInstructionMethodItem(
459                            new Instruction51lMethodItem(codeItem, codeAddress, stg, (Instruction51l)instruction),
460                            commentedOut);
461                    return;
462                case ArrayData:
463                    addInstructionMethodItem(
464                            new ArrayDataMethodItem(codeItem, codeAddress, stg, (ArrayDataPseudoInstruction)instruction),
465                            commentedOut);
466                    return;
467                case PackedSwitchData:
468                {
469                    final Integer baseAddress = packedSwitchMap.get(codeAddress);
470
471                    if (baseAddress != null) {
472                        PackedSwitchDataPseudoInstruction packedSwitchInstruction =
473                                (PackedSwitchDataPseudoInstruction)instruction;
474
475                        PackedSwitchMethodItem packedSwitch = new PackedSwitchMethodItem(labels, codeItem, codeAddress, stg,
476                                packedSwitchInstruction, baseAddress);
477                        addInstructionMethodItem(packedSwitch, commentedOut);
478
479                        if (!commentedOut) {
480                            for (LabelMethodItem label: packedSwitch) {
481                                label.setUncommented();
482                            }
483                        }
484                    }
485                    return;
486                }
487                case SparseSwitchData:
488                {
489                    final Integer baseAddress = sparseSwitchMap.get(codeAddress);
490
491                    if (baseAddress != null) {
492                        SparseSwitchDataPseudoInstruction sparseSwitchInstruction =
493                                (SparseSwitchDataPseudoInstruction)instruction;
494
495                        SparseSwitchMethodItem sparseSwitch = new SparseSwitchMethodItem(labels, codeItem, codeAddress, stg,
496                                sparseSwitchInstruction, baseAddress);
497                        addInstructionMethodItem(sparseSwitch, commentedOut);
498
499                        if (!commentedOut) {
500                            for (LabelMethodItem label: sparseSwitch) {
501                                label.setUncommented();
502                            }
503                        }
504                    }
505                    return;
506                }
507                case UnresolvedNullReference:
508                {
509                    addInstructionMethodItem(new UnresolvedNullReferenceMethodItem(codeItem, codeAddress, stg,
510                            (UnresolvedNullReference)instruction), commentedOut);
511                    addMethodItemsForInstruction(codeAddress, ((UnresolvedNullReference)instruction).OriginalInstruction,
512                            true);
513                    return;
514                }
515                case DeadInstruction:
516                {
517                    //TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
518                    addMethodItemsForInstruction(codeAddress, ((DeadInstruction)instruction).OriginalInstruction, true);
519                    return;
520                }
521            }
522        }
523
524        private void addTries() {
525            if (codeItem.getTries() == null) {
526                return;
527            }
528            for (CodeItem.TryItem tryItem: codeItem.getTries()) {
529                int startAddress = tryItem.getStartCodeAddress();
530                int endAddress = tryItem.getStartCodeAddress() + tryItem.getTryLength();
531
532                /**
533                 * The end address points to the address immediately after the end of the last
534                 * instruction that the try block covers. We want the .catch directive and end_try
535                 * label to be associated with the last covered instruction, so we need to get
536                 * the address for that instruction
537                 */
538                int index = Collections.binarySearch(instructions, new BlankMethodItem(stg, endAddress));
539                if (index < 0) {
540                    index = (index * -1) - 1;
541                }
542                //index should never be 0, so this should be safe
543                if (index == instructions.size()) {
544                    //if the end address is the same as the address of the last instruction, then
545                    //this try item ends at the next to last instruction.
546                    //otherwise, if the end address is past the address of the last instruction,
547                    //thin this try item ends at the last instruction
548                    if (instructions.get(instructions.size() - 1).getCodeAddress() == endAddress) {
549                        //get the address for the next to last instruction
550                        index -= 2;
551                    } else {
552                        //get the address for the last instruction
553                        index--;
554                    }
555                } else {
556                    index -= 2;
557                }
558
559                int lastInstructionAddress = instructions.get(index).getCodeAddress();
560
561                //add the catch all handler if it exists
562                int catchAllAddress = tryItem.encodedCatchHandler.getCatchAllHandlerAddress();
563                if (catchAllAddress != -1) {
564                    CatchMethodItem catchMethodItem = new CatchMethodItem(labels, lastInstructionAddress, stg, null,
565                            startAddress, endAddress, catchAllAddress);
566                    catches.add(catchMethodItem);
567                }
568
569                //add the rest of the handlers
570                for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
571                    //use the address from the last covered instruction
572                    CatchMethodItem catchMethodItem = new CatchMethodItem(labels, lastInstructionAddress, stg,
573                            handler.exceptionType, startAddress, endAddress, handler.getHandlerAddress());
574                    catches.add(catchMethodItem);
575                }
576            }
577        }
578
579        private void addDebugInfo() {
580            DebugInfoItem debugInfoItem = codeItem.getDebugInfo();
581            if (debugInfoItem == null) {
582                return;
583            }
584
585            DebugInstructionIterator.DecodeInstructions(debugInfoItem, codeItem.getRegisterCount(),
586                    new DebugInstructionIterator.ProcessDecodedDebugInstructionDelegate() {
587                        @Override
588                        public void ProcessStartLocal(int codeAddress, int length, int registerNum, StringIdItem name,
589                                                      TypeIdItem type) {
590                            debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "StartLocal", -1,
591                                    registerNum, name, type, null));
592                        }
593
594                        @Override
595                        public void ProcessStartLocalExtended(int codeAddress, int length, int registerNum,
596                                                              StringIdItem name, TypeIdItem type,
597                                                              StringIdItem signature) {
598                            debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "StartLocal", -1,
599                                    registerNum, name, type, signature));
600                        }
601
602                        @Override
603                        public void ProcessEndLocal(int codeAddress, int length, int registerNum, StringIdItem name,
604                                                    TypeIdItem type, StringIdItem signature) {
605                            debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "EndLocal", -1,
606                                    registerNum, name, type, signature));
607                        }
608
609                        @Override
610                        public void ProcessRestartLocal(int codeAddress, int length, int registerNum, StringIdItem name,
611                                                        TypeIdItem type, StringIdItem signature) {
612                            debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "RestartLocal", -1,
613                                    registerNum, name, type, signature));
614                        }
615
616                        @Override
617                        public void ProcessSetPrologueEnd(int codeAddress) {
618                            debugItems.add(new DebugMethodItem(codeAddress, stg, "EndPrologue", -4));
619                        }
620
621                        @Override
622                        public void ProcessSetEpilogueBegin(int codeAddress) {
623                            debugItems.add(new DebugMethodItem(codeAddress, stg, "StartEpilogue", -4));
624                        }
625
626                        @Override
627                        public void ProcessSetFile(int codeAddress, int length, final StringIdItem name) {
628                            debugItems.add(new DebugMethodItem(codeAddress, stg, "SetFile", -3) {
629                                @Override
630                                protected void setAttributes(StringTemplate template) {
631                                    template.setAttribute("FileName", name.getStringValue());
632                                }
633                            });
634                        }
635
636                        @Override
637                        public void ProcessLineEmit(int codeAddress, final int line) {
638                             debugItems.add(new DebugMethodItem(codeAddress, stg, "Line", -2) {
639                                 @Override
640                                 protected void setAttributes(StringTemplate template) {
641                                     template.setAttribute("Line", line);
642                                 }
643                             });
644                        }
645                    });
646        }
647
648        private void setLabelSequentialNumbers() {
649            HashMap<String, Integer> nextLabelSequenceByType = new HashMap<String, Integer>();
650            ArrayList<LabelMethodItem> sortedLabels = new ArrayList<LabelMethodItem>(labels.getLabels());
651
652            //sort the labels by their location in the method
653            Collections.sort(sortedLabels);
654
655            for (LabelMethodItem labelMethodItem: sortedLabels) {
656                Integer labelSequence = nextLabelSequenceByType.get(labelMethodItem.getLabelPrefix());
657                if (labelSequence == null) {
658                    labelSequence = 0;
659                }
660                labelMethodItem.setLabelSequence(labelSequence);
661                nextLabelSequenceByType.put(labelMethodItem.getLabelPrefix(), labelSequence + 1);
662            }
663        }
664    }
665
666    public static class LabelCache {
667        protected HashMap<LabelMethodItem, LabelMethodItem> labels = new HashMap<LabelMethodItem, LabelMethodItem>();
668
669        public LabelCache() {
670        }
671
672        public LabelMethodItem internLabel(LabelMethodItem labelMethodItem) {
673            LabelMethodItem internedLabelMethodItem = labels.get(labelMethodItem);
674            if (internedLabelMethodItem != null) {
675                if (!labelMethodItem.isCommentedOut()) {
676                    internedLabelMethodItem.setUncommented();
677                }
678                return internedLabelMethodItem;
679            }
680            labels.put(labelMethodItem, labelMethodItem);
681            return labelMethodItem;
682        }
683
684
685        public Collection<LabelMethodItem> getLabels() {
686            return labels.values();
687        }
688    }
689}
690