From c45b14a52d5a3ef7bbc8e4de3d349456debd9b08 Mon Sep 17 00:00:00 2001 From: Hannes Greule Date: Sun, 27 Mar 2022 23:56:59 +0200 Subject: [PATCH] Avoid Unsafe on paper (#1678) --- .../fawe/v1_17_R1_2/PaperweightGetBlocks.java | 6 ++--- .../PaperweightPlatformAdapter.java | 20 +++++++++++--- .../fawe/v1_18_R1/PaperweightGetBlocks.java | 6 ++--- .../v1_18_R1/PaperweightPlatformAdapter.java | 24 +++++++++++++---- .../fawe/v1_18_R2/PaperweightGetBlocks.java | 6 ++--- .../v1_18_R2/PaperweightPlatformAdapter.java | 26 ++++++++++++++----- 6 files changed, 64 insertions(+), 24 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/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java index 6c2e77c7d..442631806 100644 --- a/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_17_1/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_17_R1_2/PaperweightGetBlocks.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.configuration.Settings; @@ -74,6 +73,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; @@ -505,7 +505,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc } //ensure that the server doesn't try to tick the chunksection while we're editing it (again). - DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); + Semaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); PaperweightPlatformAdapter.clearCounts(existingSection); if (PaperLib.isPaper()) { existingSection.tickingList.clear(); @@ -867,7 +867,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc data = new char[4096]; Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); } - DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section); + Semaphore lock = PaperweightPlatformAdapter.applyLock(section); synchronized (lock) { // Efficiently convert ChunkSection to raw data try { 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 dfd67abe3..b4039fdc0 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 @@ -30,6 +30,7 @@ import net.minecraft.server.level.ChunkMap; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.BitStorage; +import net.minecraft.util.ThreadingDetector; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.biome.Biome; @@ -117,8 +118,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); Unsafe unsafe = ReflectionUtils.getUnsafe(); - fieldLock = PalettedContainer.class.getDeclaredField(Refraction.pickName("lock", "m")); - fieldLockOffset = unsafe.objectFieldOffset(fieldLock); + if (!PaperLib.isPaper()) { + + fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "m")); + fieldLockOffset = unsafe.objectFieldOffset(fieldLock); + } else { + // in paper, the used methods are synchronized properly + fieldLock = null; + fieldLockOffset = -1; + } fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName( "gameEventDispatcherSections", "x")); @@ -162,8 +170,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return false; } - static DelegateSemaphore applyLock(LevelChunkSection section) { - //todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS? + private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = ThreadLocal.withInitial(() -> new Semaphore(1)); + + static Semaphore applyLock(LevelChunkSection section) { + if (PaperLib.isPaper()) { + return SEMAPHORE_THREAD_LOCAL.get(); + } try { synchronized (section) { Unsafe unsafe = ReflectionUtils.getUnsafe(); diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightGetBlocks.java index ca1882d8d..b070e5ed1 100644 --- a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightGetBlocks.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1; import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.configuration.Settings; @@ -75,6 +74,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; @@ -560,7 +560,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (PaperLib.isPaper()) { existingSection.tickingList.clear(); } - DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); + Semaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); synchronized (lock) { // lock.acquire(); @@ -895,7 +895,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc data = new char[4096]; Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); } - DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section); + Semaphore lock = PaperweightPlatformAdapter.applyLock(section); synchronized (lock) { // Efficiently convert ChunkSection to raw data try { diff --git a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightPlatformAdapter.java b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightPlatformAdapter.java index 05426b73c..7a9065305 100644 --- a/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightPlatformAdapter.java +++ b/worldedit-bukkit/adapters/adapter-1_18/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R1/PaperweightPlatformAdapter.java @@ -133,11 +133,20 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); Unsafe unsafe = ReflectionUtils.getUnsafe(); - fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); - fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); + if (!PaperLib.isPaper()) { + fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); + fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); - fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); - fieldLockOffset = unsafe.objectFieldOffset(fieldLock); + fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); + fieldLockOffset = unsafe.objectFieldOffset(fieldLock); + } else { + // in paper, the used methods are synchronized properly + fieldThreadingDetector = null; + fieldThreadingDetectorOffset = -1; + + fieldLock = null; + fieldLockOffset = -1; + } fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName( "gameEventDispatcherSections", "t")); @@ -181,7 +190,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return false; } - static DelegateSemaphore applyLock(LevelChunkSection section) { + private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = ThreadLocal.withInitial(() -> new Semaphore(1)); + + static Semaphore applyLock(LevelChunkSection section) { + if (PaperLib.isPaper()) { + return SEMAPHORE_THREAD_LOCAL.get(); + } try { synchronized (section) { Unsafe unsafe = ReflectionUtils.getUnsafe(); diff --git a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java index 6c381231b..35d08454f 100644 --- a/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java +++ b/worldedit-bukkit/adapters/adapter-1_18_2/src/main/java/com/sk89q/worldedit/bukkit/adapter/impl/fawe/v1_18_R2/PaperweightGetBlocks.java @@ -1,7 +1,6 @@ package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; -import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore; import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.configuration.Settings; @@ -76,6 +75,7 @@ import java.util.Set; import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.Future; +import java.util.concurrent.Semaphore; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Function; @@ -576,7 +576,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc if (PaperLib.isPaper()) { existingSection.tickingList.clear(); } - DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); + Semaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); synchronized (lock) { // lock.acquire(); @@ -914,7 +914,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc data = new char[4096]; Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); } - DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section); + Semaphore lock = PaperweightPlatformAdapter.applyLock(section); synchronized (lock) { // Efficiently convert ChunkSection to raw data try { 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 74c1963f3..e44da5991 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 @@ -132,11 +132,20 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); Unsafe unsafe = ReflectionUtils.getUnsafe(); - fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); - fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); + if (!PaperLib.isPaper()) { + fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); + fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); - fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); - fieldLockOffset = unsafe.objectFieldOffset(fieldLock); + fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); + fieldLockOffset = unsafe.objectFieldOffset(fieldLock); + } else { + // in paper, the used methods are synchronized properly + fieldThreadingDetector = null; + fieldThreadingDetectorOffset = -1; + + fieldLock = null; + fieldLockOffset = -1; + } fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName( "gameEventDispatcherSections", "t")); @@ -180,7 +189,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { return false; } - static DelegateSemaphore applyLock(LevelChunkSection section) { + private static final ThreadLocal SEMAPHORE_THREAD_LOCAL = ThreadLocal.withInitial(() -> new Semaphore(1)); + + static Semaphore applyLock(LevelChunkSection section) { + if (PaperLib.isPaper()) { + return SEMAPHORE_THREAD_LOCAL.get(); + } try { synchronized (section) { Unsafe unsafe = ReflectionUtils.getUnsafe(); @@ -192,7 +206,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter { synchronized (currentThreadingDetector) { Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); if (currentLock instanceof DelegateSemaphore) { - return (DelegateSemaphore) currentLock; + return currentLock; } DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock);