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