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