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