|
1 // |
|
2 // Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved. |
|
3 // Copyright (c) 2015, Red Hat Inc. All rights reserved. |
|
4 // DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
5 // |
|
6 // This code is free software; you can redistribute it and/or modify it |
|
7 // under the terms of the GNU General Public License version 2 only, as |
|
8 // published by the Free Software Foundation. |
|
9 // |
|
10 // This code is distributed in the hope that it will be useful, but WITHOUT |
|
11 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
12 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
13 // version 2 for more details (a copy is included in the LICENSE file that |
|
14 // accompanied this code). |
|
15 // |
|
16 // You should have received a copy of the GNU General Public License version |
|
17 // 2 along with this work; if not, write to the Free Software Foundation, |
|
18 // Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
19 // |
|
20 // Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
21 // or visit www.oracle.com if you need additional information or have any |
|
22 // questions. |
|
23 // |
|
24 // |
|
25 |
|
26 |
|
27 import static java.lang.Math.abs; |
|
28 import java.nio.ByteBuffer; |
|
29 import java.nio.ByteOrder; |
|
30 import static java.nio.ByteOrder.BIG_ENDIAN; |
|
31 import static java.nio.ByteOrder.LITTLE_ENDIAN; |
|
32 import java.util.SplittableRandom; |
|
33 import java.util.Arrays; |
|
34 |
|
35 /** |
|
36 * @test |
|
37 * @bug 8026049 |
|
38 * @run main/othervm -XX:+UnlockDiagnosticVMOptions -XX:-UseUnalignedAccesses HeapByteBufferTest |
|
39 * @run main/othervm HeapByteBufferTest |
|
40 * @summary Verify that byte buffers are correctly accessed. |
|
41 */ |
|
42 |
|
43 // A wrapper for a ByteBuffer which maintains a backing array and a |
|
44 // position. Whenever this wrapper is written the backing array and |
|
45 // the wrapped byte buffer are updated together, and whenever it is |
|
46 // read we check that the ByteBuffer and the backing array are identical. |
|
47 |
|
48 class MyByteBuffer { |
|
49 final ByteBuffer buf; |
|
50 final byte[] bytes; |
|
51 int pos; |
|
52 ByteOrder byteOrder = BIG_ENDIAN; |
|
53 |
|
54 MyByteBuffer(ByteBuffer buf, byte[] bytes) { |
|
55 this.buf = buf; |
|
56 this.bytes = Arrays.copyOf(bytes, bytes.length); |
|
57 pos = 0; |
|
58 } |
|
59 |
|
60 public final MyByteBuffer order(ByteOrder bo) { |
|
61 byteOrder = bo; |
|
62 buf.order(bo); |
|
63 return this; |
|
64 } |
|
65 |
|
66 static MyByteBuffer wrap(byte[] bytes) { |
|
67 return new MyByteBuffer(ByteBuffer.wrap(bytes), bytes); |
|
68 } |
|
69 |
|
70 int capacity() { return bytes.length; } |
|
71 int position() { |
|
72 if (buf.position() != pos) |
|
73 throw new RuntimeException(); |
|
74 return buf.position(); |
|
75 } |
|
76 |
|
77 byte[] array() { return buf.array(); } |
|
78 byte[] backingArray() { return bytes; } |
|
79 |
|
80 private static byte long7(long x) { return (byte)(x >> 56); } |
|
81 private static byte long6(long x) { return (byte)(x >> 48); } |
|
82 private static byte long5(long x) { return (byte)(x >> 40); } |
|
83 private static byte long4(long x) { return (byte)(x >> 32); } |
|
84 private static byte long3(long x) { return (byte)(x >> 24); } |
|
85 private static byte long2(long x) { return (byte)(x >> 16); } |
|
86 private static byte long1(long x) { return (byte)(x >> 8); } |
|
87 private static byte long0(long x) { return (byte)(x ); } |
|
88 |
|
89 private static byte int3(int x) { return (byte)(x >> 24); } |
|
90 private static byte int2(int x) { return (byte)(x >> 16); } |
|
91 private static byte int1(int x) { return (byte)(x >> 8); } |
|
92 private static byte int0(int x) { return (byte)(x ); } |
|
93 |
|
94 private static byte short1(short x) { return (byte)(x >> 8); } |
|
95 private static byte short0(short x) { return (byte)(x ); } |
|
96 |
|
97 byte _get(long i) { return bytes[(int)i]; } |
|
98 void _put(long i, byte x) { bytes[(int)i] = x; } |
|
99 |
|
100 private void putLongX(long a, long x) { |
|
101 if (byteOrder == BIG_ENDIAN) { |
|
102 x = Long.reverseBytes(x); |
|
103 } |
|
104 _put(a + 7, long7(x)); |
|
105 _put(a + 6, long6(x)); |
|
106 _put(a + 5, long5(x)); |
|
107 _put(a + 4, long4(x)); |
|
108 _put(a + 3, long3(x)); |
|
109 _put(a + 2, long2(x)); |
|
110 _put(a + 1, long1(x)); |
|
111 _put(a , long0(x)); |
|
112 } |
|
113 |
|
114 private void putIntX(long a, int x) { |
|
115 if (byteOrder == BIG_ENDIAN) { |
|
116 x = Integer.reverseBytes(x); |
|
117 } |
|
118 _put(a + 3, int3(x)); |
|
119 _put(a + 2, int2(x)); |
|
120 _put(a + 1, int1(x)); |
|
121 _put(a , int0(x)); |
|
122 } |
|
123 |
|
124 private void putShortX(int bi, short x) { |
|
125 if (byteOrder == BIG_ENDIAN) { |
|
126 x = Short.reverseBytes(x); |
|
127 } |
|
128 _put(bi , short0(x)); |
|
129 _put(bi + 1, short1(x)); |
|
130 } |
|
131 |
|
132 static private int makeInt(byte b3, byte b2, byte b1, byte b0) { |
|
133 return (((b3 ) << 24) | |
|
134 ((b2 & 0xff) << 16) | |
|
135 ((b1 & 0xff) << 8) | |
|
136 ((b0 & 0xff) )); |
|
137 } |
|
138 int getIntX(long a) { |
|
139 int x = makeInt(_get(a + 3), |
|
140 _get(a + 2), |
|
141 _get(a + 1), |
|
142 _get(a)); |
|
143 if (byteOrder == BIG_ENDIAN) { |
|
144 x = Integer.reverseBytes(x); |
|
145 } |
|
146 return x; |
|
147 } |
|
148 |
|
149 static private long makeLong(byte b7, byte b6, byte b5, byte b4, |
|
150 byte b3, byte b2, byte b1, byte b0) |
|
151 { |
|
152 return ((((long)b7 ) << 56) | |
|
153 (((long)b6 & 0xff) << 48) | |
|
154 (((long)b5 & 0xff) << 40) | |
|
155 (((long)b4 & 0xff) << 32) | |
|
156 (((long)b3 & 0xff) << 24) | |
|
157 (((long)b2 & 0xff) << 16) | |
|
158 (((long)b1 & 0xff) << 8) | |
|
159 (((long)b0 & 0xff) )); |
|
160 } |
|
161 |
|
162 long getLongX(long a) { |
|
163 long x = makeLong(_get(a + 7), |
|
164 _get(a + 6), |
|
165 _get(a + 5), |
|
166 _get(a + 4), |
|
167 _get(a + 3), |
|
168 _get(a + 2), |
|
169 _get(a + 1), |
|
170 _get(a)); |
|
171 if (byteOrder == BIG_ENDIAN) { |
|
172 x = Long.reverseBytes(x); |
|
173 } |
|
174 return x; |
|
175 } |
|
176 |
|
177 static private short makeShort(byte b1, byte b0) { |
|
178 return (short)((b1 << 8) | (b0 & 0xff)); |
|
179 } |
|
180 |
|
181 short getShortX(long a) { |
|
182 short x = makeShort(_get(a + 1), |
|
183 _get(a )); |
|
184 if (byteOrder == BIG_ENDIAN) { |
|
185 x = Short.reverseBytes(x); |
|
186 } |
|
187 return x; |
|
188 } |
|
189 |
|
190 double getDoubleX(long a) { |
|
191 long x = getLongX(a); |
|
192 return Double.longBitsToDouble(x); |
|
193 } |
|
194 |
|
195 double getFloatX(long a) { |
|
196 int x = getIntX(a); |
|
197 return Float.intBitsToFloat(x); |
|
198 } |
|
199 |
|
200 void ck(long x, long y) { |
|
201 if (x != y) { |
|
202 throw new RuntimeException(" x = " + Long.toHexString(x) + ", y = " + Long.toHexString(y)); |
|
203 } |
|
204 } |
|
205 |
|
206 void ck(double x, double y) { |
|
207 if (x == x && y == y && x != y) { |
|
208 ck(x, y); |
|
209 } |
|
210 } |
|
211 |
|
212 long getLong(int i) { ck(buf.getLong(i), getLongX(i)); return buf.getLong(i); } |
|
213 int getInt(int i) { ck(buf.getInt(i), getIntX(i)); return buf.getInt(i); } |
|
214 short getShort(int i) { ck(buf.getShort(i), getShortX(i)); return buf.getShort(i); } |
|
215 char getChar(int i) { ck(buf.getChar(i), (char)getShortX(i)); return buf.getChar(i); } |
|
216 double getDouble(int i) { ck(buf.getDouble(i), getDoubleX(i)); return buf.getDouble(i); } |
|
217 float getFloat(int i) { ck(buf.getFloat(i), getFloatX(i)); return buf.getFloat(i); } |
|
218 |
|
219 void putLong(int i, long x) { buf.putLong(i, x); putLongX(i, x); } |
|
220 void putInt(int i, int x) { buf.putInt(i, x); putIntX(i, x); } |
|
221 void putShort(int i, short x) { buf.putShort(i, x); putShortX(i, x); } |
|
222 void putChar(int i, char x) { buf.putChar(i, x); putShortX(i, (short)x); } |
|
223 void putDouble(int i, double x) { buf.putDouble(i, x); putLongX(i, Double.doubleToRawLongBits(x)); } |
|
224 void putFloat(int i, float x) { buf.putFloat(i, x); putIntX(i, Float.floatToRawIntBits(x)); } |
|
225 |
|
226 long getLong() { ck(buf.getLong(buf.position()), getLongX(pos)); long x = buf.getLong(); pos += 8; return x; } |
|
227 int getInt() { ck(buf.getInt(buf.position()), getIntX(pos)); int x = buf.getInt(); pos += 4; return x; } |
|
228 short getShort() { ck(buf.getShort(buf.position()), getShortX(pos)); short x = buf.getShort(); pos += 2; return x; } |
|
229 char getChar() { ck(buf.getChar(buf.position()), (char)getShortX(pos)); char x = buf.getChar(); pos += 2; return x; } |
|
230 double getDouble() { ck(buf.getDouble(buf.position()), getDoubleX(pos)); double x = buf.getDouble(); pos += 8; return x; } |
|
231 float getFloat() { ck(buf.getFloat(buf.position()), getFloatX(pos)); float x = buf.getFloat(); pos += 4; return x; } |
|
232 |
|
233 void putLong(long x) { putLongX(pos, x); pos += 8; buf.putLong(x); } |
|
234 void putInt(int x) { putIntX(pos, x); pos += 4; buf.putInt(x); } |
|
235 void putShort(short x) { putShortX(pos, x); pos += 2; buf.putShort(x); } |
|
236 void putChar(char x) { putShortX(pos, (short)x); pos += 2; buf.putChar(x); } |
|
237 void putDouble(double x) { putLongX(pos, Double.doubleToRawLongBits(x)); pos += 8; buf.putDouble(x); } |
|
238 void putFloat(float x) { putIntX(pos, Float.floatToRawIntBits(x)); pos += 4; buf.putFloat(x); } |
|
239 |
|
240 void rewind() { pos = 0; buf.rewind(); } |
|
241 } |
|
242 |
|
243 public class HeapByteBufferTest implements Runnable { |
|
244 |
|
245 SplittableRandom random = new SplittableRandom(); |
|
246 MyByteBuffer data = MyByteBuffer.wrap(new byte[1024]); |
|
247 |
|
248 int randomOffset(SplittableRandom r, MyByteBuffer buf, int size) { |
|
249 return abs(r.nextInt()) % (buf.capacity() - size); |
|
250 } |
|
251 |
|
252 long iterations; |
|
253 |
|
254 HeapByteBufferTest(long iterations) { |
|
255 this.iterations = iterations; |
|
256 } |
|
257 |
|
258 // The core of the test. Walk over the buffer reading and writing |
|
259 // random data, XORing it as we go. We can detect writes in the |
|
260 // wrong place, writes which are too long or too short, and reads |
|
261 // or writes of the wrong data, |
|
262 void step(SplittableRandom r) { |
|
263 data.order((r.nextInt() & 1) != 0 ? BIG_ENDIAN : LITTLE_ENDIAN); |
|
264 |
|
265 data.rewind(); |
|
266 while (data.position() < data.capacity()) |
|
267 data.putLong(data.getLong() ^ random.nextLong()); |
|
268 |
|
269 data.rewind(); |
|
270 while (data.position() < data.capacity()) |
|
271 data.putInt(data.getInt() ^ random.nextInt()); |
|
272 |
|
273 data.rewind(); |
|
274 while (data.position() < data.capacity()) |
|
275 data.putShort((short)(data.getShort() ^ random.nextInt())); |
|
276 |
|
277 data.rewind(); |
|
278 while (data.position() < data.capacity()) |
|
279 data.putChar((char)(data.getChar() ^ random.nextInt())); |
|
280 |
|
281 data.rewind(); |
|
282 while (data.position() < data.capacity()) { |
|
283 data.putDouble(combine(data.getDouble(), random.nextLong())); |
|
284 } |
|
285 |
|
286 data.rewind(); |
|
287 while (data.position() < data.capacity()) |
|
288 data.putFloat(combine(data.getFloat(), random.nextInt())); |
|
289 |
|
290 for (int i = 0; i < 100; i++) { |
|
291 int offset = randomOffset(r, data, 8); |
|
292 data.putLong(offset, data.getLong(offset) ^ random.nextLong()); |
|
293 } |
|
294 for (int i = 0; i < 100; i++) { |
|
295 int offset = randomOffset(r, data, 4); |
|
296 data.putInt(offset, data.getInt(offset) ^ random.nextInt()); |
|
297 } |
|
298 for (int i = 0; i < 100; i++) { |
|
299 int offset = randomOffset(r, data, 4); |
|
300 data.putShort(offset, (short)(data.getShort(offset) ^ random.nextInt())); |
|
301 } |
|
302 for (int i = 0; i < 100; i++) { |
|
303 int offset = randomOffset(r, data, 4); |
|
304 data.putChar(offset, (char)(data.getChar(offset) ^ random.nextInt())); |
|
305 } |
|
306 for (int i = 0; i < 100; i++) { |
|
307 int offset = randomOffset(r, data, 8); |
|
308 data.putDouble(offset, combine(data.getDouble(offset), random.nextLong())); |
|
309 } |
|
310 for (int i = 0; i < 100; i++) { |
|
311 int offset = randomOffset(r, data, 4); |
|
312 data.putFloat(offset, combine(data.getFloat(offset), random.nextInt())); |
|
313 } |
|
314 } |
|
315 |
|
316 // XOR the bit pattern of a double and a long, returning the |
|
317 // result as a double. |
|
318 // |
|
319 // We convert signalling NaNs to quiet NaNs. We need to do this |
|
320 // because some platforms (in particular legacy 80x87) do not |
|
321 // provide transparent conversions between integer and |
|
322 // floating-point types even when using raw conversions but |
|
323 // quietly convert sNaN to qNaN. This causes spurious test |
|
324 // failures when the template interpreter uses 80x87 and the JITs |
|
325 // use XMM registers. |
|
326 // |
|
327 public double combine(double prev, long bits) { |
|
328 bits ^= Double.doubleToRawLongBits(prev); |
|
329 double result = Double.longBitsToDouble(bits); |
|
330 if (Double.isNaN(result)) { |
|
331 result = Double.longBitsToDouble(bits | 0x8000000000000l); |
|
332 } |
|
333 return result; |
|
334 } |
|
335 |
|
336 // XOR the bit pattern of a float and an int, returning the result |
|
337 // as a float. Convert sNaNs to qNaNs. |
|
338 public Float combine(float prev, int bits) { |
|
339 bits ^= Float.floatToRawIntBits(prev); |
|
340 Float result = Float.intBitsToFloat(bits); |
|
341 if (Float.isNaN(result)) { |
|
342 result = Float.intBitsToFloat(bits | 0x400000); |
|
343 } |
|
344 return result; |
|
345 } |
|
346 |
|
347 public void run() { |
|
348 SplittableRandom r = new SplittableRandom(); |
|
349 |
|
350 for (int i = 0; i < data.capacity(); i += 8) { |
|
351 data.putLong(i, random.nextLong()); |
|
352 } |
|
353 |
|
354 for (int i = 0; i < iterations; i++) { |
|
355 step(r); |
|
356 } |
|
357 |
|
358 if (!Arrays.equals(data.array(), data.backingArray())) { |
|
359 throw new RuntimeException(); |
|
360 } |
|
361 } |
|
362 |
|
363 public static void main(String[] args) { |
|
364 // The number of iterations is high to ensure that tiered |
|
365 // compilation kicks in all the way up to C2. |
|
366 long iterations = 100000; |
|
367 if (args.length > 0) |
|
368 iterations = Long.parseLong(args[0]); |
|
369 |
|
370 new HeapByteBufferTest(iterations).run(); |
|
371 } |
|
372 } |