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 }