From 3f0057fb0535c6d36889db9f9cf767becdec3a8b Mon Sep 17 00:00:00 2001 From: embeddedt <42941056+embeddedt@users.noreply.github.com> Date: Thu, 5 Jun 2025 21:36:12 -0400 Subject: [PATCH] Merge remote-tracking branch 'origin/1.20' into 1.21.1 --- .../perf/dynamic_dfu/DataFixTypesMixin.java | 20 +++++ .../embeddedt/modernfix/dfu/DFUBlaster.java | 88 ++++++++++--------- 2 files changed, 67 insertions(+), 41 deletions(-) create mode 100644 common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_dfu/DataFixTypesMixin.java diff --git a/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_dfu/DataFixTypesMixin.java b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_dfu/DataFixTypesMixin.java new file mode 100644 index 00000000..5a6ab91a --- /dev/null +++ b/common/src/main/java/org/embeddedt/modernfix/common/mixin/perf/dynamic_dfu/DataFixTypesMixin.java @@ -0,0 +1,20 @@ +package org.embeddedt.modernfix.common.mixin.perf.dynamic_dfu; + +import com.mojang.datafixers.DataFixer; +import com.mojang.serialization.Dynamic; +import net.minecraft.util.datafix.DataFixTypes; +import org.embeddedt.modernfix.dfu.DFUBlaster; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(DataFixTypes.class) +public class DataFixTypesMixin { + @Inject(method = "update(Lcom/mojang/datafixers/DataFixer;Lcom/mojang/serialization/Dynamic;II)Lcom/mojang/serialization/Dynamic;", at = @At(value = "INVOKE", target = "Lcom/mojang/datafixers/DataFixer;update(Lcom/mojang/datafixers/DSL$TypeReference;Lcom/mojang/serialization/Dynamic;II)Lcom/mojang/serialization/Dynamic;")) + private void kickOnUpdate(DataFixer fixer, Dynamic input, int version, int newVersion, CallbackInfoReturnable> cir) { + if (version < newVersion) { + DFUBlaster.kick(); + } + } +} diff --git a/common/src/main/java/org/embeddedt/modernfix/dfu/DFUBlaster.java b/common/src/main/java/org/embeddedt/modernfix/dfu/DFUBlaster.java index bd1b0c5f..09da5e76 100644 --- a/common/src/main/java/org/embeddedt/modernfix/dfu/DFUBlaster.java +++ b/common/src/main/java/org/embeddedt/modernfix/dfu/DFUBlaster.java @@ -1,50 +1,51 @@ package org.embeddedt.modernfix.dfu; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.mojang.datafixers.RewriteResult; -import com.mojang.datafixers.TypeRewriteRule; -import com.mojang.datafixers.functions.PointFreeRule; -import com.mojang.datafixers.types.Type; -import com.mojang.datafixers.util.Pair; -import org.apache.commons.lang3.tuple.Triple; import org.embeddedt.modernfix.ModernFix; -import sun.misc.Unsafe; import java.lang.reflect.Field; -import java.util.Optional; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; -import java.util.function.IntFunction; +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.locks.LockSupport; public class DFUBlaster { - private static final Cache>, Integer>, RewriteResult> hmapApplyCache = CacheBuilder.newBuilder() - .expireAfterAccess(3, TimeUnit.MINUTES) - .build(); - private static final Cache, TypeRewriteRule, PointFreeRule>, Optional>> rewriteCache = CacheBuilder.newBuilder() - .expireAfterAccess(3, TimeUnit.MINUTES) - .build(); - public static void blastMaps() { + private static final List> TRACKED_MAPS = buildTrackedMaps(); + private static final long DELAY_TIME = TimeUnit.SECONDS.toNanos(60); + private static final AtomicLong NEXT_WAKE_TIME = new AtomicLong(System.nanoTime() + DELAY_TIME); + + private static List> buildTrackedMaps() { + var list = new ArrayList>(); + tryAdd(list, "com.mojang.datafixers.DSL$Instances", "TAGGED_CHOICE_TYPE_CACHE"); + tryAdd(list, "com.mojang.datafixers.functions.Fold", "HMAP_APPLY_CACHE"); + tryAdd(list, "com.mojang.datafixers.types.Type", "REWRITE_CACHE"); + return list; + } + + private static void tryAdd(List> list, String className, String fieldName) { try { - Class FOLD_CLASS = Class.forName("com.mojang.datafixers.functions.Fold"); - Field hmapField = FOLD_CLASS.getDeclaredField("HMAP_APPLY_CACHE"); - hmapField.setAccessible(true); - final Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); - theUnsafe.setAccessible(true); - Unsafe unsafe = (Unsafe)theUnsafe.get(null); - Object base = unsafe.staticFieldBase(hmapField); - long offset = unsafe.staticFieldOffset(hmapField); - unsafe.putObject(base, offset, hmapApplyCache.asMap()); - Field rewriteCacheField = Type.class.getDeclaredField("REWRITE_CACHE"); - rewriteCacheField.setAccessible(true); - base = unsafe.staticFieldBase(rewriteCacheField); - offset = unsafe.staticFieldOffset(rewriteCacheField); - unsafe.putObject(base, offset, rewriteCache.asMap()); - new CleanerThread().start(); - } catch(Throwable e) { - ModernFix.LOGGER.error("Could not replace DFU map", e); + Class clz = Class.forName(className); + Field field = clz.getDeclaredField(fieldName); + field.setAccessible(true); + if (Map.class.isAssignableFrom(field.getType())) { + list.add((Map)field.get(null)); + } else { + ModernFix.LOGGER.error("Field {} on class {} is not a map", field, className); + } + } catch (ReflectiveOperationException e) { + ModernFix.LOGGER.error("Error tracking DFU field {} on class {}", fieldName, className, e); } } + public static void blastMaps() { + new CleanerThread().start(); + } + + public static void kick() { + NEXT_WAKE_TIME.getAndAdd(DELAY_TIME); + } + static class CleanerThread extends Thread { CleanerThread() { this.setName("DFU cleaning thread"); @@ -55,13 +56,18 @@ public class DFUBlaster { @Override public void run() { while(true) { - try { - Thread.sleep(15000); - } catch(InterruptedException e){ - return; + long waitTime = NEXT_WAKE_TIME.get() - System.nanoTime(); + if (waitTime > 0) { + LockSupport.parkNanos(waitTime); } - rewriteCache.cleanUp(); - hmapApplyCache.cleanUp(); + + long lastStamp = NEXT_WAKE_TIME.get(); + if (System.nanoTime() >= lastStamp) { + // Nobody kicked the watchdog again, we should clear the maps + TRACKED_MAPS.forEach(Map::clear); + NEXT_WAKE_TIME.compareAndSet(lastStamp, System.nanoTime() + DELAY_TIME); + } + // Otherwise, we were told to wait for longer, so don't do anything } } }