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