1 /* 2 * Copyright (c) 1996, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.openjdk.asmtools.jdis; 24 25 import org.openjdk.asmtools.jasm.Tables; 26 27 import java.io.DataInputStream; 28 import java.io.IOException; 29 import java.io.PrintWriter; 30 import java.util.ArrayList; 31 import java.util.HashMap; 32 33 import static org.openjdk.asmtools.jasm.OpcodeTables.Opcode; 34 import static org.openjdk.asmtools.jasm.OpcodeTables.opcode; 35 import static org.openjdk.asmtools.jasm.Tables.*; 36 import static org.openjdk.asmtools.jasm.Tables.AttrTag.ATT_RuntimeInvisibleTypeAnnotations; 37 import static org.openjdk.asmtools.jasm.Tables.AttrTag.ATT_RuntimeVisibleTypeAnnotations; 38 import static org.openjdk.asmtools.jdis.Utils.commentString; 39 40 /** 41 * Code data for a code attribute in method members in a class of the Java Disassembler 42 */ 43 public class CodeData extends Indenter { 44 45 /** 46 * Raw byte array for the byte codes 47 */ 48 protected byte[] code; 49 /** 50 * Limit for the stack size 51 */ 52 protected int max_stack; 53 54 /* CodeData Fields */ 55 /** 56 * Limit for the number of local vars 57 */ 58 protected int max_locals; 59 /** 60 * The remaining attributes of this class 61 */ 62 protected ArrayList<AttrData> attrs = new ArrayList<>(0); // AttrData 63 64 // internal references 65 protected ClassData cls; 66 protected MethodData meth; 67 /** 68 * (parsed) Trap table, describes exceptions caught 69 */ 70 private ArrayList<TrapData> trap_table = new ArrayList<>(0); // TrapData 71 /** 72 * (parsed) Line Number table, describes source lines associated with ByteCode indexes 73 */ 74 private ArrayList<LineNumData> lin_num_tb = new ArrayList<>(0); // LineNumData 75 /** 76 * (parsed) Local Variable table, describes variable scopes associated with ByteCode 77 * indexes 78 */ 79 private ArrayList<LocVarData> loc_var_tb = new ArrayList<>(0); // LocVarData 80 /** 81 * (parsed) stack map table, describes compiler hints for stack rep, associated with 82 * ByteCode indexes 83 */ 84 private ArrayList<StackMapData> stack_map = null; 85 /** 86 * The visible type annotations for this method 87 */ 88 private ArrayList<TypeAnnotationData> visibleTypeAnnotations; 89 /** 90 * The invisible type annotations for this method 91 */ 92 private ArrayList<TypeAnnotationData> invisibleTypeAnnotations; 93 94 /** 95 * (parsed) reversed bytecode index hash, associates labels with ByteCode indexes 96 */ 97 private HashMap<Integer, iAtt> iattrs = new HashMap<>(); 98 private PrintWriter out; 99 public CodeData(MethodData meth) { 100 this.meth = meth; 101 this.cls = meth.cls; 102 this.out = cls.out; 103 } 104 105 private static int align(int n) { 106 return (n + 3) & ~3; 107 } 108 /*-------------------------------------------------------- */ 109 110 private int getbyte(int pc) { 111 return code[pc]; 112 } 113 114 private int getUbyte(int pc) { 115 return code[pc] & 0xFF; 116 } 117 118 private int getShort(int pc) { 119 return (code[pc] << 8) | (code[pc + 1] & 0xFF); 120 } 121 122 private int getUShort(int pc) { 123 return ((code[pc] << 8) | (code[pc + 1] & 0xFF)) & 0xFFFF; 124 } 125 126 private int getInt(int pc) { 127 return (getShort(pc) << 16) | (getShort(pc + 2) & 0xFFFF); 128 } 129 130 protected iAtt get_iAtt(int pc) { 131 Integer PC = pc; 132 iAtt res = iattrs.get(PC); 133 if (res == null) { 134 res = new iAtt(this); 135 iattrs.put(PC, res); 136 } 137 return res; 138 } 139 140 /*========================================================*/ 141 /* Read Methods */ 142 private void readLineNumTable(DataInputStream in) throws IOException { 143 int len = in.readInt(); // attr_length 144 int numlines = in.readUnsignedShort(); 145 lin_num_tb = new ArrayList<>(numlines); 146 TraceUtils.traceln(3, "CodeAttr: LineNumTable[" + numlines + "] len=" + len); 147 for (int l = 0; l < numlines; l++) { 148 lin_num_tb.add(new LineNumData(in)); 149 } 150 } 151 152 private void readLocVarTable(DataInputStream in) throws IOException { 153 int len = in.readInt(); // attr_length 154 int numlines = in.readUnsignedShort(); 155 loc_var_tb = new ArrayList<>(numlines); 156 TraceUtils.traceln(3, "CodeAttr: LocalVariableTable[" + numlines + "] len=" + len); 157 for (int l = 0; l < numlines; l++) { 158 loc_var_tb.add(new LocVarData(in)); 159 } 160 } 161 162 private void readTrapTable(DataInputStream in) throws IOException { 163 int trap_table_len = in.readUnsignedShort(); 164 TraceUtils.traceln(3, "CodeAttr: TrapTable[" + trap_table_len + "]"); 165 trap_table = new ArrayList<>(trap_table_len); 166 for (int l = 0; l < trap_table_len; l++) { 167 trap_table.add(new TrapData(in, l)); 168 } 169 } 170 171 private void readStackMap(DataInputStream in) throws IOException { 172 int len = in.readInt(); // attr_length 173 int stack_map_len = in.readUnsignedShort(); 174 TraceUtils.traceln(3, "CodeAttr: Stack_Map: attrlen=" + len + " num=" + stack_map_len); 175 stack_map = new ArrayList<>(stack_map_len); 176 StackMapData.prevFramePC = 0; 177 for (int k = 0; k < stack_map_len; k++) { 178 stack_map.add(new StackMapData(this, in)); 179 } 180 } 181 182 private void readStackMapTable(DataInputStream in) throws IOException { 183 int len = in.readInt(); // attr_length 184 int stack_map_len = in.readUnsignedShort(); 185 TraceUtils.traceln(3, "CodeAttr: Stack_Map_Table: attrlen=" + len + " num=" + stack_map_len); 186 stack_map = new ArrayList<>(stack_map_len); 187 StackMapData.prevFramePC = 0; 188 for (int k = 0; k < stack_map_len; k++) { 189 stack_map.add(new StackMapData(this, in, true)); 190 } 191 } 192 193 private void readTypeAnnotations(DataInputStream in, boolean isInvisible) throws IOException { 194 int attrLength = in.readInt(); 195 // Read Type Annotations Attr 196 int count = in.readShort(); 197 ArrayList<TypeAnnotationData> tannots = new ArrayList<>(count); 198 TraceUtils.traceln(3, "CodeAttr: Runtime" + 199 (isInvisible ? "Inv" : "V") + 200 "isibleTypeAnnotation: attrlen=" + 201 attrLength + " num=" + count); 202 for (int index = 0; index < count; index++) { 203 TraceUtils.traceln("\t\t\t[" + index +"]:"); 204 TypeAnnotationData tannot = new TypeAnnotationData(isInvisible, cls); 205 tannot.read(in); 206 tannots.add(tannot); 207 } 208 if (isInvisible) { 209 invisibleTypeAnnotations = tannots; 210 } else { 211 visibleTypeAnnotations = tannots; 212 } 213 } 214 215 /** 216 * read 217 * <p> 218 * read and resolve the code attribute data called from MethodData. precondition: 219 * NumFields has already been read from the stream. 220 */ 221 public void read(DataInputStream in, int codeattrlen) throws IOException { 222 223 // Read the code in the Code Attribute 224 max_stack = in.readUnsignedShort(); 225 max_locals = in.readUnsignedShort(); 226 int codelen = in.readInt(); 227 TraceUtils.traceln(3, "CodeAttr: Codelen=" + codelen + 228 " fulllen=" + codeattrlen + 229 " max_stack=" + max_stack + 230 " max_locals=" + max_locals); 231 232 // read the raw code bytes 233 code = new byte[codelen]; 234 in.read(code, 0, codelen); 235 236 //read the trap table 237 readTrapTable(in); 238 239 // Read any attributes of the Code Attribute 240 int nattr = in.readUnsignedShort(); 241 TraceUtils.traceln(3, "CodeAttr: add.attr:" + nattr); 242 for (int k = 0; k < nattr; k++) { 243 int name_cpx = in.readUnsignedShort(); 244 // verify the Attrs name 245 ConstantPool.Constant name_const = cls.pool.getConst(name_cpx); 246 if (name_const != null && name_const.tag == ConstantPool.TAG.CONSTANT_UTF8) { 247 String attrname = cls.pool.getString(name_cpx); 248 TraceUtils.traceln(3, "CodeAttr: attr: " + attrname); 249 // process the attr 250 AttrTag attrtag = attrtag(attrname); 251 switch (attrtag) { 252 case ATT_LineNumberTable: 253 readLineNumTable(in); 254 break; 255 case ATT_LocalVariableTable: 256 readLocVarTable(in); 257 break; 258 case ATT_StackMap: 259 readStackMap(in); 260 break; 261 case ATT_StackMapTable: 262 readStackMapTable(in); 263 break; 264 case ATT_RuntimeVisibleTypeAnnotations: 265 case ATT_RuntimeInvisibleTypeAnnotations: 266 readTypeAnnotations(in, attrtag == ATT_RuntimeInvisibleTypeAnnotations); 267 break; 268 default: 269 AttrData attr = new AttrData(cls); 270 int attrlen = in.readInt(); // attr_length 271 attr.read(name_cpx, attrlen, in); 272 attrs.add(attr); 273 break; 274 } 275 } 276 } 277 } 278 279 /*========================================================*/ 280 /* Code Resolution Methods */ 281 private int checkForLabelRef(int pc) { 282 // throws IOException { 283 int opc = getUbyte(pc); 284 Opcode opcode = opcode(opc); 285 switch (opcode) { 286 case opc_tableswitch: { 287 int tb = align(pc + 1); 288 int default_skip = getInt(tb); /* default skip pamount */ 289 290 int low = getInt(tb + 4); 291 int high = getInt(tb + 8); 292 int count = high - low; 293 for (int i = 0; i <= count; i++) { 294 get_iAtt(pc + getInt(tb + 12 + 4 * i)).referred = true; 295 } 296 get_iAtt(default_skip + pc).referred = true; 297 return tb - pc + 16 + count * 4; 298 } 299 case opc_lookupswitch: { 300 int tb = align(pc + 1); 301 int default_skip = getInt(tb); /* default skip pamount */ 302 303 int npairs = getInt(tb + 4); 304 for (int i = 1; i <= npairs; i++) { 305 get_iAtt(pc + getInt(tb + 4 + i * 8)).referred = true; 306 } 307 get_iAtt(default_skip + pc).referred = true; 308 return tb - pc + (npairs + 1) * 8; 309 } 310 case opc_jsr: 311 case opc_goto: 312 case opc_ifeq: 313 case opc_ifge: 314 case opc_ifgt: 315 case opc_ifle: 316 case opc_iflt: 317 case opc_ifne: 318 case opc_if_icmpeq: 319 case opc_if_icmpne: 320 case opc_if_icmpge: 321 case opc_if_icmpgt: 322 case opc_if_icmple: 323 case opc_if_icmplt: 324 case opc_if_acmpeq: 325 case opc_if_acmpne: 326 case opc_ifnull: 327 case opc_ifnonnull: 328 get_iAtt(pc + getShort(pc + 1)).referred = true; 329 return 3; 330 case opc_jsr_w: 331 case opc_goto_w: 332 get_iAtt(pc + getInt(pc + 1)).referred = true; 333 return 5; 334 case opc_wide: 335 case opc_nonpriv: 336 case opc_priv: 337 int opc2 = (opcode.value() << 8) + getUbyte(pc + 1); 338 opcode = opcode(opc2); 339 } 340 try { 341 int opclen = opcode.length(); 342 return opclen == 0 ? 1 : opclen; // bugfix for 4614404 343 } catch (ArrayIndexOutOfBoundsException e) { 344 return 1; 345 } 346 } // end checkForLabelRef 347 348 private void loadLabelTable() { 349 for (int pc = 0; pc < code.length; ) { 350 pc = pc + checkForLabelRef(pc); 351 } 352 } 353 354 private void loadLineNumTable() { 355 for (LineNumData entry : lin_num_tb) { 356 get_iAtt(entry.start_pc).lnum = entry.line_number; 357 } 358 } 359 360 private void loadStackMap() { 361 for (StackMapData entry : stack_map) { 362 get_iAtt(entry.start_pc).stackMapEntry = entry; 363 } 364 } 365 366 private void loadLocVarTable() { 367 for (LocVarData entry : loc_var_tb) { 368 get_iAtt(entry.start_pc).add_var(entry); 369 get_iAtt(entry.start_pc + entry.length).add_endvar(entry); 370 } 371 } 372 373 private void loadTrapTable() { 374 for (TrapData entry : trap_table) { 375 get_iAtt(entry.start_pc).add_trap(entry); 376 get_iAtt(entry.end_pc).add_endtrap(entry); 377 get_iAtt(entry.handler_pc).add_handler(entry); 378 } 379 } 380 381 /*========================================================*/ 382 /* Print Methods */ 383 private void PrintConstant(int cpx) { 384 out.print("\t"); 385 cls.pool.PrintConstant(out, cpx); 386 } 387 388 private void PrintCommentedConstant(int cpx) { 389 out.print(commentString(cls.pool.ConstantStrValue(cpx))); 390 } 391 392 private int printInstr(int pc) { 393 boolean pr_cpx = meth.options.contains(Options.PR.CPX); 394 int opc = getUbyte(pc); 395 int opc2; 396 Opcode opcode = opcode(opc); 397 Opcode opcode2; 398 String mnem; 399 switch (opcode) { 400 case opc_nonpriv: 401 case opc_priv: 402 opc2 = getUbyte(pc + 1); 403 int finalopc = (opc << 8) + opc2; 404 opcode2 = opcode(finalopc); 405 if (opcode2 == null) { 406 // assume all (even nonexistent) priv and nonpriv instructions 407 // are 2 bytes long 408 mnem = opcode.parsekey() + " " + opc2; 409 } else { 410 mnem = opcode2.parsekey(); 411 } 412 out.print(mnem); 413 return 2; 414 case opc_wide: { 415 opc2 = getUbyte(pc + 1); 416 int finalopcwide = (opc << 8) + opc2; 417 opcode2 = opcode(finalopcwide); 418 if (opcode2 == null) { 419 // nonexistent opcode - but we have to print something 420 out.print("bytecode " + opcode); 421 return 1; 422 } else { 423 mnem = opcode2.parsekey(); 424 } 425 out.print(mnem + " " + getUShort(pc + 2)); 426 if (opcode2 == Opcode.opc_iinc_w) { 427 out.print(", " + getShort(pc + 4)); 428 return 6; 429 } 430 return 4; 431 } 432 } 433 mnem = opcode.parsekey(); 434 if (mnem == null) { 435 // nonexistent opcode - but we have to print something 436 out.print("bytecode " + opcode); 437 return 1; 438 } 439 if (opcode.value() >= Opcode.opc_bytecode.value()) { 440 // pseudo opcodes should be printed as bytecodes 441 out.print("bytecode " + opcode); 442 return 1; 443 } 444 out.print(opcode.parsekey()); 445 // TraceUtils.traceln("****** [CodeData.printInstr]: got an '" + opcode.parseKey() + "' [" + opc + "] instruction ****** "); 446 switch (opcode) { 447 case opc_aload: 448 case opc_astore: 449 case opc_fload: 450 case opc_fstore: 451 case opc_iload: 452 case opc_istore: 453 case opc_lload: 454 case opc_lstore: 455 case opc_dload: 456 case opc_dstore: 457 case opc_ret: 458 out.print("\t" + getUbyte(pc + 1)); 459 return 2; 460 case opc_iinc: 461 out.print("\t" + getUbyte(pc + 1) + ", " + getbyte(pc + 2)); 462 return 3; 463 case opc_tableswitch: { 464 int tb = align(pc + 1); 465 int default_skip = getInt(tb); /* default skip pamount */ 466 467 int low = getInt(tb + 4); 468 int high = getInt(tb + 8); 469 int count = high - low; 470 out.print("{ //" + low + " to " + high); 471 for (int i = 0; i <= count; i++) { 472 out.print("\n\t\t" + (i + low) + ": " + meth.lP + (pc + getInt(tb + 12 + 4 * i)) + ";"); 473 } 474 out.print("\n\t\tdefault: " + meth.lP + (default_skip + pc) + " }"); 475 return tb - pc + 16 + count * 4; 476 } 477 case opc_lookupswitch: { 478 int tb = align(pc + 1); 479 int default_skip = getInt(tb); 480 int npairs = getInt(tb + 4); 481 out.print("{ //" + npairs); 482 for (int i = 1; i <= npairs; i++) { 483 out.print("\n\t\t" + getInt(tb + i * 8) + ": " + meth.lP + (pc + getInt(tb + 4 + i * 8)) + ";"); 484 } 485 out.print("\n\t\tdefault: " + meth.lP + (default_skip + pc) + " }"); 486 return tb - pc + (npairs + 1) * 8; 487 } 488 case opc_newarray: 489 int tp = getUbyte(pc + 1); 490 BasicType type = basictype(tp); 491 switch (type) { 492 case T_BOOLEAN: 493 out.print(" boolean"); 494 break; 495 case T_BYTE: 496 out.print(" byte"); 497 break; 498 case T_CHAR: 499 out.print(" char"); 500 break; 501 case T_SHORT: 502 out.print(" short"); 503 break; 504 case T_INT: 505 out.print(" int"); 506 break; 507 case T_LONG: 508 out.print(" long"); 509 break; 510 case T_FLOAT: 511 out.print(" float"); 512 break; 513 case T_DOUBLE: 514 out.print(" double"); 515 break; 516 case T_CLASS: 517 out.print(" class"); 518 break; 519 default: 520 out.print(" BOGUS TYPE:" + type); 521 } 522 return 2; 523 case opc_ldc_w: 524 case opc_ldc2_w: { 525 // added printing of the tag: Method/Interface to clarify 526 // interpreting CONSTANT_MethodHandle_info:reference_kind 527 // Example: ldc_w Dynamic REF_invokeStatic:Method CondyIndy.condy_bsm 528 cls.pool.setPrintTAG(true); 529 int index = getUShort(pc + 1); 530 if (pr_cpx) { 531 out.print("\t#" + index + "; //"); 532 } 533 PrintConstant(index); 534 cls.pool.setPrintTAG(false); 535 return 3; 536 } 537 case opc_anewarray: 538 case opc_instanceof: 539 case opc_checkcast: 540 case opc_new: 541 case opc_aconst_init: 542 case opc_putstatic: 543 case opc_getstatic: 544 case opc_putfield: 545 case opc_getfield: 546 case opc_withfield: 547 case opc_invokevirtual: 548 case opc_invokespecial: 549 case opc_invokestatic: { 550 int index = getUShort(pc + 1); 551 if (pr_cpx) { 552 out.print("\t#" + index + "; //"); 553 } 554 PrintConstant(index); 555 return 3; 556 } 557 case opc_sipush: 558 out.print("\t" + getShort(pc + 1)); 559 return 3; 560 case opc_bipush: 561 out.print("\t" + getbyte(pc + 1)); 562 return 2; 563 case opc_ldc: { 564 // added printing of the tag: Method/Interface to clarify 565 // interpreting CONSTANT_MethodHandle_info:reference_kind 566 // Example: ldc Dynamic REF_invokeStatic:Method CondyIndy.condy_bsm 567 cls.pool.setPrintTAG(true); 568 int index = getUbyte(pc + 1); 569 if (pr_cpx) { 570 out.print("\t#" + index + "; //"); 571 } 572 PrintConstant(index); 573 cls.pool.setPrintTAG(false); 574 return 2; 575 } 576 case opc_invokeinterface: { 577 int index = getUShort(pc + 1), nargs = getUbyte(pc + 3); 578 if (pr_cpx) { 579 out.print("\t#" + index + ", " + nargs + "; //"); 580 PrintConstant(index); 581 } else { 582 PrintConstant(index); 583 out.print(", " + nargs); // args count 584 } 585 return 5; 586 } 587 case opc_invokedynamic: { // JSR-292 588 cls.pool.setPrintTAG(true); 589 int index = getUShort(pc + 1); 590 // getUbyte(pc + 3); // reserved byte 591 // getUbyte(pc + 4); // reserved byte 592 if (pr_cpx) { 593 out.print("\t#" + index + ";\t"); 594 PrintCommentedConstant(index); 595 } else { 596 PrintConstant(index); 597 } 598 cls.pool.setPrintTAG(false); 599 return 5; 600 } 601 case opc_multianewarray: { 602 int index = getUShort(pc + 1), dimensions = getUbyte(pc + 3); 603 if (pr_cpx) { 604 out.print("\t#" + index + ", " + dimensions + "; //"); 605 PrintConstant(index); 606 } else { 607 PrintConstant(index); 608 out.print(", " + dimensions); // dimensions count 609 } 610 return 4; 611 } 612 case opc_jsr: 613 case opc_goto: 614 case opc_ifeq: 615 case opc_ifge: 616 case opc_ifgt: 617 case opc_ifle: 618 case opc_iflt: 619 case opc_ifne: 620 case opc_if_icmpeq: 621 case opc_if_icmpne: 622 case opc_if_icmpge: 623 case opc_if_icmpgt: 624 case opc_if_icmple: 625 case opc_if_icmplt: 626 case opc_if_acmpeq: 627 case opc_if_acmpne: 628 case opc_ifnull: 629 case opc_ifnonnull: 630 out.print("\t" + meth.lP + (pc + getShort(pc + 1))); 631 return 3; 632 case opc_jsr_w: 633 case opc_goto_w: 634 out.print("\t" + meth.lP + (pc + getInt(pc + 1))); 635 return 5; 636 default: 637 return 1; 638 } 639 } // end printInstr 640 641 /** 642 * print 643 * <p> 644 * prints the code data to the current output stream. called from MethodData. 645 */ 646 public void print() throws IOException { 647 if (!lin_num_tb.isEmpty()) { 648 loadLineNumTable(); 649 } 650 if (stack_map != null) { 651 loadStackMap(); 652 } 653 if (!meth.options.contains(Options.PR.PC)) { 654 loadLabelTable(); 655 } 656 loadTrapTable(); 657 if (!loc_var_tb.isEmpty()) { 658 loadLocVarTable(); 659 } 660 661 out.println(); 662 out.println("\tstack " + max_stack + " locals " + max_locals); 663 664 // Need to print ParamAnnotations here. 665 meth.printPAnnotations(); 666 667 out.println(getIndentString() + "{"); 668 669 iAtt iatt = iattrs.get(0); 670 for (int pc = 0; pc < code.length; ) { 671 if (iatt != null) { 672 iatt.printBegins(); // equ. print("\t"); 673 } else { 674 out.print("\t"); 675 } 676 if (meth.options.contains(Options.PR.PC)) { 677 out.print(pc + ":\t"); 678 } else if ((iatt != null) && iatt.referred) { 679 out.print(meth.lP + pc + ":\t"); 680 } else { 681 out.print("\t"); 682 } 683 if (iatt != null) { 684 iatt.printStackMap(); 685 } 686 pc = pc + printInstr(pc); 687 out.println(";"); 688 iatt = iattrs.get(pc); 689 if (iatt != null) { 690 iatt.printEnds(); 691 } 692 } 693 // the right brace can be labelled: 694 if (iatt != null) { 695 iatt.printBegins(); // equ. print("\t"); 696 if (iatt.referred) { 697 out.print(meth.lP + code.length + ":\t"); 698 } 699 iatt.printStackMap(); 700 out.println(); 701 } 702 // print TypeAnnotations 703 if (visibleTypeAnnotations != null) { 704 out.println(); 705 for (TypeAnnotationData visad : visibleTypeAnnotations) { 706 visad.print(out, getIndentString()); 707 out.println(); 708 } 709 } 710 if (invisibleTypeAnnotations != null) { 711 for (TypeAnnotationData invisad : invisibleTypeAnnotations) { 712 invisad.print(out, getIndentString()); 713 out.println(); 714 } 715 } 716 // end of code 717 out.println(getIndentString() + "}"); 718 } 719 720 721 public static class LocVarData { 722 723 short start_pc, length, name_cpx, sig_cpx, slot; 724 725 public LocVarData(DataInputStream in) throws IOException { 726 start_pc = in.readShort(); 727 length = in.readShort(); 728 name_cpx = in.readShort(); 729 sig_cpx = in.readShort(); 730 slot = in.readShort(); 731 } 732 } 733 734 /* Code Data inner classes */ 735 class LineNumData { 736 737 short start_pc, line_number; 738 739 public LineNumData(DataInputStream in) throws IOException { 740 start_pc = in.readShort(); 741 line_number = in.readShort(); 742 } 743 } 744 745 }