Avoid Unsafe on paper (#1678)

This commit is contained in:
Hannes Greule 2022-03-27 23:56:59 +02:00 committed by GitHub
parent d1588f9207
commit c45b14a52d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 64 additions and 24 deletions

View File

@ -1,7 +1,6 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_17_R1_2;
import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
@ -74,6 +73,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function; 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). //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); PaperweightPlatformAdapter.clearCounts(existingSection);
if (PaperLib.isPaper()) { if (PaperLib.isPaper()) {
existingSection.tickingList.clear(); existingSection.tickingList.clear();
@ -867,7 +867,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
data = new char[4096]; data = new char[4096];
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
} }
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section); Semaphore lock = PaperweightPlatformAdapter.applyLock(section);
synchronized (lock) { synchronized (lock) {
// Efficiently convert ChunkSection to raw data // Efficiently convert ChunkSection to raw data
try { try {

View File

@ -30,6 +30,7 @@ import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer; import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.BitStorage; import net.minecraft.util.BitStorage;
import net.minecraft.util.ThreadingDetector;
import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelAccessor; import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.biome.Biome; import net.minecraft.world.level.biome.Biome;
@ -117,8 +118,15 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent);
Unsafe unsafe = ReflectionUtils.getUnsafe(); Unsafe unsafe = ReflectionUtils.getUnsafe();
fieldLock = PalettedContainer.class.getDeclaredField(Refraction.pickName("lock", "m")); if (!PaperLib.isPaper()) {
fieldLockOffset = unsafe.objectFieldOffset(fieldLock);
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( fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName(
"gameEventDispatcherSections", "x")); "gameEventDispatcherSections", "x"));
@ -162,8 +170,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return false; return false;
} }
static DelegateSemaphore applyLock(LevelChunkSection section) { private static final ThreadLocal<Semaphore> SEMAPHORE_THREAD_LOCAL = ThreadLocal.withInitial(() -> new Semaphore(1));
//todo there has to be a better way to do this. Maybe using a() in DataPaletteBlock which acquires the lock in NMS?
static Semaphore applyLock(LevelChunkSection section) {
if (PaperLib.isPaper()) {
return SEMAPHORE_THREAD_LOCAL.get();
}
try { try {
synchronized (section) { synchronized (section) {
Unsafe unsafe = ReflectionUtils.getUnsafe(); Unsafe unsafe = ReflectionUtils.getUnsafe();

View File

@ -1,7 +1,6 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R1;
import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
@ -75,6 +74,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function; import java.util.function.Function;
@ -560,7 +560,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (PaperLib.isPaper()) { if (PaperLib.isPaper()) {
existingSection.tickingList.clear(); existingSection.tickingList.clear();
} }
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); Semaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
synchronized (lock) { synchronized (lock) {
// lock.acquire(); // lock.acquire();
@ -895,7 +895,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
data = new char[4096]; data = new char[4096];
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
} }
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section); Semaphore lock = PaperweightPlatformAdapter.applyLock(section);
synchronized (lock) { synchronized (lock) {
// Efficiently convert ChunkSection to raw data // Efficiently convert ChunkSection to raw data
try { try {

View File

@ -133,11 +133,20 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent);
Unsafe unsafe = ReflectionUtils.getUnsafe(); Unsafe unsafe = ReflectionUtils.getUnsafe();
fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); if (!PaperLib.isPaper()) {
fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f"));
fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector);
fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c"));
fieldLockOffset = unsafe.objectFieldOffset(fieldLock); 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( fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName(
"gameEventDispatcherSections", "t")); "gameEventDispatcherSections", "t"));
@ -181,7 +190,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return false; return false;
} }
static DelegateSemaphore applyLock(LevelChunkSection section) { private static final ThreadLocal<Semaphore> SEMAPHORE_THREAD_LOCAL = ThreadLocal.withInitial(() -> new Semaphore(1));
static Semaphore applyLock(LevelChunkSection section) {
if (PaperLib.isPaper()) {
return SEMAPHORE_THREAD_LOCAL.get();
}
try { try {
synchronized (section) { synchronized (section) {
Unsafe unsafe = ReflectionUtils.getUnsafe(); Unsafe unsafe = ReflectionUtils.getUnsafe();

View File

@ -1,7 +1,6 @@
package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2; package com.sk89q.worldedit.bukkit.adapter.impl.fawe.v1_18_R2;
import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks; import com.fastasyncworldedit.bukkit.adapter.BukkitGetBlocks;
import com.fastasyncworldedit.bukkit.adapter.DelegateSemaphore;
import com.fastasyncworldedit.core.Fawe; import com.fastasyncworldedit.core.Fawe;
import com.fastasyncworldedit.core.FaweCache; import com.fastasyncworldedit.core.FaweCache;
import com.fastasyncworldedit.core.configuration.Settings; import com.fastasyncworldedit.core.configuration.Settings;
@ -76,6 +75,7 @@ import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function; import java.util.function.Function;
@ -576,7 +576,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
if (PaperLib.isPaper()) { if (PaperLib.isPaper()) {
existingSection.tickingList.clear(); existingSection.tickingList.clear();
} }
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(existingSection); Semaphore lock = PaperweightPlatformAdapter.applyLock(existingSection);
synchronized (lock) { synchronized (lock) {
// lock.acquire(); // lock.acquire();
@ -914,7 +914,7 @@ public class PaperweightGetBlocks extends CharGetBlocks implements BukkitGetBloc
data = new char[4096]; data = new char[4096];
Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR); Arrays.fill(data, (char) BlockTypesCache.ReservedIDs.AIR);
} }
DelegateSemaphore lock = PaperweightPlatformAdapter.applyLock(section); Semaphore lock = PaperweightPlatformAdapter.applyLock(section);
synchronized (lock) { synchronized (lock) {
// Efficiently convert ChunkSection to raw data // Efficiently convert ChunkSection to raw data
try { try {

View File

@ -132,11 +132,20 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent); methodGetVisibleChunk = MethodHandles.lookup().unreflect(getVisibleChunkIfPresent);
Unsafe unsafe = ReflectionUtils.getUnsafe(); Unsafe unsafe = ReflectionUtils.getUnsafe();
fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f")); if (!PaperLib.isPaper()) {
fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector); fieldThreadingDetector = PalettedContainer.class.getDeclaredField(Refraction.pickName("threadingDetector", "f"));
fieldThreadingDetectorOffset = unsafe.objectFieldOffset(fieldThreadingDetector);
fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c")); fieldLock = ThreadingDetector.class.getDeclaredField(Refraction.pickName("lock", "c"));
fieldLockOffset = unsafe.objectFieldOffset(fieldLock); 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( fieldGameEventDispatcherSections = LevelChunk.class.getDeclaredField(Refraction.pickName(
"gameEventDispatcherSections", "t")); "gameEventDispatcherSections", "t"));
@ -180,7 +189,12 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
return false; return false;
} }
static DelegateSemaphore applyLock(LevelChunkSection section) { private static final ThreadLocal<Semaphore> SEMAPHORE_THREAD_LOCAL = ThreadLocal.withInitial(() -> new Semaphore(1));
static Semaphore applyLock(LevelChunkSection section) {
if (PaperLib.isPaper()) {
return SEMAPHORE_THREAD_LOCAL.get();
}
try { try {
synchronized (section) { synchronized (section) {
Unsafe unsafe = ReflectionUtils.getUnsafe(); Unsafe unsafe = ReflectionUtils.getUnsafe();
@ -192,7 +206,7 @@ public final class PaperweightPlatformAdapter extends NMSAdapter {
synchronized (currentThreadingDetector) { synchronized (currentThreadingDetector) {
Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset); Semaphore currentLock = (Semaphore) unsafe.getObject(currentThreadingDetector, fieldLockOffset);
if (currentLock instanceof DelegateSemaphore) { if (currentLock instanceof DelegateSemaphore) {
return (DelegateSemaphore) currentLock; return currentLock;
} }
DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock); DelegateSemaphore newLock = new DelegateSemaphore(1, currentLock);
unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock); unsafe.putObject(currentThreadingDetector, fieldLockOffset, newLock);