1 /* 2 * Copyright (c) 2001, 2005, 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 com.sun.java.util.jar.pack; 27 28 import java.io.IOException; 29 30 /** 31 * A parsed bytecode instruction. 32 * Provides accessors to various relevant bits. 33 * @author John Rose 34 */ 35 class Instruction implements Constants { 36 protected byte[] bytes; // bytecodes 37 protected int pc; // location of this instruction 38 protected int bc; // opcode of this instruction 39 protected int w; // 0 if normal, 1 if a _wide prefix at pc 40 protected int length; // bytes in this instruction 41 42 protected boolean special; 43 44 protected Instruction(byte[] bytes, int pc, int bc, int w, int length) { 45 reset(bytes, pc, bc, w, length); 46 } 47 private void reset(byte[] bytes, int pc, int bc, int w, int length) { 48 this.bytes = bytes; 49 this.pc = pc; 50 this.bc = bc; 51 this.w = w; 52 this.length = length; 53 } 54 55 public int getBC() { 56 return bc; 57 } 58 public boolean isWide() { 59 return w != 0; 60 } 61 public byte[] getBytes() { 62 return bytes; 63 } 64 public int getPC() { 65 return pc; 66 } 67 public int getLength() { 68 return length; 69 } 70 public int getNextPC() { 71 return pc + length; 72 } 73 74 public Instruction next() { 75 int npc = pc + length; 76 if (npc == bytes.length) 77 return null; 78 else 79 return Instruction.at(bytes, npc, this); 80 } 81 82 public boolean isNonstandard() { 83 return isNonstandard(bc); 84 } 85 86 public void setNonstandardLength(int length) { 87 assert(isNonstandard()); 88 this.length = length; 89 } 90 91 92 /** A fake instruction at this pc whose next() will be at nextpc. */ 93 public Instruction forceNextPC(int nextpc) { 94 int length = nextpc - pc; 95 return new Instruction(bytes, pc, -1, -1, length); 96 } 97 98 public static Instruction at(byte[] bytes, int pc) { 99 return Instruction.at(bytes, pc, null); 100 } 101 102 public static Instruction at(byte[] bytes, int pc, Instruction reuse) { 103 int bc = getByte(bytes, pc); 104 int prefix = -1; 105 int w = 0; 106 int length = BC_LENGTH[w][bc]; 107 if (length == 0) { 108 // Hard cases: 109 switch (bc) { 110 case _wide: 111 bc = getByte(bytes, pc+1); 112 w = 1; 113 length = BC_LENGTH[w][bc]; 114 if (length == 0) { 115 // unknown instruction; treat as one byte 116 length = 1; 117 } 118 break; 119 case _tableswitch: 120 return new TableSwitch(bytes, pc); 121 case _lookupswitch: 122 return new LookupSwitch(bytes, pc); 123 default: 124 // unknown instruction; treat as one byte 125 length = 1; 126 break; 127 } 128 } 129 assert(length > 0); 130 assert(pc+length <= bytes.length); 131 // Speed hack: Instruction.next reuses self if possible. 132 if (reuse != null && !reuse.special) { 133 reuse.reset(bytes, pc, bc, w, length); 134 return reuse; 135 } 136 return new Instruction(bytes, pc, bc, w, length); 137 } 138 139 // Return the constant pool reference type, or 0 if none. 140 public byte getCPTag() { 141 return BC_TAG[w][bc]; 142 } 143 144 // Return the constant pool index, or -1 if none. 145 public int getCPIndex() { 146 int indexLoc = BC_INDEX[w][bc]; 147 if (indexLoc == 0) return -1; 148 assert(w == 0); 149 if (length == 2) 150 return getByte(bytes, pc+indexLoc); // _ldc opcode only 151 else 152 return getShort(bytes, pc+indexLoc); 153 } 154 155 public void setCPIndex(int cpi) { 156 int indexLoc = BC_INDEX[w][bc]; 157 assert(indexLoc != 0); 158 if (length == 2) 159 setByte(bytes, pc+indexLoc, cpi); // _ldc opcode only 160 else 161 setShort(bytes, pc+indexLoc, cpi); 162 assert(getCPIndex() == cpi); 163 } 164 165 public ConstantPool.Entry getCPRef(ConstantPool.Entry[] cpMap) { 166 int index = getCPIndex(); 167 return (index < 0) ? null : cpMap[index]; 168 } 169 170 // Return the slot of the affected local, or -1 if none. 171 public int getLocalSlot() { 172 int slotLoc = BC_SLOT[w][bc]; 173 if (slotLoc == 0) return -1; 174 if (w == 0) 175 return getByte(bytes, pc+slotLoc); 176 else 177 return getShort(bytes, pc+slotLoc); 178 } 179 180 // Return the target of the branch, or -1 if none. 181 public int getBranchLabel() { 182 int branchLoc = BC_BRANCH[w][bc]; 183 if (branchLoc == 0) return -1; 184 assert(w == 0); 185 assert(length == 3 || length == 5); 186 int offset; 187 if (length == 3) 188 offset = (short)getShort(bytes, pc+branchLoc); 189 else 190 offset = getInt(bytes, pc+branchLoc); 191 assert(offset+pc >= 0); 192 assert(offset+pc <= bytes.length); 193 return offset+pc; 194 } 195 196 public void setBranchLabel(int targetPC) { 197 int branchLoc = BC_BRANCH[w][bc]; 198 assert(branchLoc != 0); 199 if (length == 3) 200 setShort(bytes, pc+branchLoc, targetPC-pc); 201 else 202 setInt(bytes, pc+branchLoc, targetPC-pc); 203 assert(targetPC == getBranchLabel()); 204 } 205 206 // Return the trailing constant in the instruction (as a signed value). 207 // Return 0 if there is none. 208 public int getConstant() { 209 int conLoc = BC_CON[w][bc]; 210 if (conLoc == 0) return 0; 211 switch (length - conLoc) { 212 case 1: return (byte) getByte(bytes, pc+conLoc); 213 case 2: return (short) getShort(bytes, pc+conLoc); 214 } 215 assert(false); 216 return 0; 217 } 218 219 public void setConstant(int con) { 220 int conLoc = BC_CON[w][bc]; 221 assert(conLoc != 0); 222 switch (length - conLoc) { 223 case 1: setByte(bytes, pc+conLoc, con); break; 224 case 2: setShort(bytes, pc+conLoc, con); break; 225 } 226 assert(con == getConstant()); 227 } 228 229 public abstract static class Switch extends Instruction { 230 // Each case is a (value, label) pair, indexed 0 <= n < caseCount 231 public abstract int getCaseCount(); 232 public abstract int getCaseValue(int n); 233 public abstract int getCaseLabel(int n); 234 public abstract void setCaseCount(int caseCount); 235 public abstract void setCaseValue(int n, int value); 236 public abstract void setCaseLabel(int n, int targetPC); 237 protected abstract int getLength(int caseCount); 238 239 public int getDefaultLabel() { return intAt(0)+pc; } 240 public void setDefaultLabel(int targetPC) { setIntAt(0, targetPC-pc); } 241 242 protected int apc; // aligned pc (table base) 243 protected int intAt(int n) { return getInt(bytes, apc + n*4); } 244 protected void setIntAt(int n, int x) { setInt(bytes, apc + n*4, x); } 245 protected Switch(byte[] bytes, int pc, int bc) { 246 super(bytes, pc, bc, /*w*/0, /*length*/0); 247 this.apc = alignPC(pc+1); 248 this.special = true; 249 length = getLength(getCaseCount()); 250 } 251 public int getAlignedPC() { return apc; } 252 public String toString() { 253 String s = super.toString(); 254 s += " Default:"+labstr(getDefaultLabel()); 255 int caseCount = getCaseCount(); 256 for (int i = 0; i < caseCount; i++) { 257 s += "\n\tCase "+getCaseValue(i)+":"+labstr(getCaseLabel(i)); 258 } 259 return s; 260 } 261 public static int alignPC(int apc) { 262 while (apc % 4 != 0) ++apc; 263 return apc; 264 } 265 } 266 267 public static class TableSwitch extends Switch { 268 // apc: (df, lo, hi, (hi-lo+1)*(label)) 269 public int getLowCase() { return intAt(1); } 270 public int getHighCase() { return intAt(2); } 271 public int getCaseCount() { return intAt(2)-intAt(1)+1; } 272 public int getCaseValue(int n) { return getLowCase()+n; } 273 public int getCaseLabel(int n) { return intAt(3+n)+pc; } 274 275 public void setLowCase(int val) { setIntAt(1, val); } 276 public void setHighCase(int val) { setIntAt(2, val); } 277 public void setCaseLabel(int n, int tpc) { setIntAt(3+n, tpc-pc); } 278 public void setCaseCount(int caseCount) { 279 setHighCase(getLowCase() + caseCount - 1); 280 length = getLength(caseCount); 281 } 282 public void setCaseValue(int n, int val) { 283 if (n != 0) throw new UnsupportedOperationException(); 284 int caseCount = getCaseCount(); 285 setLowCase(val); 286 setCaseCount(caseCount); // keep invariant 287 } 288 289 TableSwitch(byte[] bytes, int pc) { 290 super(bytes, pc, _tableswitch); 291 } 292 protected int getLength(int caseCount) { 293 return (apc-pc) + (3 + caseCount) * 4; 294 } 295 } 296 297 public static class LookupSwitch extends Switch { 298 // apc: (df, nc, nc*(case, label)) 299 public int getCaseCount() { return intAt(1); } 300 public int getCaseValue(int n) { return intAt(2+n*2+0); } 301 public int getCaseLabel(int n) { return intAt(2+n*2+1)+pc; } 302 303 public void setCaseCount(int caseCount) { 304 setIntAt(1, caseCount); 305 length = getLength(caseCount); 306 } 307 public void setCaseValue(int n, int val) { setIntAt(2+n*2+0, val); } 308 public void setCaseLabel(int n, int tpc) { setIntAt(2+n*2+1, tpc-pc); } 309 310 LookupSwitch(byte[] bytes, int pc) { 311 super(bytes, pc, _lookupswitch); 312 } 313 protected int getLength(int caseCount) { 314 return (apc-pc) + (2 + caseCount*2) * 4; 315 } 316 } 317 318 /** Two insns are equal if they have the same bytes. */ 319 public boolean equals(Object o) { 320 return (o instanceof Instruction) && equals((Instruction)o); 321 } 322 323 public boolean equals(Instruction that) { 324 if (this.bc != that.bc) return false; 325 if (this.w != that.w) return false; 326 if (this.length != that.length) return false; 327 for (int i = 1; i < length; i++) { 328 if (this.bytes[this.pc+i] != that.bytes[that.pc+i]) 329 return false; 330 } 331 return true; 332 } 333 334 static String labstr(int pc) { 335 if (pc >= 0 && pc < 100000) 336 return ((100000+pc)+"").substring(1); 337 return pc+""; 338 } 339 public String toString() { 340 return toString(null); 341 } 342 public String toString(ConstantPool.Entry[] cpMap) { 343 String s = labstr(pc) + ": "; 344 if (bc >= _bytecode_limit) { 345 s += Integer.toHexString(bc); 346 return s; 347 } 348 if (w == 1) s += "wide "; 349 String bcname = (bc < BC_NAME.length)? BC_NAME[bc]: null; 350 if (bcname == null) { 351 return s+"opcode#"+bc; 352 } 353 s += bcname; 354 int tag = getCPTag(); 355 if (tag != 0) s += " "+ConstantPool.tagName(tag)+":"; 356 int idx = getCPIndex(); 357 if (idx >= 0) s += (cpMap == null) ? ""+idx : "="+cpMap[idx].stringValue(); 358 int slt = getLocalSlot(); 359 if (slt >= 0) s += " Local:"+slt; 360 int lab = getBranchLabel(); 361 if (lab >= 0) s += " To:"+labstr(lab); 362 int con = getConstant(); 363 if (con != 0) s += " Con:"+con; 364 return s; 365 } 366 367 368 //public static byte constantPoolTagFor(int bc) { return BC_TAG[0][bc]; } 369 370 /// Fetching values from byte arrays: 371 372 public int getIntAt(int off) { 373 return getInt(bytes, pc+off); 374 } 375 public int getShortAt(int off) { 376 return getShort(bytes, pc+off); 377 } 378 public int getByteAt(int off) { 379 return getByte(bytes, pc+off); 380 } 381 382 383 public static int getInt(byte[] bytes, int pc) { 384 return (getShort(bytes, pc+0) << 16) + (getShort(bytes, pc+2) << 0); 385 } 386 public static int getShort(byte[] bytes, int pc) { 387 return (getByte(bytes, pc+0) << 8) + (getByte(bytes, pc+1) << 0); 388 } 389 public static int getByte(byte[] bytes, int pc) { 390 return bytes[pc] & 0xFF; 391 } 392 393 394 public static void setInt(byte[] bytes, int pc, int x) { 395 setShort(bytes, pc+0, x >> 16); 396 setShort(bytes, pc+2, x >> 0); 397 } 398 public static void setShort(byte[] bytes, int pc, int x) { 399 setByte(bytes, pc+0, x >> 8); 400 setByte(bytes, pc+1, x >> 0); 401 } 402 public static void setByte(byte[] bytes, int pc, int x) { 403 bytes[pc] = (byte)x; 404 } 405 406 // some bytecode classifiers 407 408 409 public static boolean isNonstandard(int bc) { 410 return BC_LENGTH[0][bc] < 0; 411 } 412 413 public static int opLength(int bc) { 414 int l = BC_LENGTH[0][bc]; 415 assert(l > 0); 416 return l; 417 } 418 public static int opWideLength(int bc) { 419 int l = BC_LENGTH[1][bc]; 420 assert(l > 0); 421 return l; 422 } 423 424 public static boolean isLocalSlotOp(int bc) { 425 return (bc < BC_SLOT[0].length && BC_SLOT[0][bc] > 0); 426 } 427 428 public static boolean isBranchOp(int bc) { 429 return (bc < BC_BRANCH[0].length && BC_BRANCH[0][bc] > 0); 430 } 431 432 public static boolean isCPRefOp(int bc) { 433 if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0) return true; 434 if (bc >= _xldc_op && bc < _xldc_limit) return true; 435 return false; 436 } 437 438 public static byte getCPRefOpTag(int bc) { 439 if (bc < BC_INDEX[0].length && BC_INDEX[0][bc] > 0) return BC_TAG[0][bc]; 440 if (bc >= _xldc_op && bc < _xldc_limit) return CONSTANT_Literal; 441 return CONSTANT_None; 442 } 443 444 public static boolean isFieldOp(int bc) { 445 return (bc >= _getstatic && bc <= _putfield); 446 } 447 448 public static boolean isInvokeInitOp(int bc) { 449 return (bc >= _invokeinit_op && bc < _invokeinit_limit); 450 } 451 452 public static boolean isSelfLinkerOp(int bc) { 453 return (bc >= _self_linker_op && bc < _self_linker_limit); 454 } 455 456 /// Format definitions. 457 458 static private final byte[][] BC_LENGTH = new byte[2][0x100]; 459 static private final byte[][] BC_INDEX = new byte[2][0x100]; 460 static private final byte[][] BC_TAG = new byte[2][0x100]; 461 static private final byte[][] BC_BRANCH = new byte[2][0x100]; 462 static private final byte[][] BC_SLOT = new byte[2][0x100]; 463 static private final byte[][] BC_CON = new byte[2][0x100]; 464 static private final String[] BC_NAME = new String[0x100]; // debug only 465 static private final String[][] BC_FORMAT = new String[2][_bytecode_limit]; // debug only 466 static { 467 for (int i = 0; i < _bytecode_limit; i++) { 468 BC_LENGTH[0][i] = -1; 469 BC_LENGTH[1][i] = -1; 470 } 471 def("b", _nop, _dconst_1); 472 def("bx", _bipush); 473 def("bxx", _sipush); 474 def("bk", _ldc); // do not pack 475 def("bkk", _ldc_w, _ldc2_w); // do not pack 476 def("blwbll", _iload, _aload); 477 def("b", _iload_0, _saload); 478 def("blwbll", _istore, _astore); 479 def("b", _istore_0, _lxor); 480 def("blxwbllxx", _iinc); 481 def("b", _i2l, _dcmpg); 482 def("boo", _ifeq, _jsr); // pack oo 483 def("blwbll", _ret); 484 def("", _tableswitch, _lookupswitch); // pack all ints, omit padding 485 def("b", _ireturn, _return); 486 def("bkf", _getstatic, _putfield); // pack kf (base=Field) 487 def("bkm", _invokevirtual, _invokestatic); // pack kn (base=Method) 488 def("bkixx", _invokeinterface); // pack ki (base=IMethod), omit xx 489 def("", _xxxunusedxxx); 490 def("bkc", _new); // pack kc 491 def("bx", _newarray); 492 def("bkc", _anewarray); // pack kc 493 def("b", _arraylength, _athrow); 494 def("bkc", _checkcast, _instanceof); // pack kc 495 def("b", _monitorenter, _monitorexit); 496 def("", _wide); 497 def("bkcx", _multianewarray); // pack kc 498 def("boo", _ifnull, _ifnonnull); // pack oo 499 def("boooo", _goto_w, _jsr_w); // pack oooo 500 for (int i = 0; i < _bytecode_limit; i++) { 501 //System.out.println(i+": l="+BC_LENGTH[0][i]+" i="+BC_INDEX[0][i]); 502 //assert(BC_LENGTH[0][i] != -1); 503 if (BC_LENGTH[0][i] == -1) { 504 assert(i == _xxxunusedxxx); 505 continue; // unknown opcode 506 } 507 508 // Have a complete mapping, to support spurious _wide prefixes. 509 if (BC_LENGTH[1][i] == -1) 510 BC_LENGTH[1][i] = (byte)(1+BC_LENGTH[0][i]); 511 } 512 513 String names = 514 "nop aconst_null iconst_m1 iconst_0 iconst_1 iconst_2 iconst_3 iconst_4 "+ 515 "iconst_5 lconst_0 lconst_1 fconst_0 fconst_1 fconst_2 dconst_0 dconst_1 "+ 516 "bipush sipush ldc ldc_w ldc2_w iload lload fload dload aload iload_0 "+ 517 "iload_1 iload_2 iload_3 lload_0 lload_1 lload_2 lload_3 fload_0 fload_1 "+ 518 "fload_2 fload_3 dload_0 dload_1 dload_2 dload_3 aload_0 aload_1 aload_2 "+ 519 "aload_3 iaload laload faload daload aaload baload caload saload istore "+ 520 "lstore fstore dstore astore istore_0 istore_1 istore_2 istore_3 lstore_0 "+ 521 "lstore_1 lstore_2 lstore_3 fstore_0 fstore_1 fstore_2 fstore_3 dstore_0 "+ 522 "dstore_1 dstore_2 dstore_3 astore_0 astore_1 astore_2 astore_3 iastore "+ 523 "lastore fastore dastore aastore bastore castore sastore pop pop2 dup "+ 524 "dup_x1 dup_x2 dup2 dup2_x1 dup2_x2 swap iadd ladd fadd dadd isub lsub "+ 525 "fsub dsub imul lmul fmul dmul idiv ldiv fdiv ddiv irem lrem frem drem "+ 526 "ineg lneg fneg dneg ishl lshl ishr lshr iushr lushr iand land ior lor "+ 527 "ixor lxor iinc i2l i2f i2d l2i l2f l2d f2i f2l f2d d2i d2l d2f i2b i2c "+ 528 "i2s lcmp fcmpl fcmpg dcmpl dcmpg ifeq ifne iflt ifge ifgt ifle if_icmpeq "+ 529 "if_icmpne if_icmplt if_icmpge if_icmpgt if_icmple if_acmpeq if_acmpne "+ 530 "goto jsr ret tableswitch lookupswitch ireturn lreturn freturn dreturn "+ 531 "areturn return getstatic putstatic getfield putfield invokevirtual "+ 532 "invokespecial invokestatic invokeinterface xxxunusedxxx new newarray "+ 533 "anewarray arraylength athrow checkcast instanceof monitorenter "+ 534 "monitorexit wide multianewarray ifnull ifnonnull goto_w jsr_w "; 535 for (int bc = 0; names.length() > 0; bc++) { 536 int sp = names.indexOf(' '); 537 BC_NAME[bc] = names.substring(0, sp); 538 names = names.substring(sp+1); 539 } 540 } 541 public static String byteName(int bc) { 542 String iname; 543 if (bc < BC_NAME.length && BC_NAME[bc] != null) { 544 iname = BC_NAME[bc]; 545 } else if (isSelfLinkerOp(bc)) { 546 int idx = (bc - _self_linker_op); 547 boolean isSuper = (idx >= _self_linker_super_flag); 548 if (isSuper) idx -= _self_linker_super_flag; 549 boolean isAload = (idx >= _self_linker_aload_flag); 550 if (isAload) idx -= _self_linker_aload_flag; 551 int origBC = _first_linker_op + idx; 552 assert(origBC >= _first_linker_op && origBC <= _last_linker_op); 553 iname = BC_NAME[origBC]; 554 iname += (isSuper ? "_super" : "_this"); 555 if (isAload) iname = "aload_0&" + iname; 556 iname = "*"+iname; 557 } else if (isInvokeInitOp(bc)) { 558 int idx = (bc - _invokeinit_op); 559 switch (idx) { 560 case _invokeinit_self_option: 561 iname = "*invokespecial_init_this"; break; 562 case _invokeinit_super_option: 563 iname = "*invokespecial_init_super"; break; 564 default: 565 assert(idx == _invokeinit_new_option); 566 iname = "*invokespecial_init_new"; break; 567 } 568 } else { 569 switch (bc) { 570 case _ildc: iname = "*ildc"; break; 571 case _fldc: iname = "*fldc"; break; 572 case _ildc_w: iname = "*ildc_w"; break; 573 case _fldc_w: iname = "*fldc_w"; break; 574 case _dldc2_w: iname = "*dldc2_w"; break; 575 case _cldc: iname = "*cldc"; break; 576 case _cldc_w: iname = "*cldc_w"; break; 577 case _byte_escape: iname = "*byte_escape"; break; 578 case _ref_escape: iname = "*ref_escape"; break; 579 case _end_marker: iname = "*end"; break; 580 default: iname = "*bc#"+bc; break; 581 } 582 } 583 return iname; 584 } 585 private static int BW = 4; // width of classification field 586 private static void def(String fmt, int bc) { 587 def(fmt, bc, bc); 588 } 589 private static void def(String fmt, int from_bc, int to_bc) { 590 String[] fmts = { fmt, null }; 591 if (fmt.indexOf('w') > 0) { 592 fmts[1] = fmt.substring(fmt.indexOf('w')); 593 fmts[0] = fmt.substring(0, fmt.indexOf('w')); 594 } 595 for (int w = 0; w <= 1; w++) { 596 fmt = fmts[w]; 597 if (fmt == null) continue; 598 int length = fmt.length(); 599 int index = Math.max(0, fmt.indexOf('k')); 600 int tag = CONSTANT_None; 601 int branch = Math.max(0, fmt.indexOf('o')); 602 int slot = Math.max(0, fmt.indexOf('l')); 603 int con = Math.max(0, fmt.indexOf('x')); 604 if (index > 0 && index+1 < length) { 605 switch (fmt.charAt(index+1)) { 606 case 'c': tag = CONSTANT_Class; break; 607 case 'k': tag = CONSTANT_Literal; break; 608 case 'f': tag = CONSTANT_Fieldref; break; 609 case 'm': tag = CONSTANT_Methodref; break; 610 case 'i': tag = CONSTANT_InterfaceMethodref; break; 611 } 612 assert(tag != CONSTANT_None); 613 } else if (index > 0 && length == 2) { 614 assert(from_bc == _ldc); 615 tag = CONSTANT_Literal; // _ldc opcode only 616 } 617 for (int bc = from_bc; bc <= to_bc; bc++) { 618 BC_FORMAT[w][bc] = fmt; 619 assert(BC_LENGTH[w][bc] == -1); 620 BC_LENGTH[w][bc] = (byte) length; 621 BC_INDEX[w][bc] = (byte) index; 622 BC_TAG[w][bc] = (byte) tag; 623 assert(!(index == 0 && tag != CONSTANT_None)); 624 BC_BRANCH[w][bc] = (byte) branch; 625 BC_SLOT[w][bc] = (byte) slot; 626 assert(branch == 0 || slot == 0); // not both branch & local 627 assert(branch == 0 || index == 0); // not both branch & cp 628 assert(slot == 0 || index == 0); // not both local & cp 629 BC_CON[w][bc] = (byte) con; 630 } 631 } 632 } 633 634 public static void opcodeChecker(byte[] code) throws FormatException { 635 Instruction i = at(code, 0); 636 while (i != null) { 637 int opcode = i.getBC(); 638 if (opcode == _xxxunusedxxx || opcode < _nop || opcode > _jsr_w) { 639 String message = "illegal opcode: " + opcode + " " + i; 640 throw new FormatException(message); 641 } 642 i = i.next(); 643 } 644 } 645 static class FormatException extends IOException { 646 FormatException(String message) { 647 super(message); 648 } 649 } 650 }