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