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