/* * Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.hazelcast.internal.memory.impl; import com.hazelcast.internal.memory.GlobalMemoryAccessor; import com.hazelcast.test.HazelcastSerialClassRunner; import com.hazelcast.test.annotation.QuickTest; import com.hazelcast.util.ExceptionUtil; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; import sun.misc.Unsafe; import static com.hazelcast.internal.memory.HeapMemoryAccessor.ARRAY_BYTE_BASE_OFFSET; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @RunWith(HazelcastSerialClassRunner.class) @Category({QuickTest.class}) public abstract class BaseMemoryAccessorTest extends AbstractUnsafeDependentMemoryAccessorTest { private static final int ALLOCATED_BLOCK_SIZE = 16; private static final int CHAR_MISALIGNMENT = 1; private static final int SHORT_MISALIGNMENT = 1; private static final int INT_MISALIGNMENT = 2; private static final int FLOAT_MISALIGNMENT = 2; private static final int LONG_MISALIGNMENT = 4; private static final int DOUBLE_MISALIGNMENT = 4; private static final int OBJECT_MISALIGNMENT = 2; protected final Unsafe unsafe = UnsafeUtil.UNSAFE; private GlobalMemoryAccessor memoryAccessor; private final SampleObject sampleObject = new SampleObject(); private long baseAddress1; private long baseAddress2; @Before public void setup() { baseAddress1 = allocate(); baseAddress2 = allocate(); memoryAccessor = getMemoryAccessor(); } @After public void tearDown() { free(baseAddress1); free(baseAddress2); } private long allocate() { return unsafe.allocateMemory(ALLOCATED_BLOCK_SIZE); } private void free(long address) { if (address != 0) { unsafe.freeMemory(address); } } protected abstract GlobalMemoryAccessor getMemoryAccessor(); //////////////////////////////////////////////////////////////////////////////// @Test public void test_getObjectFieldOffset() throws NoSuchFieldException { final Class<SampleObjectBase> klass = SampleObjectBase.class; assertEquals(SampleObject.BOOLEAN_VALUE_OFFSET, memoryAccessor.objectFieldOffset(klass.getDeclaredField("booleanValue"))); assertEquals(SampleObject.BYTE_VALUE_OFFSET, memoryAccessor.objectFieldOffset(klass.getDeclaredField("byteValue"))); assertEquals(SampleObject.CHAR_VALUE_OFFSET, memoryAccessor.objectFieldOffset(klass.getDeclaredField("charValue"))); assertEquals(SampleObject.SHORT_VALUE_OFFSET, memoryAccessor.objectFieldOffset(klass.getDeclaredField("shortValue"))); assertEquals(SampleObject.INT_VALUE_OFFSET, memoryAccessor.objectFieldOffset(klass.getDeclaredField("intValue"))); assertEquals(SampleObject.FLOAT_VALUE_OFFSET, memoryAccessor.objectFieldOffset(klass.getDeclaredField("floatValue"))); assertEquals(SampleObject.LONG_VALUE_OFFSET, memoryAccessor.objectFieldOffset(klass.getDeclaredField("longValue"))); assertEquals(SampleObject.DOUBLE_VALUE_OFFSET, memoryAccessor.objectFieldOffset(klass.getDeclaredField("doubleValue"))); assertEquals(SampleObject.OBJECT_VALUE_OFFSET, memoryAccessor.objectFieldOffset(klass.getDeclaredField("objectValue"))); } @Test public void test_getArrayBaseOffset() { assertEquals(unsafe.arrayBaseOffset(boolean[].class), memoryAccessor.arrayBaseOffset(boolean[].class)); assertEquals(unsafe.arrayBaseOffset(byte[].class), memoryAccessor.arrayBaseOffset(byte[].class)); assertEquals(unsafe.arrayBaseOffset(char[].class), memoryAccessor.arrayBaseOffset(char[].class)); assertEquals(unsafe.arrayBaseOffset(short[].class), memoryAccessor.arrayBaseOffset(short[].class)); assertEquals(unsafe.arrayBaseOffset(int[].class), memoryAccessor.arrayBaseOffset(int[].class)); assertEquals(unsafe.arrayBaseOffset(float[].class), memoryAccessor.arrayBaseOffset(float[].class)); assertEquals(unsafe.arrayBaseOffset(long[].class), memoryAccessor.arrayBaseOffset(long[].class)); assertEquals(unsafe.arrayBaseOffset(double[].class), memoryAccessor.arrayBaseOffset(double[].class)); assertEquals(unsafe.arrayBaseOffset(Object[].class), memoryAccessor.arrayBaseOffset(Object[].class)); } @Test public void test_getArrayIndexScale() { assertEquals(unsafe.arrayIndexScale(boolean[].class), memoryAccessor.arrayIndexScale(boolean[].class)); assertEquals(unsafe.arrayIndexScale(byte[].class), memoryAccessor.arrayIndexScale(byte[].class)); assertEquals(unsafe.arrayIndexScale(char[].class), memoryAccessor.arrayIndexScale(char[].class)); assertEquals(unsafe.arrayIndexScale(short[].class), memoryAccessor.arrayIndexScale(short[].class)); assertEquals(unsafe.arrayIndexScale(int[].class), memoryAccessor.arrayIndexScale(int[].class)); assertEquals(unsafe.arrayIndexScale(float[].class), memoryAccessor.arrayIndexScale(float[].class)); assertEquals(unsafe.arrayIndexScale(long[].class), memoryAccessor.arrayIndexScale(long[].class)); assertEquals(unsafe.arrayIndexScale(double[].class), memoryAccessor.arrayIndexScale(double[].class)); assertEquals(unsafe.arrayIndexScale(Object[].class), memoryAccessor.arrayIndexScale(Object[].class)); } //////////////////////////////////////////////////////////////////////////////// @Test public void test_endianness() { final long address = baseAddress1; memoryAccessor.putInt(address, 0x01000009); if (memoryAccessor.isBigEndian()) { assertEquals(0x01, memoryAccessor.getByte(address)); } else { assertEquals(0x09, memoryAccessor.getByte(address)); } } //////////////////////////////////////////////////////////////////////////////// @Test public void test_copyMemory_whenAligned() { do_test_copyMemory(true); } @Test public void test_copyMemory_whenUnaligned() { do_test_copyMemory(false); } void do_test_copyMemory(boolean aligned) { final int copyLength = ALLOCATED_BLOCK_SIZE / 2; long sourceAddress = aligned ? baseAddress1 : baseAddress1 + 1; long destinationAddress = aligned ? baseAddress2 : baseAddress2 + 3; for (int i = 0; i < copyLength; i++) { memoryAccessor.putByte(sourceAddress + i, (byte) (i * i)); } memoryAccessor.copyMemory(sourceAddress, destinationAddress, copyLength); for (int i = 0; i < copyLength; i++) { assertEquals((byte) (i * i), memoryAccessor.getByte(destinationAddress + i)); } byte[] src = new byte[]{0x11, 0x22, 0x33, 0x44}; byte[] dest = new byte[src.length]; memoryAccessor.copyMemory(src, ARRAY_BYTE_BASE_OFFSET, dest, ARRAY_BYTE_BASE_OFFSET, src.length); assertArrayEquals(src, dest); } //////////////////////////////////////////////////////////////////////////////// @Test public void test_setMemory_whenAligned() { do_test_setMemory(true); } @Test public void test_setMemory_whenUnaligned() { do_test_setMemory(false); } void do_test_setMemory(boolean aligned) { final int setLength = ALLOCATED_BLOCK_SIZE / 2; long address = aligned ? baseAddress1 : baseAddress1 + 1; memoryAccessor.setMemory(address, setLength, (byte) 0x01); for (int i = 0; i < setLength; i++) { assertEquals((byte) 0x01, memoryAccessor.getByte(address + i)); } } //////////////////////////////////////////////////////////////////////////////// @Test public void test_copyFromByteArray() { final byte[] ary = {2, 3}; memoryAccessor.copyFromByteArray(ary, 0, baseAddress1, 2); for (int i = 0; i < ary.length; i++) { assertEquals(ary[i], memoryAccessor.getByte(baseAddress1 + i)); } } @Test public void test_copyToByteArray() { final byte[] ary = new byte[2]; for (int i = 0; i < ary.length; i++) { memoryAccessor.putByte(baseAddress1 + i, (byte) i); } memoryAccessor.copyToByteArray(baseAddress1, ary, 0, 2); for (int i = 0; i < ary.length; i++) { assertEquals(ary[i], memoryAccessor.getByte(baseAddress1 + i)); } } @Test public void test_putGetBoolean() { final long address = baseAddress1; memoryAccessor.putBoolean(address, true); assertTrue(memoryAccessor.getBoolean(address)); memoryAccessor.putBooleanVolatile(address, false); assertFalse(memoryAccessor.getBooleanVolatile(address)); memoryAccessor.putBoolean(sampleObject, SampleObject.BOOLEAN_VALUE_OFFSET, true); assertTrue(memoryAccessor.getBoolean(sampleObject, SampleObject.BOOLEAN_VALUE_OFFSET)); memoryAccessor.putBooleanVolatile(sampleObject, SampleObject.BOOLEAN_VALUE_OFFSET, false); assertFalse(memoryAccessor.getBooleanVolatile(sampleObject, SampleObject.BOOLEAN_VALUE_OFFSET)); } //////////////////////////////////////////////////////////////////////////////// @Test public void test_putGetByte() { final long address = baseAddress1; memoryAccessor.putByte(address, (byte) 1); assertEquals(1, memoryAccessor.getByte(address)); memoryAccessor.putByteVolatile(address, (byte) 2); assertEquals(2, memoryAccessor.getByteVolatile(address)); memoryAccessor.putByte(sampleObject, SampleObject.BYTE_VALUE_OFFSET, (byte) 3); assertEquals(3, memoryAccessor.getByte(sampleObject, SampleObject.BYTE_VALUE_OFFSET)); memoryAccessor.putByteVolatile(sampleObject, SampleObject.BYTE_VALUE_OFFSET, (byte) 4); assertEquals(4, memoryAccessor.getByteVolatile(sampleObject, SampleObject.BYTE_VALUE_OFFSET)); } //////////////////////////////////////////////////////////////////////////////// @Test public void test_putGetChar_whenAligned() { do_test_putGetChar(true); do_test_putGetCharVolatile(); } void do_test_putGetChar(boolean aligned) { long address = aligned ? baseAddress1 : baseAddress1 + CHAR_MISALIGNMENT; memoryAccessor.putChar(address, 'A'); assertEquals('A', memoryAccessor.getChar(address)); memoryAccessor.putChar(sampleObject, SampleObject.CHAR_VALUE_OFFSET, 'B'); assertEquals('B', memoryAccessor.getChar(sampleObject, SampleObject.CHAR_VALUE_OFFSET)); } void do_test_putGetCharVolatile() { long address = baseAddress1; memoryAccessor.putCharVolatile(address, 'C'); assertEquals('C', memoryAccessor.getCharVolatile(address)); memoryAccessor.putCharVolatile(sampleObject, SampleObject.CHAR_VALUE_OFFSET, 'D'); assertEquals('D', memoryAccessor.getCharVolatile(sampleObject, SampleObject.CHAR_VALUE_OFFSET)); } void assert_putGetCharVolatileUnalignedFails() { long address = baseAddress1 + 1; long objectOffset = SampleObject.CHAR_VALUE_OFFSET + CHAR_MISALIGNMENT; try { memoryAccessor.putCharVolatile(address, 'A'); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getCharVolatile(address); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.putCharVolatile(sampleObject, objectOffset, 'A'); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getCharVolatile(sampleObject, objectOffset); fail(); } catch (IllegalArgumentException ignored) { } } //////////////////////////////////////////////////////////////////// @Test public void test_putGetShort_whenAligned() { do_test_putGetShort(true); do_test_putGetShortVolatile(); } void do_test_putGetShort(boolean aligned) { long address = aligned ? baseAddress1 : baseAddress1 + SHORT_MISALIGNMENT; memoryAccessor.putShort(address, (short) 1); assertEquals(1, memoryAccessor.getShort(address)); memoryAccessor.putShort(sampleObject, SampleObject.SHORT_VALUE_OFFSET, (short) 2); assertEquals(2, memoryAccessor.getShort(sampleObject, SampleObject.SHORT_VALUE_OFFSET)); } void do_test_putGetShortVolatile() { long address = baseAddress1; memoryAccessor.putShortVolatile(address, (short) 3); assertEquals(3, memoryAccessor.getShortVolatile(address)); memoryAccessor.putShortVolatile(sampleObject, SampleObject.SHORT_VALUE_OFFSET, (short) 4); assertEquals(4, memoryAccessor.getShortVolatile(sampleObject, SampleObject.SHORT_VALUE_OFFSET)); } void assert_putGetShortVolatileUnalignedFails() { long address = baseAddress1 + SHORT_MISALIGNMENT; long objectOffset = SampleObject.SHORT_VALUE_OFFSET + SHORT_MISALIGNMENT; try { memoryAccessor.putShortVolatile(address, (short) 1); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getShortVolatile(address); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.putShortVolatile(sampleObject, objectOffset, (short) 1); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getShortVolatile(sampleObject, objectOffset); fail(); } catch (IllegalArgumentException ignored) { } } //////////////////////////////////////////////////////////////////// @Test public void test_putGetInt_whenAligned() { do_test_putGetInt(true); do_test_putGetIntVolatile(); } void do_test_putGetInt(boolean aligned) { long address = aligned ? baseAddress1 : baseAddress1 + 2; memoryAccessor.putInt(address, 1); assertEquals(1, memoryAccessor.getInt(address)); memoryAccessor.putInt(sampleObject, SampleObject.INT_VALUE_OFFSET, 2); assertEquals(2, memoryAccessor.getInt(sampleObject, SampleObject.INT_VALUE_OFFSET)); } void do_test_putGetIntVolatile() { long address = baseAddress1; memoryAccessor.putIntVolatile(address, 3); assertEquals(3, memoryAccessor.getIntVolatile(address)); memoryAccessor.putIntVolatile(sampleObject, SampleObject.INT_VALUE_OFFSET, 4); assertEquals(4, memoryAccessor.getIntVolatile(sampleObject, SampleObject.INT_VALUE_OFFSET)); } void assert_putGetIntVolatileUnalignedFails() { long address = baseAddress1 + 2; long objectOffset = SampleObject.INT_VALUE_OFFSET + INT_MISALIGNMENT; try { memoryAccessor.putIntVolatile(address, 1); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getIntVolatile(address); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.putIntVolatile(sampleObject, objectOffset, 1); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getIntVolatile(sampleObject, objectOffset); fail(); } catch (IllegalArgumentException ignored) { } } //////////////////////////////////////////////////////////////////// @Test public void test_putGetFloat_whenAligned() { do_test_putGetFloat(true); do_test_putGetFloatVolatile(); } void do_test_putGetFloat(boolean aligned) { long address = aligned ? baseAddress1 : baseAddress1 + FLOAT_MISALIGNMENT; memoryAccessor.putFloat(address, 1f); assertEquals(1f, memoryAccessor.getFloat(address), 0f); memoryAccessor.putFloat(sampleObject, SampleObject.FLOAT_VALUE_OFFSET, 2f); assertEquals(2f, memoryAccessor.getFloat(sampleObject, SampleObject.FLOAT_VALUE_OFFSET), 0f); } void do_test_putGetFloatVolatile() { long address = baseAddress1; memoryAccessor.putFloatVolatile(address, 3f); assertEquals(3f, memoryAccessor.getFloatVolatile(address), 0f); memoryAccessor.putFloatVolatile(sampleObject, SampleObject.FLOAT_VALUE_OFFSET, 4f); assertEquals(4f, memoryAccessor.getFloatVolatile(sampleObject, SampleObject.FLOAT_VALUE_OFFSET), 0f); } void assert_putGetFloatVolatileUnalignedFails() { long address = baseAddress1 + FLOAT_MISALIGNMENT; long objectOffset = SampleObject.FLOAT_VALUE_OFFSET + FLOAT_MISALIGNMENT; try { memoryAccessor.putFloatVolatile(address, 1); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getFloatVolatile(address); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.putFloatVolatile(sampleObject, objectOffset, 1); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getFloatVolatile(sampleObject, objectOffset); fail(); } catch (IllegalArgumentException ignored) { } } //////////////////////////////////////////////////////////////////// @Test public void test_putGetLong_whenAligned() { do_test_putGetLong(true); do_test_putGetLongVolatile(); } void do_test_putGetLong(boolean aligned) { long address = aligned ? baseAddress1 : baseAddress1 + LONG_MISALIGNMENT; memoryAccessor.putLong(address, 1); assertEquals(1, memoryAccessor.getLong(address)); memoryAccessor.putLong(sampleObject, SampleObject.LONG_VALUE_OFFSET, 2); assertEquals(2, memoryAccessor.getLong(sampleObject, SampleObject.LONG_VALUE_OFFSET)); } void do_test_putGetLongVolatile() { long address = baseAddress1; memoryAccessor.putLongVolatile(address, 3); assertEquals(3, memoryAccessor.getLongVolatile(address)); memoryAccessor.putLongVolatile(sampleObject, SampleObject.LONG_VALUE_OFFSET, 4); assertEquals(4, memoryAccessor.getLongVolatile(sampleObject, SampleObject.LONG_VALUE_OFFSET)); } void assert_putGetLongVolatileUnalignedFails() { long address = baseAddress1 + LONG_MISALIGNMENT; long objectOffset = SampleObject.LONG_VALUE_OFFSET + LONG_MISALIGNMENT; try { memoryAccessor.putLongVolatile(address, 1); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getLongVolatile(address); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.putLongVolatile(sampleObject, objectOffset, 1); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getLongVolatile(sampleObject, objectOffset); fail(); } catch (IllegalArgumentException ignored) { } } //////////////////////////////////////////////////////////////////// @Test public void test_putGetDouble_whenAligned() { do_test_putGetDouble(true); do_test_putGetDoubleVolatile(); } void do_test_putGetDouble(boolean aligned) { long address = aligned ? baseAddress1 : baseAddress1 + DOUBLE_MISALIGNMENT; memoryAccessor.putDouble(address, 1f); assertEquals(1f, memoryAccessor.getDouble(address), 0f); memoryAccessor.putDouble(sampleObject, SampleObject.DOUBLE_VALUE_OFFSET, 2f); assertEquals(2f, memoryAccessor.getDouble(sampleObject, SampleObject.DOUBLE_VALUE_OFFSET), 0f); } void do_test_putGetDoubleVolatile() { long address = baseAddress1; memoryAccessor.putDoubleVolatile(address, 3f); assertEquals(3f, memoryAccessor.getDoubleVolatile(address), 0f); memoryAccessor.putDoubleVolatile(sampleObject, SampleObject.DOUBLE_VALUE_OFFSET, 4f); assertEquals(4f, memoryAccessor.getDoubleVolatile(sampleObject, SampleObject.DOUBLE_VALUE_OFFSET), 0f); } void assert_putGetDoubleVolatileUnalignedFails() { long address = baseAddress1 + DOUBLE_MISALIGNMENT; long objectOffset = SampleObject.DOUBLE_VALUE_OFFSET + DOUBLE_MISALIGNMENT; try { memoryAccessor.putDoubleVolatile(address, 1); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getDoubleVolatile(address); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.putDoubleVolatile(sampleObject, objectOffset, 1); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getDoubleVolatile(sampleObject, objectOffset); fail(); } catch (IllegalArgumentException ignored) { } } //////////////////////////////////////////////////////////////////////////////// @Test public void test_putGetObject_whenAligned() { final String value1 = "a"; memoryAccessor.putObject(sampleObject, SampleObject.OBJECT_VALUE_OFFSET, value1); assertEquals(value1, memoryAccessor.getObject(sampleObject, SampleObject.OBJECT_VALUE_OFFSET)); final String value2 = "b"; memoryAccessor.putObjectVolatile(sampleObject, SampleObject.OBJECT_VALUE_OFFSET, value2); assertEquals(value2, memoryAccessor.getObjectVolatile(sampleObject, SampleObject.OBJECT_VALUE_OFFSET)); } void assert_putGetObjectUnalignedFails() { long objectOffset = SampleObject.OBJECT_VALUE_OFFSET + OBJECT_MISALIGNMENT; final String value = "a"; try { memoryAccessor.putObjectVolatile(sampleObject, objectOffset, value); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getObjectVolatile(sampleObject, objectOffset); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.putObject(sampleObject, objectOffset, value); fail(); } catch (IllegalArgumentException ignored) { } try { memoryAccessor.getObject(sampleObject, objectOffset); fail(); } catch (IllegalArgumentException ignored) { } } //////////////////////////////////////////////////////////////////////////////// @Test public void test_compareAndSwapInt_whenAligned() { do_test_compareAndSwapInt(true); } @Test @RequiresUnalignedMemoryAccessSupport public void test_compareAndSwapInt_whenUnaligned() { do_test_compareAndSwapInt(false); } void do_test_compareAndSwapInt(boolean aligned) { long accessAddress = aligned ? baseAddress1 : baseAddress1 + 1; memoryAccessor.putInt(accessAddress, 1); assertEquals(1, memoryAccessor.getInt(accessAddress)); assertFalse(memoryAccessor.compareAndSwapInt(accessAddress, 0, 2)); assertTrue(memoryAccessor.compareAndSwapInt(accessAddress, 1, 2)); assertEquals(2, memoryAccessor.getInt(accessAddress)); memoryAccessor.putInt(sampleObject, SampleObject.INT_VALUE_OFFSET, 1); assertEquals(1, memoryAccessor.getInt(sampleObject, SampleObject.INT_VALUE_OFFSET)); assertFalse(memoryAccessor.compareAndSwapInt(sampleObject, SampleObject.INT_VALUE_OFFSET, 0, 2)); assertTrue(memoryAccessor.compareAndSwapInt(sampleObject, SampleObject.INT_VALUE_OFFSET, 1, 2)); assertEquals(2, memoryAccessor.getInt(sampleObject, SampleObject.INT_VALUE_OFFSET)); } //////////////////////////////////////////////////////////////////////////////// @Test public void test_compareAndSwapLong_whenAligned() { do_test_compareAndSwapLong(true); } @Test @RequiresUnalignedMemoryAccessSupport public void test_compareAndSwapLong_whenUnaligned() { do_test_compareAndSwapLong(false); } void do_test_compareAndSwapLong(boolean aligned) { long accessAddress = aligned ? baseAddress1 : baseAddress1 + 1; memoryAccessor.putLong(accessAddress, 1L); assertEquals(1L, memoryAccessor.getLong(accessAddress)); assertFalse(memoryAccessor.compareAndSwapLong(accessAddress, 0L, 2L)); assertTrue(memoryAccessor.compareAndSwapLong(accessAddress, 1L, 2L)); assertEquals(2L, memoryAccessor.getLong(accessAddress)); memoryAccessor.putLong(sampleObject, SampleObject.LONG_VALUE_OFFSET, 1L); assertEquals(1L, memoryAccessor.getLong(sampleObject, SampleObject.LONG_VALUE_OFFSET)); assertFalse(memoryAccessor.compareAndSwapLong(sampleObject, SampleObject.LONG_VALUE_OFFSET, 0L, 2L)); assertTrue(memoryAccessor.compareAndSwapLong(sampleObject, SampleObject.LONG_VALUE_OFFSET, 1L, 2L)); assertEquals(2L, memoryAccessor.getLong(sampleObject, SampleObject.LONG_VALUE_OFFSET)); } //////////////////////////////////////////////////////////////////////////////// @Test public void test_compareAndSwapObject_whenAligned() { do_test_compareAndSwapObject(true); } protected void do_test_compareAndSwapObject(boolean aligned) { long offset = SampleObject.OBJECT_VALUE_OFFSET; long accessOffset = aligned ? offset : offset + 1; String str1 = "String Object 1"; memoryAccessor.putObject(sampleObject, accessOffset, str1); assertEquals(str1, memoryAccessor.getObject(sampleObject, accessOffset)); String str2 = "String Object 2"; assertFalse(memoryAccessor.compareAndSwapObject(sampleObject, accessOffset, null, str2)); assertTrue(memoryAccessor.compareAndSwapObject(sampleObject, accessOffset, str1, str2)); assertEquals(str2, memoryAccessor.getObject(sampleObject, accessOffset)); } //////////////////////////////////////////////////////////////////////////////// @Test public void test_putOrderedInt_whenAligned() { do_test_putOrderedInt(true); } @Test @RequiresUnalignedMemoryAccessSupport public void test_putOrderedInt_whenUnaligned() { do_test_putOrderedInt(false); } void do_test_putOrderedInt(boolean aligned) { long accessAddress = aligned ? baseAddress1 : baseAddress1 + 1; memoryAccessor.putOrderedInt(accessAddress, 1); assertEquals(1, memoryAccessor.getInt(accessAddress)); memoryAccessor.putOrderedInt(sampleObject, SampleObject.INT_VALUE_OFFSET, 1); assertEquals(1, memoryAccessor.getInt(sampleObject, SampleObject.INT_VALUE_OFFSET)); } //////////////////////////////////////////////////////////////////////////////// @Test public void test_putOrderedLong_whenAligned() { do_test_putOrderedLong(true); } @Test @RequiresUnalignedMemoryAccessSupport public void test_putOrderedLong_whenUnaligned() { do_test_putOrderedLong(false); } void do_test_putOrderedLong(boolean aligned) { long accessAddress = aligned ? baseAddress1 : baseAddress1 + 1; memoryAccessor.putOrderedLong(accessAddress, 1L); assertEquals(1L, memoryAccessor.getLong(accessAddress)); memoryAccessor.putOrderedLong(sampleObject, SampleObject.LONG_VALUE_OFFSET, 1L); assertEquals(1L, memoryAccessor.getLong(sampleObject, SampleObject.LONG_VALUE_OFFSET)); } //////////////////////////////////////////////////////////////////////////////// @Test public void test_putOrderedObject_whenAligned() { do_test_putOrderedObject(true); } protected void do_test_putOrderedObject(boolean aligned) { long offset = SampleObject.OBJECT_VALUE_OFFSET; long accessOffset = aligned ? offset : offset + 1; String str = "String Object"; memoryAccessor.putOrderedObject(sampleObject, accessOffset, str); assertEquals(str, memoryAccessor.getObject(sampleObject, accessOffset)); } //////////////////////////////////////////////////////////////////////////////// private static long getSampleObjectFieldOffset(String fieldName) { try { return UnsafeUtil.UNSAFE.objectFieldOffset(SampleObjectBase.class.getDeclaredField(fieldName)); } catch (NoSuchFieldException e) { throw ExceptionUtil.rethrow(e); } } @SuppressWarnings("unused") private static class SampleObjectBase { private byte byteValue; private boolean booleanValue; private char charValue; private short shortValue; private int intValue; private float floatValue; private long longValue; private double doubleValue; private Object objectValue; } @SuppressWarnings("unused") private static class SampleObject extends SampleObjectBase { private static final long BYTE_VALUE_OFFSET = getSampleObjectFieldOffset("byteValue"); private static final long BOOLEAN_VALUE_OFFSET = getSampleObjectFieldOffset("booleanValue"); private static final long CHAR_VALUE_OFFSET = getSampleObjectFieldOffset("charValue"); private static final long SHORT_VALUE_OFFSET = getSampleObjectFieldOffset("shortValue"); private static final long INT_VALUE_OFFSET = getSampleObjectFieldOffset("intValue"); private static final long FLOAT_VALUE_OFFSET = getSampleObjectFieldOffset("floatValue"); private static final long LONG_VALUE_OFFSET = getSampleObjectFieldOffset("longValue"); private static final long DOUBLE_VALUE_OFFSET = getSampleObjectFieldOffset("doubleValue"); private static final long OBJECT_VALUE_OFFSET = getSampleObjectFieldOffset("objectValue"); // ensures additional allocated space at the end of the object, which may be needed to test // unaligned access without causing heap corruption private long padding; } }