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 }