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