1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 import java.lang.invoke.MethodHandles; 18 import java.lang.invoke.VarHandle; 19 import java.nio.ByteBuffer; 20 import java.nio.ByteOrder; 21 22 // These tests cover DoVarHandleInvokeCommon in interpreter_common.cc. 23 24 public class VarHandleArrayTests { 25 public static class ArrayStoreTest extends VarHandleUnitTest { 26 private static final Integer ZERO = Integer.valueOf(0); 27 private static final Integer ONE = Integer.valueOf(1); 28 private static final Integer TWO = Integer.valueOf(2); 29 30 private final Integer[] values = new Integer[10]; 31 testIntegerArrayVarHandle()32 private void testIntegerArrayVarHandle() { 33 final VarHandle vh = MethodHandles.arrayElementVarHandle(Integer[].class); 34 35 // AccessModeTemplate::kSet 36 vh.set(values, 0, ZERO); 37 assertEquals(0, values[0].intValue()); 38 vh.set((Object[]) values, 1, ONE); 39 assertEquals(ONE, values[1]); 40 assertThrowsAIOBE(() -> vh.set(values, values.length, null)); 41 assertThrowsCCE(() -> vh.set(values, 6, new Object())); 42 assertThrowsCCE(() -> vh.set((Object[]) values, 6, new Object())); 43 assertThrowsNPE(() -> vh.set((Integer[]) null, 6, ONE)); 44 assertThrowsWMTE(() -> vh.set(values, 'c')); 45 assertThrowsWMTE(() -> vh.set((Object[]) values, 5, 'c')); 46 47 // AccessModeTemplate::kGetAndUpdate 48 assertEquals(ZERO, (Integer) vh.getAndSet(values, 0, ONE)); 49 assertEquals(ONE, values[0]); 50 assertThrowsAIOBE(() -> vh.getAndSet(values, values.length, null)); 51 assertThrowsCCE(() -> vh.getAndSet(values, 6, new Object())); 52 assertThrowsCCE(() -> vh.getAndSet((Object[]) values, 6, new Object())); 53 assertThrowsNPE(() -> vh.getAndSet((Integer[]) null, 6, ONE)); 54 assertThrowsWMTE(() -> vh.getAndSet(values, 'c')); 55 assertThrowsWMTE(() -> vh.getAndSet((Object[]) values, 5, 'c')); 56 57 // AccessModeTemplate::kCompareAndExchange 58 assertEquals(ONE, (Integer) vh.compareAndExchange(values, 0, ONE, TWO)); 59 assertEquals(TWO, values[0]); 60 assertEquals(TWO, (Integer) vh.compareAndExchange(values, 0, ONE, ZERO)); 61 assertEquals(TWO, values[0]); 62 assertThrowsAIOBE(() -> vh.compareAndExchange(values, values.length, null, null)); 63 assertThrowsCCE(() -> vh.compareAndExchange(values, 6, 6, new Object())); 64 assertThrowsCCE(() -> vh.compareAndExchange((Object[]) values, 6, 6, new Object())); 65 assertThrowsNPE(() -> vh.compareAndExchange((Integer[]) null, 6, ONE, ONE)); 66 assertThrowsWMTE(() -> vh.compareAndExchange(values, null, 'c')); 67 assertThrowsWMTE(() -> vh.compareAndExchange((Object[]) values, 5, null, 'c')); 68 69 // AccessModeTemplate::kCompareAndSet 70 assertEquals(true, (boolean) vh.compareAndSet(values, 0, TWO, ONE)); 71 assertEquals(ONE, values[0]); 72 assertEquals(false, (boolean) vh.compareAndSet(values, 0, ZERO, TWO)); 73 assertEquals(ONE, values[0]); 74 assertThrowsAIOBE(() -> vh.compareAndSet(values, values.length, null, null)); 75 assertThrowsCCE(() -> vh.compareAndSet(values, 6, 6, new Object())); 76 assertThrowsCCE(() -> vh.compareAndSet((Object[]) values, 6, 6, new Object())); 77 assertThrowsNPE(() -> vh.compareAndSet((Integer[]) null, 6, ONE, ONE)); 78 assertThrowsWMTE(() -> vh.compareAndSet(values, null, 'c')); 79 assertThrowsWMTE(() -> vh.compareAndSet((Object[]) values, 5, null, 'c')); 80 } 81 testObjectArrayVarHandle()82 private void testObjectArrayVarHandle() { 83 final VarHandle vho = MethodHandles.arrayElementVarHandle(Object[].class); 84 85 // AccessModeTemplate::kSet 86 vho.set(values, 0, ONE); 87 assertEquals(ONE, values[0]); 88 assertThrowsAIOBE(() -> vho.set(values, values.length, null)); 89 assertThrowsASE(() -> vho.set(values, 0, new Object())); 90 assertThrowsASE(() -> vho.set(values, 0, "hello")); 91 assertThrowsNPE(() -> vho.set(null, 0, ZERO)); 92 assertThrowsWMTE(() -> vho.set(0, ZERO)); 93 assertThrowsWMTE(() -> vho.set(values, ZERO)); 94 95 // AccessModeTemplate::kGetAndUpdate 96 assertEquals(ONE, vho.getAndSetAcquire(values, 0, TWO)); 97 assertThrowsAIOBE(() -> vho.getAndSetRelease(values, values.length, null)); 98 assertThrowsASE(() -> vho.getAndSet(values, 0, new Object())); 99 assertThrowsASE(() -> vho.getAndSet(values, 0, "hello")); 100 assertThrowsNPE(() -> vho.getAndSet(null, 0, ZERO)); 101 assertThrowsWMTE(() -> vho.getAndSet(0, ZERO)); 102 assertThrowsWMTE(() -> vho.getAndSet(values, ZERO)); 103 104 // AccessModeTemplate::kCompareAndExchange 105 assertEquals(TWO, vho.compareAndExchange(values, 0, TWO, ZERO)); 106 assertThrowsAIOBE(() -> vho.compareAndExchange(values, values.length, ONE, TWO)); 107 assertThrowsASE(() -> vho.compareAndExchange(values, 0, ONE, new Object())); 108 assertThrowsASE(() -> vho.compareAndExchange(values, 0, ONE, "hello")); 109 assertThrowsNPE(() -> vho.compareAndExchange(null, 0, ONE, ZERO)); 110 assertThrowsWMTE(() -> vho.compareAndExchange(0, ZERO, ONE)); 111 assertThrowsWMTE(() -> vho.compareAndExchange(values, ONE, ZERO)); 112 113 // AccessModeTemplate::kCompareAndSet 114 assertEquals(true, (boolean) vho.compareAndSet(values, 0, ZERO, ONE)); 115 assertThrowsAIOBE(() -> vho.compareAndSet(values, values.length, ONE, TWO)); 116 assertThrowsASE(() -> vho.compareAndSet(values, 0, ONE, new Object())); 117 assertThrowsASE(() -> vho.compareAndSet(values, 0, ONE, "hello")); 118 assertThrowsNPE(() -> vho.compareAndSet(null, 0, ONE, ZERO)); 119 assertThrowsWMTE(() -> vho.compareAndSet(0, ZERO, ONE)); 120 assertThrowsWMTE(() -> vho.compareAndSet(values, ONE, ZERO)); 121 } 122 toHost(ByteOrder order, byte b0, byte b1)123 private short toHost(ByteOrder order, byte b0, byte b1) { 124 final int u0 = Byte.toUnsignedInt(b0); 125 final int u1 = Byte.toUnsignedInt(b1); 126 if (order == ByteOrder.LITTLE_ENDIAN) { 127 return (short) (u0 + (u1 << 8)); 128 } else { 129 return (short) (u1 + (u0 << 8)); 130 } 131 } 132 toHost(ByteOrder order, byte b0, byte b1, byte b2, byte b3)133 private int toHost(ByteOrder order, byte b0, byte b1, byte b2, byte b3) { 134 final int u0 = Byte.toUnsignedInt(b0); 135 final int u1 = Byte.toUnsignedInt(b1); 136 final int u2 = Byte.toUnsignedInt(b2); 137 final int u3 = Byte.toUnsignedInt(b3); 138 if (order == ByteOrder.LITTLE_ENDIAN) { 139 return u0 + (u1 << 8) + (u2 << 16) + (u3 << 24); 140 } else { 141 return u3 + (u2 << 8) + (u1 << 16) + (u0 << 24); 142 } 143 } 144 testByteArrayViewVarHandle()145 private void testByteArrayViewVarHandle() { 146 final int BITS_PER_BYTE = 8; 147 byte[] array = new byte[32]; 148 149 final ByteOrder[] byteOrders = 150 new ByteOrder[] {ByteOrder.LITTLE_ENDIAN, ByteOrder.BIG_ENDIAN}; 151 152 for (ByteOrder order : byteOrders) { 153 { 154 final VarHandle vhShort = 155 MethodHandles.byteArrayViewVarHandle(short[].class, order); 156 assertThrowsIOOBE(() -> vhShort.get(array, -1)); 157 assertThrowsIOOBE(() -> vhShort.get(array, Integer.MIN_VALUE)); 158 assertThrowsIOOBE(() -> vhShort.get(array, array.length)); 159 assertThrowsIOOBE(() -> vhShort.get(array, array.length - 1)); 160 assertThrowsIOOBE(() -> vhShort.get(array, Integer.MAX_VALUE)); 161 162 for (int i = 0; i < array.length - 1; ++i) { 163 final boolean isAligned = (i % 2) == 0; 164 final short value = (short) ((i + 1) * 0xff); 165 vhShort.set(array, i, value); 166 assertEquals(value, (short) vhShort.get(array, i)); 167 assertEquals(value, toHost(order, array[i], array[i + 1])); 168 for (int j = 0; j < array.length; ++j) { 169 if (j < i || j > i + 1) { 170 assertEquals((byte) 0, array[j]); 171 } 172 } 173 if (isAligned) { 174 vhShort.getAcquire(array, i); 175 vhShort.setRelease(array, i, (short) 0); 176 } else { 177 final int fi = i; 178 assertThrowsISE(() -> vhShort.getAcquire(array, fi)); 179 assertThrowsISE(() -> vhShort.setRelease(array, fi, (short) 0)); 180 } 181 vhShort.set(array, i, (short) 0); 182 } 183 } 184 { 185 final VarHandle vhInt = 186 MethodHandles.byteArrayViewVarHandle(int[].class, order); 187 assertThrowsIOOBE(() -> vhInt.get(array, -1)); 188 assertThrowsIOOBE(() -> vhInt.get(array, Integer.MIN_VALUE)); 189 assertThrowsIOOBE(() -> vhInt.get(array, array.length)); 190 assertThrowsIOOBE(() -> vhInt.get(array, array.length - 1)); 191 assertThrowsIOOBE(() -> vhInt.get(array, array.length - 2)); 192 assertThrowsIOOBE(() -> vhInt.get(array, array.length - 3)); 193 assertThrowsIOOBE(() -> vhInt.get(array, Integer.MAX_VALUE)); 194 for (int i = 0; i < array.length - 3; ++i) { 195 final boolean isAligned = (i % 4) == 0; 196 final int value = (i + 1) * 0x11223344; 197 vhInt.set(array, i, value); 198 assertEquals(value, vhInt.get(array, i)); 199 assertEquals( 200 value, 201 toHost(order, array[i], array[i + 1], array[i + 2], array[i + 3])); 202 for (int j = 0; j < array.length; ++j) { 203 if (j < i || j > i + 3) { 204 assertEquals((byte) 0, array[j]); 205 } 206 } 207 if (isAligned) { 208 vhInt.getAcquire(array, i); 209 vhInt.setRelease(array, i, (int) 0); 210 } else { 211 final int fi = i; 212 assertThrowsISE(() -> vhInt.getAcquire(array, fi)); 213 assertThrowsISE(() -> vhInt.setRelease(array, fi, (int) 0)); 214 } 215 vhInt.set(array, i, 0); 216 } 217 } 218 } 219 } 220 testByteBufferVarHandle()221 private void testByteBufferVarHandle() { 222 final ByteOrder[] byteOrders = 223 new ByteOrder[] {ByteOrder.LITTLE_ENDIAN, ByteOrder.BIG_ENDIAN}; 224 225 for (final ByteOrder byteOrder : byteOrders) { 226 final ByteBuffer heapBuffer = ByteBuffer.allocate(32); 227 final ByteBuffer directBuffer = ByteBuffer.allocateDirect(32); 228 final ByteBuffer arrayBuffer = ByteBuffer.wrap(new byte[32]); 229 final ByteBuffer anotherArrayBuffer = ByteBuffer.wrap(new byte[32], 3, 23); 230 final ByteBuffer[] buffers = { 231 heapBuffer, 232 ((ByteBuffer) heapBuffer.duplicate().position(1)).slice(), 233 directBuffer, 234 ((ByteBuffer) directBuffer.duplicate().position(1)).slice(), 235 arrayBuffer, 236 ((ByteBuffer) arrayBuffer.duplicate().position(1)).slice(), 237 anotherArrayBuffer, 238 ((ByteBuffer) anotherArrayBuffer.duplicate().position(1)).slice() 239 }; 240 for (final ByteBuffer buffer : buffers) { 241 { 242 final VarHandle vhShort = 243 MethodHandles.byteBufferViewVarHandle(short[].class, byteOrder); 244 assertThrowsIOOBE(() -> vhShort.get(buffer, -1)); 245 assertThrowsIOOBE(() -> vhShort.get(buffer, Integer.MIN_VALUE)); 246 assertThrowsIOOBE(() -> vhShort.get(buffer, Integer.MAX_VALUE)); 247 assertThrowsIOOBE(() -> vhShort.get(buffer, buffer.limit())); 248 assertThrowsIOOBE(() -> vhShort.get(buffer, buffer.limit() - 1)); 249 final int zeroAlignment = buffer.alignmentOffset(0, Short.BYTES); 250 for (int i = 0; i < buffer.limit() - 1; ++i) { 251 boolean isAligned = (zeroAlignment + i) % Short.BYTES == 0; 252 final short value = (short) ((i + 1) * 0xff); 253 vhShort.set(buffer, i, value); 254 assertEquals(value, (short) vhShort.get(buffer, i)); 255 assertEquals( 256 value, toHost(byteOrder, buffer.get(i), buffer.get(i + 1))); 257 for (int j = 0; j < buffer.limit(); ++j) { 258 if (j < i || j > i + 1) { 259 assertEquals((byte) 0, buffer.get(j)); 260 } 261 } 262 if (isAligned) { 263 vhShort.getAcquire(buffer, i); 264 vhShort.setRelease(buffer, i, (short) 0); 265 } else { 266 final int fi = i; 267 assertThrowsISE(() -> vhShort.getAcquire(buffer, fi)); 268 assertThrowsISE(() -> vhShort.setRelease(buffer, fi, (short) 0)); 269 } 270 vhShort.set(buffer, i, (short) 0); 271 } 272 } 273 { 274 final VarHandle vhInt = 275 MethodHandles.byteBufferViewVarHandle(int[].class, byteOrder); 276 assertThrowsIOOBE(() -> vhInt.get(buffer, -1)); 277 assertThrowsIOOBE(() -> vhInt.get(buffer, Integer.MIN_VALUE)); 278 assertThrowsIOOBE(() -> vhInt.get(buffer, Integer.MAX_VALUE)); 279 assertThrowsIOOBE(() -> vhInt.get(buffer, buffer.limit())); 280 assertThrowsIOOBE(() -> vhInt.get(buffer, buffer.limit() - 1)); 281 assertThrowsIOOBE(() -> vhInt.get(buffer, buffer.limit() - 2)); 282 assertThrowsIOOBE(() -> vhInt.get(buffer, buffer.limit() - 3)); 283 final int zeroAlignment = buffer.alignmentOffset(0, Integer.BYTES); 284 for (int i = 0; i < buffer.limit() - 3; ++i) { 285 boolean isAligned = (zeroAlignment + i) % Integer.BYTES == 0; 286 final int value = (i + 1) * 0x11223344; 287 vhInt.set(buffer, i, value); 288 assertEquals(value, vhInt.get(buffer, i)); 289 assertEquals( 290 value, 291 toHost( 292 byteOrder, 293 buffer.get(i), 294 buffer.get(i + 1), 295 buffer.get(i + 2), 296 buffer.get(i + 3))); 297 for (int j = 0; j < buffer.limit(); ++j) { 298 if (j < i || j > i + 3) { 299 assertEquals((byte) 0, buffer.get(j)); 300 } 301 } 302 if (isAligned) { 303 vhInt.getAcquire(buffer, i); 304 vhInt.setRelease(buffer, i, (int) 0); 305 } else { 306 final int fi = i; 307 assertThrowsISE(() -> vhInt.getAcquire(buffer, fi)); 308 assertThrowsISE(() -> vhInt.setRelease(buffer, fi, (int) 0)); 309 } 310 vhInt.set(buffer, i, 0); 311 } 312 } 313 } 314 } 315 } 316 317 @Override doTest()318 protected void doTest() throws Exception { 319 testIntegerArrayVarHandle(); 320 testObjectArrayVarHandle(); 321 testByteArrayViewVarHandle(); 322 testByteBufferVarHandle(); 323 } 324 main(String[] args)325 public static void main(String[] args) { 326 new ArrayStoreTest().run(); 327 } 328 } 329 main(String[] args)330 public static void main(String[] args) { 331 ArrayStoreTest.main(args); 332 } 333 } 334