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