MethodDefinition.java revision 5867263eb588f4671400895d1e6b01c01535061b
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.InstructionIterator;
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 makeTemplate(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 (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.makeTemplate(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.makeTemplate(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        methodItems.addAll(methodItemList.debugItems);
172        Collections.sort(methodItems);
173
174        return methodItems;
175    }
176
177
178    private static class MethodItemList {
179        private final DexFile dexFile;
180        private final StringTemplateGroup stg;
181        private final CodeItem codeItem;
182
183        public LabelCache labels = new LabelCache();
184
185        public List<MethodItem> instructions = new ArrayList<MethodItem>();
186        public List<BlankMethodItem> blanks = new ArrayList<BlankMethodItem>();
187        public List<CatchMethodItem> catches = new ArrayList<CatchMethodItem>();
188        public List<MethodItem> debugItems = new ArrayList<MethodItem>();
189
190        private HashMap<Integer, Integer> packedSwitchMap = new HashMap<Integer, Integer>();
191        private HashMap<Integer, Integer> sparseSwitchMap = new HashMap<Integer, Integer>();
192
193        public MethodItemList(DexFile dexFile, StringTemplateGroup stg, CodeItem codeItem) {
194            this.dexFile = dexFile;
195            this.stg = stg;
196            this.codeItem = codeItem;
197        }
198
199        public void generateMethodItemList() {
200            if (codeItem == null) {
201                return;
202            }
203
204            if (baksmali.deodexUtil != null && dexFile.isOdex()) {
205                List<Instruction> instructions = baksmali.deodexUtil.deodexerizeCode(codeItem);
206
207                int offset = 0;
208                for (Instruction instruction: instructions) {
209                    if (instruction.opcode == Opcode.PACKED_SWITCH) {
210                        Instruction31t ins = (Instruction31t)instruction;
211                        packedSwitchMap.put(offset + ins.getOffset(), offset);
212                    } else if (instruction.opcode == Opcode.SPARSE_SWITCH) {
213                        Instruction31t ins = (Instruction31t)instruction;
214                        sparseSwitchMap.put(offset + ins.getOffset(), offset);
215                    }
216
217                    offset += instruction.getSize()/2;
218                }
219
220                offset = 0;
221                for (Instruction instruction: instructions) {
222                    addMethodItemsForInstruction(offset, instruction, false);
223                    blanks.add(new BlankMethodItem(stg, offset));
224
225                    offset += instruction.getSize()/2;
226                }
227
228                /*
229                 * Look for the last uncommented instruction. If it is an UnresolvedNullReference,
230                 * then set IsLastInstruction, so a goto will be added after it, to avoid validation
231                 * issues
232                 */
233                for (int i=this.instructions.size()-1; i>=0; i--) {
234                    MethodItem ins = this.instructions.get(i);
235                    if (ins instanceof UnresolvedNullReferenceMethodItem) {
236                        ((UnresolvedNullReferenceMethodItem)ins).setIsLastInstruction(true);
237                        break;
238                    }
239
240                    if (!(ins instanceof CommentedOutMethodItem)) {
241                        break;
242                    }
243                }
244            } else {
245                final byte[] encodedInstructions = codeItem.getEncodedInstructions();
246
247                InstructionIterator.IterateInstructions(encodedInstructions,
248                        new InstructionIterator.ProcessRawInstructionDelegate() {
249                            public void ProcessNormalInstruction(Opcode opcode, int index) {
250                                if (opcode == Opcode.PACKED_SWITCH) {
251                                    Instruction31t ins = (Instruction31t)opcode.format.Factory.makeInstruction(
252                                            dexFile, opcode, encodedInstructions, index);
253                                    packedSwitchMap.put(index/2 + ins.getOffset(), index/2);
254                                } else if (opcode == Opcode.SPARSE_SWITCH) {
255                                    Instruction31t ins = (Instruction31t)opcode.format.Factory.makeInstruction(
256                                            dexFile, opcode, encodedInstructions, index);
257                                    sparseSwitchMap.put(index/2 + ins.getOffset(),  index/2);
258                                }
259                            }
260
261                            public void ProcessReferenceInstruction(Opcode opcode, int index) {
262                            }
263
264                            public void ProcessPackedSwitchInstruction(int index, int targetCount, int instructionLength) {
265                            }
266
267                            public void ProcessSparseSwitchInstruction(int index, int targetCount, int instructionLength) {
268                            }
269
270                            public void ProcessFillArrayDataInstruction(int index, int elementWidth, int elementCount,
271                                                                        int instructionLength) {
272                            }
273                        });
274
275                InstructionIterator.IterateInstructions(dexFile, encodedInstructions,
276                        new InstructionIterator.ProcessInstructionDelegate() {
277                            public void ProcessInstruction(int index, Instruction instruction) {
278                                int offset = index/2;
279                                addMethodItemsForInstruction(offset, instruction, false);
280                                blanks.add(new BlankMethodItem(stg, offset));
281                            }
282                        });
283            }
284
285            blanks.remove(blanks.size()-1);
286
287            addTries();
288
289            addDebugInfo();
290
291            if (baksmali.useIndexedLabels) {
292                setLabelIndexes();
293            }
294        }
295
296        private void addOffsetInstructionMethodItem(OffsetInstructionFormatMethodItem methodItem,
297                                                    boolean commentedOut) {
298            if (commentedOut) {
299                instructions.add(new CommentedOutMethodItem(stg, methodItem));
300            } else {
301                instructions.add(methodItem);
302                LabelMethodItem label = methodItem.getLabel();
303                label.setUncommented();
304            }
305        }
306
307
308        private void addInstructionMethodItem(InstructionFormatMethodItem methodItem, boolean commentedOut) {
309            if (commentedOut) {
310                instructions.add(new CommentedOutMethodItem(stg, methodItem));
311            } else {
312                instructions.add(methodItem);
313            }
314        }
315
316        private void addMethodItemsForInstruction(int offset, Instruction instruction, boolean commentedOut) {
317            switch (instruction.getFormat()) {
318                case Format10t:
319                    addOffsetInstructionMethodItem(
320                            new Instruction10tMethodItem(labels, codeItem, offset, stg,(Instruction10t)instruction),
321                            commentedOut);
322                    return;
323                case Format10x:
324                    addInstructionMethodItem(
325                            new Instruction10xMethodItem(codeItem, offset, stg, (Instruction10x)instruction),
326                            commentedOut);
327                    return;
328                case Format11n:
329                    addInstructionMethodItem(
330                            new Instruction11nMethodItem(codeItem, offset, stg, (Instruction11n)instruction),
331                            commentedOut);
332                    return;
333                case Format11x:
334                    addInstructionMethodItem(
335                            new Instruction11xMethodItem(codeItem, offset, stg, (Instruction11x)instruction),
336                            commentedOut);
337                    return;
338                case Format12x:
339                    addInstructionMethodItem(
340                            new Instruction12xMethodItem(codeItem, offset, stg, (Instruction12x)instruction),
341                            commentedOut);
342                    return;
343                case Format20t:
344                    addOffsetInstructionMethodItem(
345                            new Instruction20tMethodItem(labels, codeItem, offset, stg, (Instruction20t)instruction),
346                            commentedOut);
347                    return;
348                case Format21c:
349                    addInstructionMethodItem(
350                            new Instruction21cMethodItem(codeItem, offset, stg, (Instruction21c)instruction),
351                            commentedOut);
352                    return;
353                case Format21h:
354                    addInstructionMethodItem(
355                            new Instruction21hMethodItem(codeItem, offset, stg, (Instruction21h)instruction),
356                            commentedOut);
357                    return;
358                case Format21s:
359                    addInstructionMethodItem(
360                            new Instruction21sMethodItem(codeItem, offset, stg, (Instruction21s)instruction),
361                            commentedOut);
362                    return;
363                case Format21t:
364                    addOffsetInstructionMethodItem(
365                            new Instruction21tMethodItem(labels, codeItem, offset, stg, (Instruction21t)instruction),
366                            commentedOut);
367                    return;
368                case Format22b:
369                    addInstructionMethodItem(
370                            new Instruction22bMethodItem(codeItem, offset, stg, (Instruction22b)instruction),
371                            commentedOut);
372                    return;
373                case Format22c:
374                    addInstructionMethodItem(
375                            new Instruction22cMethodItem(codeItem, offset, stg, (Instruction22c)instruction),
376                            commentedOut);
377                    return;
378                case Format22cs:
379                    addInstructionMethodItem(
380                            new Instruction22csMethodItem(codeItem, offset, stg, (Instruction22cs)instruction),
381                            commentedOut);
382                    return;
383                case Format22csf:
384                    addInstructionMethodItem(
385                            new Instruction22csfMethodItem(codeItem, offset, stg, (Instruction22csf)instruction),
386                            commentedOut);
387                    return;
388                case Format22s:
389                    addInstructionMethodItem(
390                            new Instruction22sMethodItem(codeItem, offset, stg, (Instruction22s)instruction),
391                            commentedOut);
392                    return;
393                case Format22t:
394                    addOffsetInstructionMethodItem(
395                            new Instruction22tMethodItem(labels, codeItem, offset, stg, (Instruction22t)instruction),
396                            commentedOut);
397                    return;
398                case Format22x:
399                    addInstructionMethodItem(
400                            new Instruction22xMethodItem(codeItem, offset, stg, (Instruction22x)instruction),
401                            commentedOut);
402                    return;
403                case Format23x:
404                    addInstructionMethodItem(
405                            new Instruction23xMethodItem(codeItem, offset, stg, (Instruction23x)instruction),
406                            commentedOut);
407                    return;
408                case Format30t:
409                    addOffsetInstructionMethodItem(
410                            new Instruction30tMethodItem(labels, codeItem, offset, stg, (Instruction30t)instruction),
411                            commentedOut);
412                    return;
413                case Format31c:
414                    addInstructionMethodItem(
415                            new Instruction31cMethodItem(codeItem, offset, stg, (Instruction31c)instruction),
416                            commentedOut);
417                    return;
418                case Format31i:
419                    addInstructionMethodItem(
420                            new Instruction31iMethodItem(codeItem, offset, stg, (Instruction31i)instruction),
421                            commentedOut);
422                    return;
423                case Format31t:
424                    addOffsetInstructionMethodItem(
425                            new Instruction31tMethodItem(labels, codeItem, offset, stg, (Instruction31t)instruction),
426                            commentedOut);
427                    return;
428                case Format32x:
429                    addInstructionMethodItem(
430                            new Instruction32xMethodItem(codeItem, offset, stg, (Instruction32x)instruction),
431                            commentedOut);
432                    return;
433                case Format35c:
434                    addInstructionMethodItem(
435                            new Instruction35cMethodItem(codeItem, offset, stg, (Instruction35c)instruction),
436                            commentedOut);
437                    return;
438                case Format35s:
439                    addInstructionMethodItem(
440                            new Instruction35sMethodItem(codeItem, offset, stg, (Instruction35s)instruction),
441                            commentedOut);
442                    return;
443                case Format35sf:
444                    addInstructionMethodItem(
445                            new Instruction35sfMethodItem(codeItem, offset, stg, (Instruction35sf)instruction),
446                            commentedOut);
447                    return;
448                case Format35ms:
449                    addInstructionMethodItem(
450                            new Instruction35msMethodItem(codeItem, offset, stg, (Instruction35ms)instruction),
451                            commentedOut);
452                    return;
453                case Format35msf:
454                    addInstructionMethodItem(
455                            new Instruction35msfMethodItem(codeItem, offset, stg, (Instruction35msf)instruction),
456                            commentedOut);
457                    return;
458                case Format3rc:
459                    addInstructionMethodItem(
460                            new Instruction3rcMethodItem(codeItem, offset, stg, (Instruction3rc)instruction),
461                            commentedOut);
462                    return;
463                case Format3rms:
464                    addInstructionMethodItem(
465                            new Instruction3rmsMethodItem(codeItem, offset, stg, (Instruction3rms)instruction),
466                            commentedOut);
467                    return;
468                case Format3rmsf:
469                    addInstructionMethodItem(
470                            new Instruction3rmsfMethodItem(codeItem, offset, stg, (Instruction3rmsf)instruction),
471                            commentedOut);
472                    return;
473                case Format51l:
474                    addInstructionMethodItem(
475                            new Instruction51lMethodItem(codeItem, offset, stg, (Instruction51l)instruction),
476                            commentedOut);
477                    return;
478                case ArrayData:
479                    addInstructionMethodItem(
480                            new ArrayDataMethodItem(codeItem, offset, stg, (ArrayDataPseudoInstruction)instruction),
481                            commentedOut);
482                    return;
483                case PackedSwitchData:
484                {
485                    final Integer baseAddress = packedSwitchMap.get(offset);
486
487                    if (baseAddress != null) {
488                        PackedSwitchDataPseudoInstruction packedSwitchInstruction =
489                                (PackedSwitchDataPseudoInstruction)instruction;
490
491                        PackedSwitchMethodItem packedSwitch = new PackedSwitchMethodItem(labels, codeItem, offset, stg,
492                                packedSwitchInstruction, baseAddress);
493                        addInstructionMethodItem(packedSwitch, commentedOut);
494
495                        if (!commentedOut) {
496                            for (LabelMethodItem label: packedSwitch) {
497                                label.setUncommented();
498                            }
499                        }
500                    }
501                    return;
502                }
503                case SparseSwitchData:
504                {
505                    final Integer baseAddress = sparseSwitchMap.get(offset);
506
507                    if (baseAddress != null) {
508                        SparseSwitchDataPseudoInstruction sparseSwitchInstruction =
509                                (SparseSwitchDataPseudoInstruction)instruction;
510
511                        SparseSwitchMethodItem sparseSwitch = new SparseSwitchMethodItem(labels, codeItem, offset, stg,
512                                sparseSwitchInstruction, baseAddress);
513                        addInstructionMethodItem(sparseSwitch, commentedOut);
514
515                        if (!commentedOut) {
516                            for (LabelMethodItem label: sparseSwitch) {
517                                label.setUncommented();
518                            }
519                        }
520                    }
521                    return;
522                }
523                case UnresolvedNullReference:
524                {
525                    addInstructionMethodItem(new UnresolvedNullReferenceMethodItem(codeItem, offset, stg,
526                            (UnresolvedNullReference)instruction), commentedOut);
527                    addMethodItemsForInstruction(offset, ((UnresolvedNullReference)instruction).OriginalInstruction,
528                            true);
529                    return;
530                }
531                case DeadInstruction:
532                {
533                    //TODO: what about try/catch blocks inside the dead code? those will need to be commented out too. ugh.
534                    addMethodItemsForInstruction(offset, ((DeadInstruction)instruction).OriginalInstruction, true);
535                    return;
536                }
537            }
538        }
539
540        private void addTries() {
541            if (codeItem.getTries() == null) {
542                return;
543            }
544            for (CodeItem.TryItem tryItem: codeItem.getTries()) {
545                int startAddress = tryItem.startAddress;
546                int endAddress = tryItem.startAddress + tryItem.instructionCount;
547
548                /**
549                 * The end address points to the address immediately after the end of the last
550                 * instruction that the try block covers. We want the .catch directive and end_try
551                 * label to be associated with the last covered instruction, so we need to get
552                 * the offset for that instruction
553                 */
554                int index = Collections.binarySearch(instructions, new BlankMethodItem(stg, endAddress));
555                if (index < 0) {
556                    index = (index * -1) - 1;
557                }
558                //index should never be 0, so this should be safe
559                if (index == instructions.size()) {
560                    //if the end address is the same as the address of the last instruction, then
561                    //this try item ends at the next to last instruction.
562                    //otherwise, if the end address is past the address of the last instruction,
563                    //thin this try item ends at the last instruction
564                    if (instructions.get(instructions.size() - 1).getOffset() == endAddress) {
565                        //get the address for the next to last instruction
566                        index -= 2;
567                    } else {
568                        //get the address for the last instruction
569                        index--;
570                    }
571                } else {
572                    index -= 2;
573                }
574
575                int lastInstructionOffset = instructions.get(index).getOffset();
576
577                //add the catch all handler if it exists
578                int catchAllAddress = tryItem.encodedCatchHandler.catchAllHandlerAddress;
579                if (catchAllAddress != -1) {
580                    CatchMethodItem catchMethodItem = new CatchMethodItem(labels, lastInstructionOffset, stg, null,
581                            startAddress, endAddress, catchAllAddress);
582                    catches.add(catchMethodItem);
583                }
584
585                //add the rest of the handlers
586                for (CodeItem.EncodedTypeAddrPair handler: tryItem.encodedCatchHandler.handlers) {
587                    //use the offset from the last covered instruction
588                    CatchMethodItem catchMethodItem = new CatchMethodItem(labels, lastInstructionOffset, stg,
589                            handler.exceptionType, startAddress, endAddress, handler.handlerAddress);
590                    catches.add(catchMethodItem);
591                }
592            }
593        }
594
595        private void addDebugInfo() {
596            DebugInfoItem debugInfoItem = codeItem.getDebugInfo();
597            if (debugInfoItem == null) {
598                return;
599            }
600
601            DebugInstructionIterator.DecodeInstructions(debugInfoItem, codeItem.getRegisterCount(),
602                    new DebugInstructionIterator.ProcessDecodedDebugInstructionDelegate() {
603                        @Override
604                        public void ProcessStartLocal(int codeAddress, int length, int registerNum, StringIdItem name,
605                                                      TypeIdItem type) {
606                            debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "StartLocal", -1,
607                                    registerNum, name, type, null));
608                        }
609
610                        @Override
611                        public void ProcessStartLocalExtended(int codeAddress, int length, int registerNum,
612                                                              StringIdItem name, TypeIdItem type,
613                                                              StringIdItem signature) {
614                            debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "StartLocal", -1,
615                                    registerNum, name, type, signature));
616                        }
617
618                        @Override
619                        public void ProcessEndLocal(int codeAddress, int length, int registerNum, StringIdItem name,
620                                                    TypeIdItem type, StringIdItem signature) {
621                            debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "EndLocal", -1,
622                                    registerNum, name, type, signature));
623                        }
624
625                        @Override
626                        public void ProcessRestartLocal(int codeAddress, int length, int registerNum, StringIdItem name,
627                                                        TypeIdItem type, StringIdItem signature) {
628                            debugItems.add(new LocalDebugMethodItem(codeItem, codeAddress, stg, "RestartLocal", -1,
629                                    registerNum, name, type, signature));
630                        }
631
632                        @Override
633                        public void ProcessSetPrologueEnd(int codeAddress) {
634                            debugItems.add(new DebugMethodItem(codeAddress, stg, "EndPrologue", -4));
635                        }
636
637                        @Override
638                        public void ProcessSetEpilogueBegin(int codeAddress) {
639                            debugItems.add(new DebugMethodItem(codeAddress, stg, "StartEpilogue", -4));
640                        }
641
642                        @Override
643                        public void ProcessSetFile(int codeAddress, int length, final StringIdItem name) {
644                            debugItems.add(new DebugMethodItem(codeAddress, stg, "SetFile", -3) {
645                                @Override
646                                protected void setAttributes(StringTemplate template) {
647                                    template.setAttribute("FileName", name.getStringValue());
648                                }
649                            });
650                        }
651
652                        @Override
653                        public void ProcessLineEmit(int codeAddress, final int line) {
654                             debugItems.add(new DebugMethodItem(codeAddress, stg, "Line", -2) {
655                                 @Override
656                                 protected void setAttributes(StringTemplate template) {
657                                     template.setAttribute("Line", line);
658                                 }
659                             });
660                        }
661                    });
662        }
663
664        private void setLabelIndexes() {
665            HashMap<String, Integer> nextLabelIndexByType = new HashMap<String, Integer>();
666            ArrayList<LabelMethodItem> sortedLabels = new ArrayList<LabelMethodItem>(labels.getLabels());
667
668            //sort the labels by their location in the method
669            Collections.sort(sortedLabels);
670
671            for (LabelMethodItem labelMethodItem: sortedLabels) {
672                Integer labelIndex = nextLabelIndexByType.get(labelMethodItem.getLabelPrefix());
673                if (labelIndex == null) {
674                    labelIndex = 0;
675                }
676                labelMethodItem.setLabelIndex(labelIndex);
677                nextLabelIndexByType.put(labelMethodItem.getLabelPrefix(), labelIndex + 1);
678            }
679        }
680    }
681
682    public static class LabelCache {
683        protected HashMap<LabelMethodItem, LabelMethodItem> labels = new HashMap<LabelMethodItem, LabelMethodItem>();
684
685        public LabelCache() {
686        }
687
688        public LabelMethodItem internLabel(LabelMethodItem labelMethodItem) {
689            LabelMethodItem internedLabelMethodItem = labels.get(labelMethodItem);
690            if (internedLabelMethodItem != null) {
691                if (!labelMethodItem.isCommentedOut()) {
692                    internedLabelMethodItem.setUncommented();
693                }
694                return internedLabelMethodItem;
695            }
696            labels.put(labelMethodItem, labelMethodItem);
697            return labelMethodItem;
698        }
699
700
701        public Collection<LabelMethodItem> getLabels() {
702            return labels.values();
703        }
704    }
705}
706