1 /* 2 * Copyright (c) 1994, 2013, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.tools.asm; 27 28 import sun.tools.java.*; 29 import java.util.Enumeration; 30 import java.io.IOException; 31 import java.io.DataOutputStream; 32 33 /** 34 * An Java instruction 35 * 36 * WARNING: The contents of this source file are not part of any 37 * supported API. Code that depends on them does so at its own risk: 38 * they are subject to change or removal without notice. 39 */ 40 public 41 class Instruction implements Constants { 42 long where; 43 int pc; 44 int opc; 45 Object value; 46 Instruction next; 47 //JCOV 48 boolean flagCondInverted; /* if true, the condition is reversed 49 relatively of source code */ 50 boolean flagNoCovered = false; /* if true, the command will 51 ignored for coverage */ 52 53 54 /** 55 * Constructor 56 */ Instruction(long where, int opc, Object value, boolean flagCondInverted)57 public Instruction(long where, int opc, Object value, boolean flagCondInverted) { 58 this.where = where; 59 this.opc = opc; 60 this.value = value; 61 this.flagCondInverted = flagCondInverted; 62 } 63 64 /** 65 * Constructor 66 */ Instruction(boolean flagNoCovered, long where, int opc, Object value)67 public Instruction(boolean flagNoCovered, long where, int opc, Object value) { 68 this.where = where; 69 this.opc = opc; 70 this.value = value; 71 this.flagNoCovered = flagNoCovered; 72 } 73 74 /** 75 * Constructor 76 */ Instruction(long where, int opc, boolean flagNoCovered)77 public Instruction(long where, int opc, boolean flagNoCovered) { 78 this.where = where; 79 this.opc = opc; 80 this.flagNoCovered = flagNoCovered; 81 } 82 //end JCOV 83 84 /** 85 * Constructor 86 */ Instruction(long where, int opc, Object value)87 public Instruction(long where, int opc, Object value) { 88 this.where = where; 89 this.opc = opc; 90 this.value = value; 91 } 92 93 /** 94 * When deciding between a lookupswitch and a tableswitch, this 95 * value is used in determining how much size increase is 96 * acceptable. 97 */ 98 public static final double SWITCHRATIO; 99 100 static { 101 // Set SWITCHRATIO from the property javac.switchratio 102 // if it exists and is reasonable. Otherwise, set 103 // SWITCHRATIO to 1.5, meaning that we will accept a 1.5x 104 // blowup (for the instruction) to use a tableswitch instead 105 // of a lookupswitch. 106 double ratio = 1.5; 107 String valStr = System.getProperty("javac.switchratio"); 108 if (valStr != null) { 109 try { 110 double temp = Double.valueOf(valStr).doubleValue(); 111 if (!(Double.isNaN(temp) || temp < 0.0)) { 112 ratio = temp; 113 } 114 } catch (NumberFormatException ee) {} 115 } 116 SWITCHRATIO = ratio; 117 } 118 119 /** 120 * Accessor 121 */ getOpcode()122 public int getOpcode() { 123 return pc; 124 } 125 getValue()126 public Object getValue() { 127 return value; 128 } 129 setValue(Object value)130 public void setValue(Object value) { 131 this.value = value; 132 } 133 134 135 /** 136 * Optimize 137 */ optimize(Environment env)138 void optimize(Environment env) { 139 switch (opc) { 140 case opc_istore: case opc_lstore: case opc_fstore: 141 case opc_dstore: case opc_astore: 142 // Don't keep the LocalVariable info around, unless we 143 // are actually going to generate a local variable table. 144 if ((value instanceof LocalVariable) && !env.debug_vars()) { 145 value = ((LocalVariable)value).slot; 146 } 147 break; 148 149 case opc_goto: { 150 Label lbl = (Label)value; 151 value = lbl = lbl.getDestination(); 152 if (lbl == next) { 153 // goto to the next instruction, obsolete 154 opc = opc_dead; 155 break; 156 } 157 158 // We optimize 159 // 160 // goto Tag 161 // ... 162 // Tag: 163 // return 164 // 165 // except when we're generating debuggable code. When 166 // we're generating debuggable code, we leave it alone, 167 // in order to provide better stepping behavior. Consider 168 // a method the end of which looks like this: 169 // 170 // ... 171 // break; 172 // } // end of loop 173 // } // end of method 174 // 175 // If we optimize the goto away, we'll be left with a 176 // single instruction (return) and the need to ascribe that 177 // instruction to two source lines (the break statement and 178 // the method's right curly). Can't get there from here. 179 // Depending on which line-number ascription we choose, the 180 // stepping user will step directly from the break statement 181 // back into the caller of the method (case 1) or from the 182 // statement that precedes the break statement to the method's 183 // right curly (case 2). Similarly, he'll be able to set a 184 // breakpoint on the break statement (case 1) or the method's 185 // right curly (case 2), but not on both. Neither case 1 nor 186 // case 2 is desirable. .We want him to see both the break 187 // statement and the method's right curly when stepping, 188 // and we want him to be able to set a breakpoint on either or 189 // both. So we suppress the optimization when generating 190 // debuggable code. 191 // (Above notes from brucek@eng in JDK1.0.2, copied here 192 // by kelly.ohair@eng for JDK1.1) 193 // 194 // With the changes to allow -O and -g at the same time, 195 // I've changed the condition to be whether optimization is 196 // on instead of the debugging flag being off. 197 // - david.stoutamire@eng for 1.2 198 199 if (lbl.next != null && env.opt()) { 200 switch (lbl.next.opc) { 201 case opc_return: case opc_ireturn: case opc_lreturn: 202 case opc_freturn: case opc_dreturn: case opc_areturn: 203 // goto to return 204 opc = lbl.next.opc; 205 value = lbl.next.value; 206 break; 207 } 208 } 209 break; 210 } 211 212 case opc_ifeq: case opc_ifne: case opc_ifgt: 213 case opc_ifge: case opc_iflt: case opc_ifle: 214 case opc_ifnull: case opc_ifnonnull: 215 value = ((Label)value).getDestination(); 216 if (value == next) { 217 // branch to next instruction, obsolete 218 opc = opc_pop; 219 break; 220 } 221 if ((next.opc == opc_goto) && (value == next.next)) { 222 // Conditional branch over goto, invert 223 // Note that you can't invert all conditions, condition 224 // results for float/double compares are not invertable. 225 switch (opc) { 226 case opc_ifeq: opc = opc_ifne; break; 227 case opc_ifne: opc = opc_ifeq; break; 228 case opc_iflt: opc = opc_ifge; break; 229 case opc_ifle: opc = opc_ifgt; break; 230 case opc_ifgt: opc = opc_ifle; break; 231 case opc_ifge: opc = opc_iflt; break; 232 case opc_ifnull: opc = opc_ifnonnull; break; 233 case opc_ifnonnull: opc = opc_ifnull; break; 234 } 235 //JCOV 236 flagCondInverted = !flagCondInverted; 237 //end JCOV 238 value = next.value; 239 next.opc = opc_dead; 240 } 241 break; 242 243 case opc_if_acmpeq: case opc_if_acmpne: 244 case opc_if_icmpeq: case opc_if_icmpne: 245 case opc_if_icmpgt: case opc_if_icmpge: 246 case opc_if_icmplt: case opc_if_icmple: 247 value = ((Label)value).getDestination(); 248 if (value == next) { 249 // branch to next instruction, obsolete 250 opc = opc_pop2; 251 break; 252 } 253 if ((next.opc == opc_goto) && (value == next.next)) { 254 // Conditional branch over goto, invert 255 switch (opc) { 256 case opc_if_acmpeq: opc = opc_if_acmpne; break; 257 case opc_if_acmpne: opc = opc_if_acmpeq; break; 258 case opc_if_icmpeq: opc = opc_if_icmpne; break; 259 case opc_if_icmpne: opc = opc_if_icmpeq; break; 260 case opc_if_icmpgt: opc = opc_if_icmple; break; 261 case opc_if_icmpge: opc = opc_if_icmplt; break; 262 case opc_if_icmplt: opc = opc_if_icmpge; break; 263 case opc_if_icmple: opc = opc_if_icmpgt; break; 264 } 265 //JCOV 266 flagCondInverted = !flagCondInverted; 267 //end JCOV 268 value = next.value; 269 next.opc = opc_dead; 270 } 271 break; 272 273 case opc_tableswitch: 274 case opc_lookupswitch: { 275 SwitchData sw = (SwitchData)value; 276 sw.defaultLabel = sw.defaultLabel.getDestination(); 277 for (Enumeration<Integer> e = sw.tab.keys() ; e.hasMoreElements() ; ) { 278 Integer k = e.nextElement(); 279 Label lbl = sw.tab.get(k); 280 sw.tab.put(k, lbl.getDestination()); 281 } 282 283 // Compute the approximate sizes of a tableswitch and a 284 // lookupswitch. Decide which one we want to generate. 285 286 long range = (long)sw.maxValue - (long)sw.minValue + 1; 287 long entries = sw.tab.size(); 288 289 long tableSize = 4 + range; 290 long lookupSize = 3 + 2 * entries; 291 292 if (tableSize <= lookupSize * SWITCHRATIO) { 293 opc = opc_tableswitch; 294 } else { 295 opc = opc_lookupswitch; 296 } 297 break; 298 } 299 300 } 301 } 302 303 /** 304 * Collect constants into the constant table 305 */ collect(ConstantPool tab)306 void collect(ConstantPool tab) { 307 switch (opc) { 308 case opc_istore: case opc_lstore: case opc_fstore: 309 case opc_dstore: case opc_astore: 310 if (value instanceof LocalVariable) { 311 MemberDefinition field = ((LocalVariable)value).field; 312 tab.put(field.getName().toString()); 313 tab.put(field.getType().getTypeSignature()); 314 } 315 return; 316 317 case opc_new: case opc_putfield: 318 case opc_putstatic: case opc_getfield: 319 case opc_getstatic: case opc_invokevirtual: 320 case opc_invokespecial: case opc_invokestatic: 321 case opc_invokeinterface: case opc_instanceof: 322 case opc_checkcast: 323 tab.put(value); 324 return; 325 326 case opc_anewarray: 327 tab.put(value); 328 return; 329 330 case opc_multianewarray: 331 tab.put(((ArrayData)value).type); 332 return; 333 334 case opc_ldc: 335 case opc_ldc_w: 336 if (value instanceof Integer) { 337 int v = ((Integer)value).intValue(); 338 if ((v >= -1) && (v <= 5)) { 339 opc = opc_iconst_0 + v; 340 return; 341 } else if ((v >= -(1 << 7)) && (v < (1 << 7))) { 342 opc = opc_bipush; 343 return; 344 } else if ((v >= -(1 << 15)) && (v < (1 << 15))) { 345 opc = opc_sipush; 346 return; 347 } 348 } else if (value instanceof Float) { 349 float v = ((Float)value).floatValue(); 350 if (v == 0) { 351 if (Float.floatToIntBits(v) == 0) { 352 opc = opc_fconst_0; 353 return; 354 } 355 } else if (v == 1) { 356 opc = opc_fconst_1; 357 return; 358 } else if (v == 2) { 359 opc = opc_fconst_2; 360 return; 361 } 362 } 363 tab.put(value); 364 return; 365 366 case opc_ldc2_w: 367 if (value instanceof Long) { 368 long v = ((Long)value).longValue(); 369 if (v == 0) { 370 opc = opc_lconst_0; 371 return; 372 } else if (v == 1) { 373 opc = opc_lconst_1; 374 return; 375 } 376 } else if (value instanceof Double) { 377 double v = ((Double)value).doubleValue(); 378 if (v == 0) { 379 if (Double.doubleToLongBits(v) == 0) { 380 opc = opc_dconst_0; 381 return; 382 } 383 } else if (v == 1) { 384 opc = opc_dconst_1; 385 return; 386 } 387 } 388 tab.put(value); 389 return; 390 391 case opc_try: 392 for (Enumeration<CatchData> e = ((TryData)value).catches.elements() ; e.hasMoreElements() ;) { 393 CatchData cd = e.nextElement(); 394 if (cd.getType() != null) { 395 tab.put(cd.getType()); 396 } 397 } 398 return; 399 400 case opc_nop: 401 if ((value != null) && (value instanceof ClassDeclaration)) 402 tab.put(value); 403 return; 404 } 405 } 406 407 /** 408 * Balance the stack 409 */ balance()410 int balance() { 411 switch (opc) { 412 case opc_dead: case opc_label: case opc_iinc: 413 case opc_arraylength: case opc_laload: case opc_daload: 414 case opc_nop: case opc_ineg: case opc_fneg: 415 case opc_lneg: case opc_dneg: case opc_i2f: 416 case opc_f2i: case opc_l2d: case opc_d2l: 417 case opc_i2b: case opc_i2c: case opc_i2s: 418 case opc_jsr: case opc_goto: case opc_jsr_w: 419 case opc_goto_w: case opc_return: case opc_ret: 420 case opc_instanceof: case opc_checkcast: case opc_newarray: 421 case opc_anewarray: case opc_try: case opc_swap: 422 return 0; 423 424 case opc_ldc: case opc_ldc_w: case opc_bipush: 425 case opc_sipush: case opc_aconst_null: case opc_iconst_m1: 426 case opc_iconst_0: case opc_iconst_1: case opc_iconst_2: 427 case opc_iconst_3: case opc_iconst_4: case opc_iconst_5: 428 case opc_fconst_0: case opc_fconst_1: case opc_fconst_2: 429 case opc_iload: case opc_fload: case opc_aload: 430 case opc_dup: case opc_dup_x1: case opc_dup_x2: 431 case opc_i2l: case opc_i2d: case opc_f2l: 432 case opc_f2d: case opc_new: 433 return 1; 434 435 case opc_lload: case opc_dload: case opc_dup2: 436 case opc_dup2_x1: case opc_dup2_x2: case opc_ldc2_w: 437 case opc_lconst_0: case opc_lconst_1: case opc_dconst_0: 438 case opc_dconst_1: 439 return 2; 440 441 case opc_istore: case opc_fstore: case opc_astore: 442 case opc_iaload: case opc_faload: case opc_aaload: 443 case opc_baload: case opc_caload: case opc_saload: 444 case opc_pop: case opc_iadd: case opc_fadd: 445 case opc_isub: case opc_fsub: case opc_imul: 446 case opc_fmul: case opc_idiv: case opc_fdiv: 447 case opc_irem: case opc_frem: case opc_ishl: 448 case opc_ishr: case opc_iushr: case opc_lshl: 449 case opc_lshr: case opc_lushr: case opc_iand: 450 case opc_ior: case opc_ixor: case opc_l2i: 451 case opc_l2f: case opc_d2i: case opc_d2f: 452 case opc_ifeq: case opc_ifne: case opc_iflt: 453 case opc_ifle: case opc_ifgt: case opc_ifge: 454 case opc_ifnull: case opc_ifnonnull: case opc_fcmpl: 455 case opc_fcmpg: case opc_ireturn: case opc_freturn: 456 case opc_areturn: case opc_tableswitch: case opc_lookupswitch: 457 case opc_athrow: case opc_monitorenter: case opc_monitorexit: 458 return -1; 459 460 case opc_lstore: case opc_dstore: case opc_pop2: 461 case opc_ladd: case opc_dadd: case opc_lsub: 462 case opc_dsub: case opc_lmul: case opc_dmul: 463 case opc_ldiv: case opc_ddiv: case opc_lrem: 464 case opc_drem: case opc_land: case opc_lor: 465 case opc_lxor: case opc_if_acmpeq: case opc_if_acmpne: 466 case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmplt: 467 case opc_if_icmple: case opc_if_icmpgt: case opc_if_icmpge: 468 case opc_lreturn: case opc_dreturn: 469 return -2; 470 471 case opc_iastore: case opc_fastore: case opc_aastore: 472 case opc_bastore: case opc_castore: case opc_sastore: 473 case opc_lcmp: case opc_dcmpl: case opc_dcmpg: 474 return -3; 475 476 case opc_lastore: case opc_dastore: 477 return -4; 478 479 case opc_multianewarray: 480 return 1 - ((ArrayData)value).nargs; 481 482 case opc_getfield: 483 return ((MemberDefinition)value).getType().stackSize() - 1; 484 485 case opc_putfield: 486 return -1 - ((MemberDefinition)value).getType().stackSize(); 487 488 case opc_getstatic: 489 return ((MemberDefinition)value).getType().stackSize(); 490 491 case opc_putstatic: 492 return -((MemberDefinition)value).getType().stackSize(); 493 494 case opc_invokevirtual: 495 case opc_invokespecial: 496 case opc_invokeinterface: 497 return ((MemberDefinition)value).getType().getReturnType().stackSize() - 498 (((MemberDefinition)value).getType().stackSize() + 1); 499 500 case opc_invokestatic: 501 return ((MemberDefinition)value).getType().getReturnType().stackSize() - 502 (((MemberDefinition)value).getType().stackSize()); 503 } 504 throw new CompilerError("invalid opcode: " + toString()); 505 } 506 507 /** 508 * Return the size of the instruction 509 */ size(ConstantPool tab)510 int size(ConstantPool tab) { 511 switch (opc) { 512 case opc_try: case opc_label: case opc_dead: 513 return 0; 514 515 case opc_bipush: case opc_newarray: 516 return 2; 517 518 case opc_sipush: case opc_goto: case opc_jsr: 519 case opc_ifeq: case opc_ifne: case opc_ifgt: 520 case opc_ifge: case opc_iflt: case opc_ifle: 521 case opc_ifnull: case opc_ifnonnull: case opc_if_acmpeq: 522 case opc_if_acmpne: case opc_if_icmpeq: case opc_if_icmpne: 523 case opc_if_icmpgt: case opc_if_icmpge: case opc_if_icmplt: 524 case opc_if_icmple: 525 return 3; 526 527 case opc_ldc: 528 case opc_ldc_w: 529 if (tab.index(value) < 256) { 530 opc = opc_ldc; 531 return 2; 532 } else { 533 opc = opc_ldc_w; 534 return 3; 535 } 536 537 case opc_iload: case opc_lload: case opc_fload: 538 case opc_dload: case opc_aload: { 539 int v = ((Number)value).intValue(); 540 if (v < 4) { 541 if (v < 0) { 542 throw new CompilerError("invalid slot: " + toString() 543 + "\nThis error possibly resulted from poorly constructed class paths."); 544 } 545 opc = opc_iload_0 + (opc - opc_iload) * 4 + v; 546 return 1; 547 } else if (v <= 255) { 548 return 2; 549 } else { 550 opc += 256; // indicate wide variant 551 return 4; 552 } 553 } 554 555 case opc_iinc: { 556 int register = ((int[])value)[0]; 557 int increment = ((int[])value)[1]; 558 if (register < 0) { 559 throw new CompilerError("invalid slot: " + toString()); 560 } 561 if (register <= 255 && (((byte)increment) == increment)) { 562 return 3; 563 } else { 564 opc += 256; // indicate wide variant 565 return 6; 566 } 567 } 568 569 case opc_istore: case opc_lstore: case opc_fstore: 570 case opc_dstore: case opc_astore: { 571 int v = (value instanceof Number) ? 572 ((Number)value).intValue() : ((LocalVariable)value).slot; 573 if (v < 4) { 574 if (v < 0) { 575 throw new CompilerError("invalid slot: " + toString()); 576 } 577 opc = opc_istore_0 + (opc - opc_istore) * 4 + v; 578 return 1; 579 } else if (v <= 255) { 580 return 2; 581 } else { 582 opc += 256; // indicate wide variant 583 return 4; 584 } 585 } 586 587 case opc_ret: { 588 int v = ((Number)value).intValue(); 589 if (v <= 255) { 590 if (v < 0) { 591 throw new CompilerError("invalid slot: " + toString()); 592 } 593 return 2; 594 } else { 595 opc += 256; // indicate wide variant 596 return 4; 597 } 598 } 599 600 case opc_ldc2_w: case opc_new: 601 case opc_putstatic: case opc_getstatic: 602 case opc_putfield: case opc_getfield: 603 case opc_invokevirtual: case opc_invokespecial: 604 case opc_invokestatic: case opc_instanceof: 605 case opc_checkcast: case opc_anewarray: 606 return 3; 607 608 case opc_multianewarray: 609 return 4; 610 611 case opc_invokeinterface: 612 case opc_goto_w: 613 case opc_jsr_w: 614 return 5; 615 616 case opc_tableswitch: { 617 SwitchData sw = (SwitchData)value; 618 int n = 1; 619 for(; ((pc + n) % 4) != 0 ; n++); 620 return n + 16 + (sw.maxValue - sw.minValue) * 4; 621 } 622 623 case opc_lookupswitch: { 624 SwitchData sw = (SwitchData)value; 625 int n = 1; 626 for(; ((pc + n) % 4) != 0 ; n++); 627 return n + 8 + sw.tab.size() * 8; 628 } 629 630 case opc_nop: 631 if ((value != null) && !(value instanceof Integer)) 632 return 2; 633 else 634 return 1; 635 } 636 637 // most opcodes are only 1 byte long 638 return 1; 639 } 640 641 /** 642 * Generate code 643 */ 644 @SuppressWarnings("fallthrough") write(DataOutputStream out, ConstantPool tab)645 void write(DataOutputStream out, ConstantPool tab) throws IOException { 646 switch (opc) { 647 case opc_try: case opc_label: case opc_dead: 648 break; 649 650 case opc_bipush: case opc_newarray: 651 case opc_iload: case opc_lload: case opc_fload: 652 case opc_dload: case opc_aload: case opc_ret: 653 out.writeByte(opc); 654 out.writeByte(((Number)value).intValue()); 655 break; 656 657 case opc_iload + 256: case opc_lload + 256: 658 case opc_fload + 256: case opc_dload + 256: 659 case opc_aload + 256: case opc_ret + 256: 660 out.writeByte(opc_wide); 661 out.writeByte(opc - 256); 662 out.writeShort(((Number)value).intValue()); 663 break; 664 665 case opc_istore: case opc_lstore: case opc_fstore: 666 case opc_dstore: case opc_astore: 667 out.writeByte(opc); 668 out.writeByte((value instanceof Number) ? 669 ((Number)value).intValue() : ((LocalVariable)value).slot); 670 break; 671 672 case opc_istore + 256: case opc_lstore + 256: 673 case opc_fstore + 256: case opc_dstore + 256: 674 case opc_astore + 256: 675 out.writeByte(opc_wide); 676 out.writeByte(opc - 256); 677 out.writeShort((value instanceof Number) ? 678 ((Number)value).intValue() : ((LocalVariable)value).slot); 679 break; 680 681 case opc_sipush: 682 out.writeByte(opc); 683 out.writeShort(((Number)value).intValue()); 684 break; 685 686 case opc_ldc: 687 out.writeByte(opc); 688 out.writeByte(tab.index(value)); 689 break; 690 691 case opc_ldc_w: case opc_ldc2_w: 692 case opc_new: case opc_putstatic: 693 case opc_getstatic: case opc_putfield: 694 case opc_getfield: case opc_invokevirtual: 695 case opc_invokespecial: case opc_invokestatic: 696 case opc_instanceof: case opc_checkcast: 697 out.writeByte(opc); 698 out.writeShort(tab.index(value)); 699 break; 700 701 case opc_iinc: 702 out.writeByte(opc); 703 out.writeByte(((int[])value)[0]); // register 704 out.writeByte(((int[])value)[1]); // increment 705 break; 706 707 case opc_iinc + 256: 708 out.writeByte(opc_wide); 709 out.writeByte(opc - 256); 710 out.writeShort(((int[])value)[0]); // register 711 out.writeShort(((int[])value)[1]); // increment 712 break; 713 714 case opc_anewarray: 715 out.writeByte(opc); 716 out.writeShort(tab.index(value)); 717 break; 718 719 case opc_multianewarray: 720 out.writeByte(opc); 721 out.writeShort(tab.index(((ArrayData)value).type)); 722 out.writeByte(((ArrayData)value).nargs); 723 break; 724 725 case opc_invokeinterface: 726 out.writeByte(opc); 727 out.writeShort(tab.index(value)); 728 out.writeByte(((MemberDefinition)value).getType().stackSize() + 1); 729 out.writeByte(0); 730 break; 731 732 case opc_goto: case opc_jsr: case opc_ifeq: 733 case opc_ifne: case opc_ifgt: case opc_ifge: 734 case opc_iflt: case opc_ifle: case opc_ifnull: 735 case opc_ifnonnull: case opc_if_acmpeq: case opc_if_acmpne: 736 case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpgt: 737 case opc_if_icmpge: case opc_if_icmplt: case opc_if_icmple: 738 out.writeByte(opc); 739 out.writeShort(((Instruction)value).pc - pc); 740 break; 741 742 case opc_goto_w: 743 case opc_jsr_w: 744 out.writeByte(opc); 745 out.writeLong(((Instruction)value).pc - pc); 746 break; 747 748 case opc_tableswitch: { 749 SwitchData sw = (SwitchData)value; 750 out.writeByte(opc); 751 for(int n = 1 ; ((pc + n) % 4) != 0 ; n++) { 752 out.writeByte(0); 753 } 754 out.writeInt(sw.defaultLabel.pc - pc); 755 out.writeInt(sw.minValue); 756 out.writeInt(sw.maxValue); 757 for (int n = sw.minValue ; n <= sw.maxValue ; n++) { 758 Label lbl = sw.get(n); 759 int target_pc = (lbl != null) ? lbl.pc : sw.defaultLabel.pc; 760 out.writeInt(target_pc - pc); 761 } 762 break; 763 } 764 765 case opc_lookupswitch: { 766 SwitchData sw = (SwitchData)value; 767 out.writeByte(opc); 768 int n = pc + 1; 769 for(; (n % 4) != 0 ; n++) { 770 out.writeByte(0); 771 } 772 out.writeInt(sw.defaultLabel.pc - pc); 773 out.writeInt(sw.tab.size()); 774 for (Enumeration<Integer> e = sw.sortedKeys(); e.hasMoreElements() ; ) { 775 Integer v = e.nextElement(); 776 out.writeInt(v.intValue()); 777 out.writeInt(sw.get(v).pc - pc); 778 } 779 break; 780 } 781 782 case opc_nop: 783 if (value != null) { 784 if (value instanceof Integer) 785 out.writeByte(((Integer)value).intValue()); 786 else 787 out.writeShort(tab.index(value)); 788 return; 789 } 790 // fall through 791 792 default: 793 out.writeByte(opc); 794 break; 795 } 796 } 797 798 /** 799 * toString 800 */ toString()801 public String toString() { 802 String prefix = (where >> WHEREOFFSETBITS) + ":\t"; 803 switch (opc) { 804 case opc_try: 805 return prefix + "try " + ((TryData)value).getEndLabel().hashCode(); 806 807 case opc_dead: 808 return prefix + "dead"; 809 810 case opc_iinc: { 811 int register = ((int[])value)[0]; 812 int increment = ((int[])value)[1]; 813 return prefix + opcNames[opc] + " " + register + ", " + increment; 814 } 815 816 default: 817 if (value != null) { 818 if (value instanceof Label) { 819 return prefix + opcNames[opc] + " " + value.toString(); 820 } else if (value instanceof Instruction) { 821 return prefix + opcNames[opc] + " " + value.hashCode(); 822 } else if (value instanceof String) { 823 return prefix + opcNames[opc] + " \"" + value + "\""; 824 } else { 825 return prefix + opcNames[opc] + " " + value; 826 } 827 } else { 828 return prefix + opcNames[opc]; 829 } 830 } 831 } 832 } 833