From 9b137681bb32502770e710b454b9aefbd4490816 Mon Sep 17 00:00:00 2001 From: SirYwell Date: Sun, 20 Aug 2023 10:48:12 +0200 Subject: [PATCH] Avoid Unsafe usage where possible --- .../PaperweightPlatformAdapter.java | 24 +++---------- .../v1_17_R1_2/regen/PaperweightRegen.java | 2 +- .../v1_18_R2/PaperweightPlatformAdapter.java | 35 ++++--------------- .../fawe/v1_18_R2/regen/PaperweightRegen.java | 2 +- .../v1_19_R3/PaperweightPlatformAdapter.java | 34 ++++-------------- .../fawe/v1_19_R3/regen/PaperweightRegen.java | 2 +- .../v1_20_R1/PaperweightPlatformAdapter.java | 34 ++++-------------- .../fawe/v1_20_R1/regen/PaperweightRegen.java | 2 +- .../core/util/ReflectionUtils.java | 19 ++++++++-- 9 files changed, 43 insertions(+), 111 deletions(-) diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java index 688a84a149..0854fc7ad6 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightPlatformAdapter.java @@ -85,11 +85,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodGetVisibleChunk; - private static final int CHUNKSECTION_BASE; - private static final int CHUNKSECTION_SHIFT; - private static final Field fieldLock; - private static final long fieldLockOffset; private static final Field fieldGameEventDispatcherSections; private static final MethodHandle methodremoveBlockEntityTicker; @@ -127,15 +123,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { getVisibleChunkIfPresent.setAccessible(true); methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); - Unsafe unsafe = ReflectionUtils.getUnsafe(); if (!PaperLib.isPaper()) { - fieldLock = PalettedContainer.class.getDeclaredField(Refraction.pickName("lock", "m")); - fieldLockOffset = unsafe.objectFieldOffset(fieldLock); + fieldLock.setAccessible(true); } else { // in paper, the used methods are synchronized properly fieldLock = null; - fieldLockOffset = -1; } fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName( @@ -152,13 +145,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); fieldRemove.setAccessible(true); - - CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class); - int scale = unsafe.arrayIndexScale(LevelChunkSection[].class); - if ((scale & (scale - 1)) != 0) { - throw new Error("data type scale not a power of two"); - } - CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale); } catch (RuntimeException e) { throw e; } catch (Throwable rethrow) { @@ -173,9 +159,8 @@ static boolean setSectionAtomic( LevelChunkSection value, int layer ) { - long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value); + return ReflectionUtils.compareAndSet(sections, expected, value, layer); } return false; } @@ -190,14 +175,13 @@ static DelegateSemaphore applyLock(LevelChunkSection section) { } try { synchronized (section) { - Unsafe unsafe = ReflectionUtils.getUnsafe(); PalettedContainer blocks = section.getStates(); - Semaphore currentLock = (Semaphore) unsafe.getObject(blocks, fieldLockOffset); + Semaphore currentLock = (Semaphore) fieldLock.get(blocks); if (currentLock instanceof DelegateSemaphore delegateSemaphore) { return delegateSemaphore; } DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - unsafe.putObject(blocks, fieldLockOffset, newLock); + fieldLock.set(blocks, newLock); return newLock; } } catch (Throwable e) { diff --git a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java index 3d9694af99..09577f1eff 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/regen/PaperweightRegen.java @@ -332,7 +332,7 @@ public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean creat } }; - ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider); + chunkSourceField.set(freshWorld, freshChunkProvider); //let's start then structureManager = server.getStructureManager(); threadedLevelLightEngine = freshChunkProvider.getLightEngine(); diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPlatformAdapter.java index dbf7f88f3c..1075694b47 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightPlatformAdapter.java @@ -92,14 +92,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodGetVisibleChunk; - private static final int CHUNKSECTION_BASE; - private static final int CHUNKSECTION_SHIFT; - private static final Field fieldThreadingDetector; - private static final long fieldThreadingDetectorOffset; - private static final Field fieldLock; - private static final long fieldLockOffset; private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; @@ -136,20 +130,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { getVisibleChunkIfPresent.setAccessible(true); methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); - Unsafe unsafe = ReflectionUtils.getUnsafe(); if (!PaperLib.isPaper()) { fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); - fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); - + fieldThreadingDetector.setAccessible(true); fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); - fieldLockOffset = unsafe.objectFieldOffset(fieldLock); + fieldLock.setAccessible(true); } else { // in paper, the used methods are synchronized properly fieldThreadingDetector = null; - fieldThreadingDetectorOffset = -1; - fieldLock = null; - fieldLockOffset = -1; } Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( @@ -169,13 +158,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "p")); fieldRemove.setAccessible(true); - - CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class); - int scale = unsafe.arrayIndexScale(LevelChunkSection[].class); - if ((scale & (scale - 1)) != 0) { - throw new Error("data type scale not a power of two"); - } - CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale); } catch (RuntimeException e) { throw e; } catch (Throwable rethrow) { @@ -190,9 +172,8 @@ static boolean setSectionAtomic( LevelChunkSection value, int layer ) { - long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value); + return ReflectionUtils.compareAndSet(sections, expected, value, layer); } return false; } @@ -207,19 +188,15 @@ static DelegateSemaphore applyLock(LevelChunkSection section) { } try { synchronized (section) { - Unsafe unsafe = ReflectionUtils.getUnsafe(); PalettedContainer blocks = section.getStates(); - ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject( - blocks, - fieldThreadingDetectorOffset - ); + ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); synchronized (currentThreadingDetector) { - Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); + Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); if (currentLock instanceof DelegateSemaphore delegateSemaphore) { return delegateSemaphore; } DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); + fieldLock.set(currentThreadingDetector, newLock); return newLock; } } diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java index 51bd22bdb2..575068a743 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/regen/PaperweightRegen.java @@ -345,7 +345,7 @@ public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean creat } }; - ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider); + chunkSourceField.set(freshWorld, freshChunkProvider); //let's start then structureManager = server.getStructureManager(); threadedLevelLightEngine = freshChunkProvider.getLightEngine(); diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java index d351bbacdc..16210db381 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/PaperweightPlatformAdapter.java @@ -99,14 +99,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodGetVisibleChunk; - private static final int CHUNKSECTION_BASE; - private static final int CHUNKSECTION_SHIFT; - private static final Field fieldThreadingDetector; - private static final long fieldThreadingDetectorOffset; - private static final Field fieldLock; - private static final long fieldLockOffset; private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; @@ -149,20 +143,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { getVisibleChunkIfPresent.setAccessible(true); methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent); - Unsafe unsafe = ReflectionUtils.getUnsafe(); if (!PaperLib.isPaper()) { fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); - fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); - + fieldThreadingDetector.setAccessible(true); fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); - fieldLockOffset = unsafe.objectFieldOffset(fieldLock); + fieldLock.setAccessible(true); } else { // in paper, the used methods are synchronized properly fieldThreadingDetector = null; - fieldThreadingDetectorOffset = -1; - fieldLock = null; - fieldLockOffset = -1; } Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( @@ -185,12 +174,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "q")); fieldRemove.setAccessible(true); - CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class); - int scale = unsafe.arrayIndexScale(LevelChunkSection[].class); - if ((scale & (scale - 1)) != 0) { - throw new Error("data type scale not a power of two"); - } - CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale); boolean chunkRewrite; try { ServerLevel.class.getDeclaredMethod("getEntityLookup"); @@ -226,9 +209,8 @@ static boolean setSectionAtomic( LevelChunkSection value, int layer ) { - long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value); + return ReflectionUtils.compareAndSet(sections, expected, value, layer); } return false; } @@ -243,19 +225,15 @@ static DelegateSemaphore applyLock(LevelChunkSection section) { } try { synchronized (section) { - Unsafe unsafe = ReflectionUtils.getUnsafe(); PalettedContainer blocks = section.getStates(); - ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject( - blocks, - fieldThreadingDetectorOffset - ); + ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); synchronized (currentThreadingDetector) { - Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); + Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); if (currentLock instanceof DelegateSemaphore delegateSemaphore) { return delegateSemaphore; } DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); + fieldLock.set(currentThreadingDetector, newLock); return newLock; } } diff --git a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java index 4f22e87346..b5ec4a0eac 100644 --- a/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_19_4/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_19_R3/regen/PaperweightRegen.java @@ -372,7 +372,7 @@ public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean creat } - ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider); + chunkSourceField.set(freshWorld, freshChunkProvider); //let's start then structureTemplateManager = server.getStructureManager(); threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java index 8cb8a86622..2fe34894d9 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/PaperweightPlatformAdapter.java @@ -102,14 +102,8 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { private static final MethodHandle methodGetVisibleChunk; - private static final int CHUNKSECTION_BASE; - private static final int CHUNKSECTION_SHIFT; - private static final Field fieldThreadingDetector; - private static final long fieldThreadingDetectorOffset; - private static final Field fieldLock; - private static final long fieldLockOffset; private static final MethodHandle methodRemoveGameEventListener; private static final MethodHandle methodremoveTickingBlockEntity; @@ -158,20 +152,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { getVisibleChunkIfPresent.setAccessible(true); methodGetVisibleChunk = lookup.unreflect(getVisibleChunkIfPresent); - Unsafe unsafe = ReflectionUtils.getUnsafe(); if (!PaperLib.isPaper()) { fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); - fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); - + fieldThreadingDetector.setAccessible(true); fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); - fieldLockOffset = unsafe.objectFieldOffset(fieldLock); + fieldLock.setAccessible(true); } else { // in paper, the used methods are synchronized properly fieldThreadingDetector = null; - fieldThreadingDetectorOffset = -1; - fieldLock = null; - fieldLockOffset = -1; } Method removeGameEventListener = LevelChunk.class.getDeclaredMethod( @@ -194,12 +183,6 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { fieldRemove = BlockEntity.class.getDeclaredField(Refraction.pickName("remove", "q")); fieldRemove.setAccessible(true); - CHUNKSECTION_BASE = unsafe.arrayBaseOffset(LevelChunkSection[].class); - int scale = unsafe.arrayIndexScale(LevelChunkSection[].class); - if ((scale & (scale - 1)) != 0) { - throw new Error("data type scale not a power of two"); - } - CHUNKSECTION_SHIFT = 31 - Integer.numberOfLeadingZeros(scale); boolean chunkRewrite; try { ServerLevel.class.getDeclaredMethod("getEntityLookup"); @@ -249,9 +232,8 @@ static boolean setSectionAtomic( LevelChunkSection value, int layer ) { - long offset = ((long) layer << CHUNKSECTION_SHIFT) + CHUNKSECTION_BASE; if (layer >= 0 && layer < sections.length) { - return ReflectionUtils.getUnsafe().compareAndSwapObject(sections, offset, expected, value); + return ReflectionUtils.compareAndSet(sections, expected, value, layer); } return false; } @@ -266,19 +248,15 @@ static DelegateSemaphore applyLock(LevelChunkSection section) { } try { synchronized (section) { - Unsafe unsafe = ReflectionUtils.getUnsafe(); PalettedContainer blocks = section.getStates(); - ThreadingDetector currentThreadingDetector = (ThreadingDetector) unsafe.getObject( - blocks, - fieldThreadingDetectorOffset - ); + ThreadingDetector currentThreadingDetector = (ThreadingDetector) fieldThreadingDetector.get(blocks); synchronized (currentThreadingDetector) { - Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); + Semaphore currentLock = (Semaphore) fieldLock.get(currentThreadingDetector); if (currentLock instanceof DelegateSemaphore delegateSemaphore) { return delegateSemaphore; } DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); - unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); + fieldLock.set(currentThreadingDetector, newLock); return newLock; } } diff --git a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java index b5d5a27331..726aa77525 100644 --- a/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java +++ b/worldedit-bukkit/adapters/adapter-1_20/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_20_R1/regen/PaperweightRegen.java @@ -373,7 +373,7 @@ public ChunkAccess getChunk(int x, int z, ChunkStatus chunkstatus, boolean creat } - ReflectionUtils.unsafeSet(chunkSourceField, freshWorld, freshChunkProvider); + chunkSourceField.set(freshWorld, freshChunkProvider); //let's start then structureTemplateManager = server.getStructureManager(); threadedLevelLightEngine = new NoOpLightEngine(freshChunkProvider); diff --git a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ReflectionUtils.java b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ReflectionUtils.java index 6071175350..7b8ffcd2cd 100644 --- a/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ReflectionUtils.java +++ b/worldedit-core/src/main/java/com/fastasyncworldedit/core/util/ReflectionUtils.java @@ -4,19 +4,19 @@ import javax.annotation.Nonnull; import java.lang.invoke.MethodHandles; +import java.lang.invoke.VarHandle; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.Arrays; -import java.util.Comparator; /** * This is an internal class not meant to be used outside the FAWE internals. */ public class ReflectionUtils { + private static final VarHandle REFERENCE_ARRAY_HANDLE = MethodHandles.arrayElementVarHandle(Object[].class); private static Unsafe UNSAFE; static { @@ -33,6 +33,21 @@ public static T as(Class t, Object o) { return t.isInstance(o) ? t.cast(o) : null; } + /** + * Performs CAS on the array element at the given index. + * + * @param array the array in which to compare and set the value + * @param expectedValue the value expected to be at the index + * @param newValue the new value to be set at the index if the expected value matches + * @param index the index at which to compare and set the value + * @param the type of elements in the array + * @return true if the value at the index was successfully updated to the new value, false otherwise + * @see VarHandle#compareAndSet(Object...) + */ + public static boolean compareAndSet(T[] array, T expectedValue, T newValue, int index) { + return REFERENCE_ARRAY_HANDLE.compareAndSet(array, index, expectedValue, newValue); + } + public static void setAccessibleNonFinal(Field field) { // let's make the field accessible field.setAccessible(true);