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