1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/share/classes/com/sun/tools/classfile/Instruction.java Mon Mar 30 15:08:09 2009 -0700 1.3 @@ -0,0 +1,339 @@ 1.4 +/* 1.5 + * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. 1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.7 + * 1.8 + * This code is free software; you can redistribute it and/or modify it 1.9 + * under the terms of the GNU General Public License version 2 only, as 1.10 + * published by the Free Software Foundation. Sun designates this 1.11 + * particular file as subject to the "Classpath" exception as provided 1.12 + * by Sun in the LICENSE file that accompanied this code. 1.13 + * 1.14 + * This code is distributed in the hope that it will be useful, but WITHOUT 1.15 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1.16 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1.17 + * version 2 for more details (a copy is included in the LICENSE file that 1.18 + * accompanied this code). 1.19 + * 1.20 + * You should have received a copy of the GNU General Public License version 1.21 + * 2 along with this work; if not, write to the Free Software Foundation, 1.22 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 1.23 + * 1.24 + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, 1.25 + * CA 95054 USA or visit www.sun.com if you need additional information or 1.26 + * have any questions. 1.27 + */ 1.28 + 1.29 +package com.sun.tools.classfile; 1.30 + 1.31 +/** 1.32 + * See JVMS3, chapter 6. 1.33 + * 1.34 + * <p><b>This is NOT part of any API supported by Sun Microsystems. If 1.35 + * you write code that depends on this, you do so at your own risk. 1.36 + * This code and its internal interfaces are subject to change or 1.37 + * deletion without notice.</b> 1.38 + * 1.39 + * @see Code_attribute#getInstructions 1.40 + */ 1.41 +public class Instruction { 1.42 + /** The kind of an instruction, as determined by the position, size and 1.43 + * types of its operands. */ 1.44 + public static enum Kind { 1.45 + /** Opcode is not followed by any operands. */ 1.46 + NO_OPERANDS(1), 1.47 + /** Opcode is followed by a byte indicating a type. */ 1.48 + ATYPE(2), 1.49 + /** Opcode is followed by a 2-byte branch offset. */ 1.50 + BRANCH(3), 1.51 + /** Opcode is followed by a 4-byte branch offset. */ 1.52 + BRANCH_W(5), 1.53 + /** Opcode is followed by a signed byte value. */ 1.54 + BYTE(2), 1.55 + /** Opcode is followed by a 1-byte index into the constant pool. */ 1.56 + CPREF(2), 1.57 + /** Opcode is followed by a 2-byte index into the constant pool. */ 1.58 + CPREF_W(3), 1.59 + /** Opcode is followed by a 2-byte index into the constant pool, 1.60 + * an unsigned byte value. */ 1.61 + CPREF_W_UBYTE(4), 1.62 + /** Opcode is followed by a 2-byte index into the constant pool., 1.63 + * an unsigned byte value, and a zero byte. */ 1.64 + CPREF_W_UBYTE_ZERO(5), 1.65 + /** Opcode is followed by variable number of operands, depending 1.66 + * on the instruction.*/ 1.67 + DYNAMIC(-1), 1.68 + /** Opcode is followed by a 1-byte reference to a local variable. */ 1.69 + LOCAL(2), 1.70 + /** Opcode is followed by a 1-byte reference to a local variable, 1.71 + * and a signed byte value. */ 1.72 + LOCAL_BYTE(3), 1.73 + /** Opcode is followed by a signed short value. */ 1.74 + SHORT(3), 1.75 + /** Wide opcode is not followed by any operands. */ 1.76 + WIDE_NO_OPERANDS(2), 1.77 + /** Wide opcode is followed by a 2-byte index into the constant pool. */ 1.78 + WIDE_CPREF_W(4), 1.79 + /** Wide opcode is followed by a 2-byte index into the constant pool, 1.80 + * and a signed short value. */ 1.81 + WIDE_CPREF_W_SHORT(6), 1.82 + /** Opcode was not recognized. */ 1.83 + UNKNOWN(1); 1.84 + 1.85 + Kind(int length) { 1.86 + this.length = length; 1.87 + } 1.88 + 1.89 + /** The length, in bytes, of this kind of instruction, or -1 is the 1.90 + * length depends on the specific instruction. */ 1.91 + public final int length; 1.92 + }; 1.93 + 1.94 + /** A utility visitor to help decode the operands of an instruction. 1.95 + * @see Instruction#accept */ 1.96 + public interface KindVisitor<R,P> { 1.97 + /** See {@link Kind#NO_OPERANDS}, {@link Kind#WIDE_NO_OPERANDS}. */ 1.98 + R visitNoOperands(Instruction instr, P p); 1.99 + /** See {@link Kind#ATYPE}. */ 1.100 + R visitArrayType(Instruction instr, TypeKind kind, P p); 1.101 + /** See {@link Kind#BRANCH}, {@link Kind#BRANCH_W}. */ 1.102 + R visitBranch(Instruction instr, int offset, P p); 1.103 + /** See {@link Kind#CPREF}, {@link Kind#CPREF_W}, {@link Kind#WIDE_CPREF_W}. */ 1.104 + R visitConstantPoolRef(Instruction instr, int index, P p); 1.105 + /** See {@link Kind#CPREF_W_UBYTE}, {@link Kind#CPREF_W_UBYTE_ZERO}, {@link Kind#WIDE_CPREF_W_SHORT}. */ 1.106 + R visitConstantPoolRefAndValue(Instruction instr, int index, int value, P p); 1.107 + /** See {@link Kind#LOCAL}. */ 1.108 + R visitLocal(Instruction instr, int index, P p); 1.109 + /** See {@link Kind#LOCAL_UBYTE}. */ 1.110 + R visitLocalAndValue(Instruction instr, int index, int value, P p); 1.111 + /** See {@link Kind#DYNAMIC}. */ 1.112 + R visitLookupSwitch(Instruction instr, int default_, int npairs, int[] matches, int[] offsets); 1.113 + /** See {@link Kind#DYNAMIC}. */ 1.114 + R visitTableSwitch(Instruction instr, int default_, int low, int high, int[] offsets); 1.115 + /** See {@link Kind#BYTE}, {@link Kind#SHORT}. */ 1.116 + R visitValue(Instruction instr, int value, P p); 1.117 + /** Instruction is unrecognized. */ 1.118 + R visitUnknown(Instruction instr, P p); 1.119 + 1.120 + } 1.121 + 1.122 + /** The kind of primitive array type to create. 1.123 + * See JVMS chapter 6, newarray. */ 1.124 + public static enum TypeKind { 1.125 + T_BOOLEAN(4, "boolean"), 1.126 + T_CHAR(5, "char"), 1.127 + T_FLOAT(6, "float"), 1.128 + T_DOUBLE(7, "double"), 1.129 + T_BYTE(8, "byte"), 1.130 + T_SHORT(9, "short"), 1.131 + T_INT (10, "int"), 1.132 + T_LONG (11, "long"); 1.133 + TypeKind(int value, String name) { 1.134 + this.value = value; 1.135 + this.name = name; 1.136 + } 1.137 + 1.138 + public static TypeKind get(int value) { 1.139 + switch (value) { 1.140 + case 4: return T_BOOLEAN; 1.141 + case 5: return T_CHAR; 1.142 + case 6: return T_FLOAT; 1.143 + case 7: return T_DOUBLE; 1.144 + case 8: return T_BYTE; 1.145 + case 9: return T_SHORT; 1.146 + case 10: return T_INT; 1.147 + case 11: return T_LONG; 1.148 + default: return null; 1.149 + } 1.150 + } 1.151 + 1.152 + public final int value; 1.153 + public final String name; 1.154 + } 1.155 + 1.156 + /** An instruction is defined by its position in a bytecode array. */ 1.157 + public Instruction(byte[] bytes, int pc) { 1.158 + this.bytes = bytes; 1.159 + this.pc = pc; 1.160 + } 1.161 + 1.162 + /** Get the position of the instruction within the bytecode array. */ 1.163 + public int getPC() { 1.164 + return pc; 1.165 + } 1.166 + 1.167 + /** Get a byte value, relative to the start of this instruction. */ 1.168 + public int getByte(int offset) { 1.169 + return bytes[pc + offset]; 1.170 + } 1.171 + 1.172 + /** Get an unsigned byte value, relative to the start of this instruction. */ 1.173 + public int getUnsignedByte(int offset) { 1.174 + return getByte(offset) & 0xff; 1.175 + } 1.176 + 1.177 + /** Get a 2-byte value, relative to the start of this instruction. */ 1.178 + public int getShort(int offset) { 1.179 + return (getByte(offset) << 8) | getUnsignedByte(offset + 1); 1.180 + } 1.181 + 1.182 + /** Get a unsigned 2-byte value, relative to the start of this instruction. */ 1.183 + public int getUnsignedShort(int offset) { 1.184 + return getShort(offset) & 0xFFFF; 1.185 + } 1.186 + 1.187 + /** Get a 4-byte value, relative to the start of this instruction. */ 1.188 + public int getInt(int offset) { 1.189 + return (getShort(offset) << 16) | (getUnsignedShort(offset + 2)); 1.190 + } 1.191 + 1.192 + /** Get the Opcode for this instruction, or null if the instruction is 1.193 + * unrecognized. */ 1.194 + public Opcode getOpcode() { 1.195 + int b = getUnsignedByte(0); 1.196 + switch (b) { 1.197 + case Opcode.NONPRIV: 1.198 + case Opcode.PRIV: 1.199 + case Opcode.WIDE: 1.200 + return Opcode.get(b, getUnsignedByte(1)); 1.201 + } 1.202 + return Opcode.get(b); 1.203 + } 1.204 + 1.205 + /** Get the mnemonic for this instruction, or a default string if the 1.206 + * instruction is unrecognized. */ 1.207 + public String getMnemonic() { 1.208 + Opcode opcode = getOpcode(); 1.209 + if (opcode == null) 1.210 + return "bytecode " + getUnsignedByte(0); 1.211 + else 1.212 + return opcode.toString().toLowerCase(); 1.213 + } 1.214 + 1.215 + /** Get the length, in bytes, of this instruction, including the opcode 1.216 + * and all its operands. */ 1.217 + public int length() { 1.218 + Opcode opcode = getOpcode(); 1.219 + if (opcode == null) 1.220 + return 1; 1.221 + 1.222 + switch (opcode) { 1.223 + case TABLESWITCH: { 1.224 + int pad = align(pc + 1) - pc; 1.225 + int low = getInt(pad + 4); 1.226 + int high = getInt(pad + 8); 1.227 + return pad + 12 + 4 * (high - low + 1); 1.228 + } 1.229 + case LOOKUPSWITCH: { 1.230 + int pad = align(pc + 1) - pc; 1.231 + int npairs = getInt(pad + 4); 1.232 + return pad + 8 + 8 * npairs; 1.233 + 1.234 + } 1.235 + default: 1.236 + return opcode.kind.length; 1.237 + } 1.238 + } 1.239 + 1.240 + /** Get the {@link Kind} of this instruction. */ 1.241 + public Kind getKind() { 1.242 + Opcode opcode = getOpcode(); 1.243 + return (opcode != null ? opcode.kind : Kind.UNKNOWN); 1.244 + } 1.245 + 1.246 + /** Invoke a method on the visitor according to the kind of this 1.247 + * instruction, passing in the decoded operands for the instruction. */ 1.248 + public <R,P> R accept(KindVisitor<R,P> visitor, P p) { 1.249 + switch (getKind()) { 1.250 + case NO_OPERANDS: 1.251 + return visitor.visitNoOperands(this, p); 1.252 + 1.253 + case ATYPE: 1.254 + return visitor.visitArrayType( 1.255 + this, TypeKind.get(getUnsignedByte(1)), p); 1.256 + 1.257 + case BRANCH: 1.258 + return visitor.visitBranch(this, getShort(1), p); 1.259 + 1.260 + case BRANCH_W: 1.261 + return visitor.visitBranch(this, getInt(1), p); 1.262 + 1.263 + case BYTE: 1.264 + return visitor.visitValue(this, getByte(1), p); 1.265 + 1.266 + case CPREF: 1.267 + return visitor.visitConstantPoolRef(this, getUnsignedByte(1), p); 1.268 + 1.269 + case CPREF_W: 1.270 + return visitor.visitConstantPoolRef(this, getUnsignedShort(1), p); 1.271 + 1.272 + case CPREF_W_UBYTE: 1.273 + case CPREF_W_UBYTE_ZERO: 1.274 + return visitor.visitConstantPoolRefAndValue( 1.275 + this, getUnsignedShort(1), getUnsignedByte(3), p); 1.276 + 1.277 + case DYNAMIC: { 1.278 + switch (getOpcode()) { 1.279 + case TABLESWITCH: { 1.280 + int pad = align(pc + 1) - pc; 1.281 + int default_ = getInt(pad); 1.282 + int low = getInt(pad + 4); 1.283 + int high = getInt(pad + 8); 1.284 + int[] values = new int[high - low + 1]; 1.285 + for (int i = 0; i < values.length; i++) 1.286 + values[i] = getInt(pad + 12 + 4 * i); 1.287 + return visitor.visitTableSwitch( 1.288 + this, default_, low, high, values); 1.289 + } 1.290 + case LOOKUPSWITCH: { 1.291 + int pad = align(pc + 1) - pc; 1.292 + int default_ = getInt(pad); 1.293 + int npairs = getInt(pad + 4); 1.294 + int[] matches = new int[npairs]; 1.295 + int[] offsets = new int[npairs]; 1.296 + for (int i = 0; i < npairs; i++) { 1.297 + matches[i] = getInt(pad + 8 + i * 8); 1.298 + offsets[i] = getInt(pad + 12 + i * 8); 1.299 + } 1.300 + return visitor.visitLookupSwitch( 1.301 + this, default_, npairs, matches, offsets); 1.302 + } 1.303 + default: 1.304 + throw new IllegalStateException(); 1.305 + } 1.306 + } 1.307 + 1.308 + case LOCAL: 1.309 + return visitor.visitLocal(this, getUnsignedByte(1), p); 1.310 + 1.311 + case LOCAL_BYTE: 1.312 + return visitor.visitLocalAndValue( 1.313 + this, getUnsignedByte(1), getByte(2), p); 1.314 + 1.315 + case SHORT: 1.316 + return visitor.visitValue(this, getShort(1), p); 1.317 + 1.318 + case WIDE_NO_OPERANDS: 1.319 + return visitor.visitNoOperands(this, p); 1.320 + 1.321 + case WIDE_CPREF_W: 1.322 + return visitor.visitConstantPoolRef(this, getUnsignedShort(2), p); 1.323 + 1.324 + case WIDE_CPREF_W_SHORT: 1.325 + return visitor.visitConstantPoolRefAndValue( 1.326 + this, getUnsignedShort(2), getUnsignedByte(4), p); 1.327 + 1.328 + case UNKNOWN: 1.329 + return visitor.visitUnknown(this, p); 1.330 + 1.331 + default: 1.332 + throw new IllegalStateException(); 1.333 + } 1.334 + } 1.335 + 1.336 + private static int align(int n) { 1.337 + return (n + 3) & ~3; 1.338 + } 1.339 + 1.340 + private byte[] bytes; 1.341 + private int pc; 1.342 +}