Tue, 17 Dec 2013 10:55:59 +0100
8029800: Flags.java uses String.toLowerCase without specifying Locale
Summary: Introducing StringUtils.toLowerCase/toUpperCase independent on the default locale, converting almost all usages of String.toLowerCase/toUpperCase to use the new methods.
Reviewed-by: jjg, bpatel
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 */
26 package com.sun.tools.classfile;
28 import java.util.Locale;
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);
89 Kind(int length) {
90 this.length = length;
91 }
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 };
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);
124 }
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 }
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 }
156 public final int value;
157 public final String name;
158 }
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 }
166 /** Get the position of the instruction within the bytecode array. */
167 public int getPC() {
168 return pc;
169 }
171 /** Get a byte value, relative to the start of this instruction. */
172 public int getByte(int offset) {
173 return bytes[pc + offset];
174 }
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 }
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 }
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 }
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 }
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 }
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 }
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;
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;
238 }
239 default:
240 return opcode.kind.length;
241 }
242 }
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 }
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);
257 case ATYPE:
258 return visitor.visitArrayType(
259 this, TypeKind.get(getUnsignedByte(1)), p);
261 case BRANCH:
262 return visitor.visitBranch(this, getShort(1), p);
264 case BRANCH_W:
265 return visitor.visitBranch(this, getInt(1), p);
267 case BYTE:
268 return visitor.visitValue(this, getByte(1), p);
270 case CPREF:
271 return visitor.visitConstantPoolRef(this, getUnsignedByte(1), p);
273 case CPREF_W:
274 return visitor.visitConstantPoolRef(this, getUnsignedShort(1), p);
276 case CPREF_W_UBYTE:
277 case CPREF_W_UBYTE_ZERO:
278 return visitor.visitConstantPoolRefAndValue(
279 this, getUnsignedShort(1), getUnsignedByte(3), p);
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 }
312 case LOCAL:
313 return visitor.visitLocal(this, getUnsignedByte(1), p);
315 case LOCAL_BYTE:
316 return visitor.visitLocalAndValue(
317 this, getUnsignedByte(1), getByte(2), p);
319 case SHORT:
320 return visitor.visitValue(this, getShort(1), p);
322 case WIDE_NO_OPERANDS:
323 return visitor.visitNoOperands(this, p);
325 case WIDE_LOCAL:
326 return visitor.visitLocal(this, getUnsignedShort(2), p);
328 case WIDE_CPREF_W:
329 return visitor.visitConstantPoolRef(this, getUnsignedShort(2), p);
331 case WIDE_CPREF_W_SHORT:
332 return visitor.visitConstantPoolRefAndValue(
333 this, getUnsignedShort(2), getUnsignedByte(4), p);
335 case WIDE_LOCAL_SHORT:
336 return visitor.visitLocalAndValue(
337 this, getUnsignedShort(2), getShort(4), p);
339 case UNKNOWN:
340 return visitor.visitUnknown(this, p);
342 default:
343 throw new IllegalStateException();
344 }
345 }
347 private static int align(int n) {
348 return (n + 3) & ~3;
349 }
351 private byte[] bytes;
352 private int pc;
353 }