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