1 /*
   2  * Copyright (c) 2009, 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.tools.classfile;
  27 
  28 import java.util.Locale;
  29 
  30 /**
  31  * See JVMS, chapter 6.
  32  *
  33  *  <p><b>This is NOT part of any supported API.
  34  *  If you write code that depends on this, you do so at your own risk.
  35  *  This code and its internal interfaces are subject to change or
  36  *  deletion without notice.</b>
  37  *
  38  * @see Code_attribute#getInstructions
  39  */
  40 public class Instruction {
  41     /** The kind of an instruction, as determined by the position, size and
  42      *  types of its operands. */
  43     public static enum Kind {
  44         /** Opcode is not followed by any operands. */
  45         NO_OPERANDS(1),
  46         /** Opcode is followed by a byte indicating a type. */
  47         ATYPE(2),
  48         /** Opcode is followed by a 2-byte branch offset. */
  49         BRANCH(3),
  50         /** Opcode is followed by a 4-byte branch offset. */
  51         BRANCH_W(5),
  52         /** Opcode is followed by a signed byte value. */
  53         BYTE(2),
  54         /** Opcode is followed by a 1-byte index into the constant pool. */
  55         CPREF(2),
  56         /** Opcode is followed by a 2-byte index into the constant pool. */
  57         CPREF_W(3),
  58         /** Opcode is followed by a 2-byte index into the constant pool,
  59          *  an unsigned byte value. */
  60         CPREF_W_UBYTE(4),
  61         /** Opcode is followed by a 2-byte index into the constant pool.,
  62          *  an unsigned byte value, and a zero byte. */
  63         CPREF_W_UBYTE_ZERO(5),
  64         /** Opcode is followed by variable number of operands, depending
  65          * on the instruction.*/
  66         DYNAMIC(-1),
  67         /** Opcode is followed by a 1-byte reference to a local variable. */
  68         LOCAL(2),
  69         /** Opcode is followed by a 1-byte reference to a local variable,
  70          *  and a signed byte value. */
  71         LOCAL_BYTE(3),
  72         /** Opcode is followed by a signed short value. */
  73         SHORT(3),
  74         /** Wide opcode is not followed by any operands. */
  75         WIDE_NO_OPERANDS(2),
  76         /** Wide opcode is followed by a 2-byte index into the local variables array. */
  77         WIDE_LOCAL(4),
  78         /** Wide opcode is followed by a 2-byte index into the constant pool. */
  79         WIDE_CPREF_W(4),
  80         /** Wide opcode is followed by a 2-byte index into the constant pool,
  81          *  and a signed short value. */
  82         WIDE_CPREF_W_SHORT(6),
  83         /** Wide opcode is followed by a 2-byte reference to a local variable,
  84          *  and a signed short value. */
  85         WIDE_LOCAL_SHORT(6),
  86         /** Opcode was not recognized. */
  87         UNKNOWN(1);
  88 
  89         Kind(int length) {
  90             this.length = length;
  91         }
  92 
  93         /** The length, in bytes, of this kind of instruction, or -1 is the
  94          *  length depends on the specific instruction. */
  95         public final int length;
  96     }
  97 
  98     /** A utility visitor to help decode the operands of an instruction.
  99      *  @see Instruction#accept */
 100     public interface KindVisitor<R,P> {
 101         /** See {@link Kind#NO_OPERANDS}, {@link Kind#WIDE_NO_OPERANDS}. */
 102         R visitNoOperands(Instruction instr, P p);
 103         /** See {@link Kind#ATYPE}. */
 104         R visitArrayType(Instruction instr, TypeKind kind, P p);
 105         /** See {@link Kind#BRANCH}, {@link Kind#BRANCH_W}. */
 106         R visitBranch(Instruction instr, int offset, P p);
 107         /** See {@link Kind#CPREF}, {@link Kind#CPREF_W}, {@link Kind#WIDE_CPREF_W}. */
 108         R visitConstantPoolRef(Instruction instr, int index, P p);
 109         /** See {@link Kind#CPREF_W_UBYTE}, {@link Kind#CPREF_W_UBYTE_ZERO}, {@link Kind#WIDE_CPREF_W_SHORT}. */
 110         R visitConstantPoolRefAndValue(Instruction instr, int index, int value, P p);
 111         /** See {@link Kind#LOCAL}, {@link Kind#WIDE_LOCAL}. */
 112         R visitLocal(Instruction instr, int index, P p);
 113         /** See {@link Kind#LOCAL_BYTE}. */
 114         R visitLocalAndValue(Instruction instr, int index, int value, P p);
 115         /** See {@link Kind#DYNAMIC}. */
 116         R visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets, P p);
 117         /** See {@link Kind#DYNAMIC}. */
 118         R visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets, P p);
 119         /** See {@link Kind#BYTE}, {@link Kind#SHORT}. */
 120         R visitValue(Instruction instr, int value, P p);
 121         /** Instruction is unrecognized. */
 122         R visitUnknown(Instruction instr, P p);
 123 
 124     }
 125 
 126     /** The kind of primitive array type to create.
 127      *  See JVMS chapter 6, newarray. */
 128     public static enum TypeKind {
 129         T_BOOLEAN(4, "boolean"),
 130         T_CHAR(5, "char"),
 131         T_FLOAT(6, "float"),
 132         T_DOUBLE(7, "double"),
 133         T_BYTE(8, "byte"),
 134         T_SHORT(9, "short"),
 135         T_INT (10, "int"),
 136         T_LONG (11, "long");
 137         TypeKind(int value, String name) {
 138             this.value = value;
 139             this.name = name;
 140         }
 141 
 142         public static TypeKind get(int value) {
 143             switch (value) {
 144                 case  4: return T_BOOLEAN;
 145                 case  5: return T_CHAR;
 146                 case  6: return T_FLOAT;
 147                 case  7: return T_DOUBLE;
 148                 case  8: return T_BYTE;
 149                 case  9: return T_SHORT;
 150                 case  10: return T_INT;
 151                 case  11: return T_LONG;
 152                 default: return null;
 153             }
 154         }
 155 
 156         public final int value;
 157         public final String name;
 158     }
 159 
 160     /** An instruction is defined by its position in a bytecode array. */
 161     public Instruction(byte[] bytes, int pc) {
 162         this.bytes = bytes;
 163         this.pc = pc;
 164     }
 165 
 166     /** Get the position of the instruction within the bytecode array. */
 167     public int getPC() {
 168         return pc;
 169     }
 170 
 171     /** Get a byte value, relative to the start of this instruction. */
 172     public int getByte(int offset) {
 173         return bytes[pc + offset];
 174     }
 175 
 176     /** Get an unsigned byte value, relative to the start of this instruction. */
 177     public int getUnsignedByte(int offset) {
 178         return getByte(offset) & 0xff;
 179     }
 180 
 181     /** Get a 2-byte value, relative to the start of this instruction. */
 182     public int getShort(int offset) {
 183         return (getByte(offset) << 8) | getUnsignedByte(offset + 1);
 184     }
 185 
 186     /** Get a unsigned 2-byte value, relative to the start of this instruction. */
 187     public int getUnsignedShort(int offset) {
 188         return getShort(offset) & 0xFFFF;
 189     }
 190 
 191     /** Get a 4-byte value, relative to the start of this instruction. */
 192     public int getInt(int offset) {
 193         return (getShort(offset) << 16) | (getUnsignedShort(offset + 2));
 194     }
 195 
 196     /** Get the Opcode for this instruction, or null if the instruction is
 197      * unrecognized. */
 198     public Opcode getOpcode() {
 199         int b = getUnsignedByte(0);
 200         switch (b) {
 201             case Opcode.NONPRIV:
 202             case Opcode.PRIV:
 203             case Opcode.WIDE:
 204                 return Opcode.get(b, getUnsignedByte(1));
 205         }
 206         return Opcode.get(b);
 207     }
 208 
 209     /** Get the mnemonic for this instruction, or a default string if the
 210      * instruction is unrecognized. */
 211     public String getMnemonic() {
 212         Opcode opcode = getOpcode();
 213         if (opcode == null)
 214             return "bytecode " + getUnsignedByte(0);
 215         else
 216             return opcode.toString().toLowerCase(Locale.US);
 217     }
 218 
 219     /** Get the length, in bytes, of this instruction, including the opcode
 220      * and all its operands. */
 221     public int length() {
 222         Opcode opcode = getOpcode();
 223         if (opcode == null)
 224             return 1;
 225 
 226         switch (opcode) {
 227             case TABLESWITCH: {
 228                 int pad = align(pc + 1) - pc;
 229                 int low = getInt(pad + 4);
 230                 int high = getInt(pad + 8);
 231                 return pad + 12 + 4 * (high - low + 1);
 232             }
 233             case LOOKUPSWITCH: {
 234                 int pad = align(pc + 1) - pc;
 235                 int npairs = getInt(pad + 4);
 236                 return pad + 8 + 8 * npairs;
 237 
 238             }
 239             default:
 240                 return opcode.kind.length;
 241         }
 242     }
 243 
 244     /** Get the {@link Kind} of this instruction. */
 245     public Kind getKind() {
 246         Opcode opcode = getOpcode();
 247         return (opcode != null ? opcode.kind : Kind.UNKNOWN);
 248     }
 249 
 250     /** Invoke a method on the visitor according to the kind of this
 251      * instruction, passing in the decoded operands for the instruction. */
 252     public <R,P> R accept(KindVisitor<R,P> visitor, P p) {
 253         switch (getKind()) {
 254             case NO_OPERANDS:
 255                 return visitor.visitNoOperands(this, p);
 256 
 257             case ATYPE:
 258                 return visitor.visitArrayType(
 259                         this, TypeKind.get(getUnsignedByte(1)), p);
 260 
 261             case BRANCH:
 262                 return visitor.visitBranch(this, getShort(1), p);
 263 
 264             case BRANCH_W:
 265                 return visitor.visitBranch(this, getInt(1), p);
 266 
 267             case BYTE:
 268                 return visitor.visitValue(this, getByte(1), p);
 269 
 270             case CPREF:
 271                 return visitor.visitConstantPoolRef(this, getUnsignedByte(1), p);
 272 
 273             case CPREF_W:
 274                 return visitor.visitConstantPoolRef(this, getUnsignedShort(1), p);
 275 
 276             case CPREF_W_UBYTE:
 277             case CPREF_W_UBYTE_ZERO:
 278                 return visitor.visitConstantPoolRefAndValue(
 279                         this, getUnsignedShort(1), getUnsignedByte(3), p);
 280 
 281             case DYNAMIC: {
 282                 switch (getOpcode()) {
 283                     case TABLESWITCH: {
 284                         int pad = align(pc + 1) - pc;
 285                         int default_ = getInt(pad);
 286                         int low = getInt(pad + 4);
 287                         int high = getInt(pad + 8);
 288                         int[] values = new int[high - low + 1];
 289                         for (int i = 0; i < values.length; i++)
 290                             values[i] = getInt(pad + 12 + 4 * i);
 291                         return visitor.visitTableSwitch(
 292                                 this, default_, low, high, values, p);
 293                     }
 294                     case LOOKUPSWITCH: {
 295                         int pad = align(pc + 1) - pc;
 296                         int default_ = getInt(pad);
 297                         int npairs = getInt(pad + 4);
 298                         int[] matches = new int[npairs];
 299                         int[] offsets = new int[npairs];
 300                         for (int i = 0; i < npairs; i++) {
 301                             matches[i] = getInt(pad +  8 + i * 8);
 302                             offsets[i] = getInt(pad + 12 + i * 8);
 303                         }
 304                         return visitor.visitLookupSwitch(
 305                                 this, default_, npairs, matches, offsets, p);
 306                     }
 307                     default:
 308                         throw new IllegalStateException();
 309                 }
 310             }
 311 
 312             case LOCAL:
 313                 return visitor.visitLocal(this, getUnsignedByte(1), p);
 314 
 315             case LOCAL_BYTE:
 316                 return visitor.visitLocalAndValue(
 317                         this, getUnsignedByte(1), getByte(2), p);
 318 
 319             case SHORT:
 320                 return visitor.visitValue(this, getShort(1), p);
 321 
 322             case WIDE_NO_OPERANDS:
 323                 return visitor.visitNoOperands(this, p);
 324 
 325             case WIDE_LOCAL:
 326                 return visitor.visitLocal(this, getUnsignedShort(2), p);
 327 
 328             case WIDE_CPREF_W:
 329                 return visitor.visitConstantPoolRef(this, getUnsignedShort(2), p);
 330 
 331             case WIDE_CPREF_W_SHORT:
 332                 return visitor.visitConstantPoolRefAndValue(
 333                         this, getUnsignedShort(2), getUnsignedByte(4), p);
 334 
 335             case WIDE_LOCAL_SHORT:
 336                 return visitor.visitLocalAndValue(
 337                         this, getUnsignedShort(2), getShort(4), p);
 338 
 339             case UNKNOWN:
 340                 return visitor.visitUnknown(this, p);
 341 
 342             default:
 343                 throw new IllegalStateException();
 344         }
 345     }
 346 
 347     private static int align(int n) {
 348         return (n + 3) & ~3;
 349     }
 350 
 351     private byte[] bytes;
 352     private int pc;
 353 }