From edb695900950f069405083fd2df321063f481267 Mon Sep 17 00:00:00 2001
From: Matyrobbrt <65940752+Matyrobbrt@users.noreply.github.com>
Date: Thu, 14 Dec 2023 18:01:43 +0200
Subject: [PATCH] Get rid of CapabilityTokenSubclass and ObjectHolderDefinalize
(#53)
---
.../common/asm/CapabilityTokenSubclass.java | 120 ------------------
.../common/asm/ObjectHolderDefinalize.java | 110 ----------------
.../asm}/RuntimeDistCleaner.java | 2 +-
.../net/neoforged/fml/loading/FMLLoader.java | 2 +-
...odlauncher.serviceapi.ILaunchPluginService | 6 +-
5 files changed, 4 insertions(+), 236 deletions(-)
delete mode 100644 loader/src/main/java/net/neoforged/fml/common/asm/CapabilityTokenSubclass.java
delete mode 100644 loader/src/main/java/net/neoforged/fml/common/asm/ObjectHolderDefinalize.java
rename loader/src/main/java/net/neoforged/fml/{loading => common/asm}/RuntimeDistCleaner.java (99%)
diff --git a/loader/src/main/java/net/neoforged/fml/common/asm/CapabilityTokenSubclass.java b/loader/src/main/java/net/neoforged/fml/common/asm/CapabilityTokenSubclass.java
deleted file mode 100644
index 376951eb1..000000000
--- a/loader/src/main/java/net/neoforged/fml/common/asm/CapabilityTokenSubclass.java
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (c) Forge Development LLC and contributors
- * SPDX-License-Identifier: LGPL-2.1-only
- */
-
-package net.neoforged.fml.common.asm;
-
-import java.util.ArrayDeque;
-import java.util.Deque;
-import java.util.EnumSet;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-import org.objectweb.asm.signature.SignatureReader;
-import org.objectweb.asm.signature.SignatureVisitor;
-import org.objectweb.asm.tree.ClassNode;
-import org.objectweb.asm.tree.MethodNode;
-
-import cpw.mods.modlauncher.serviceapi.ILaunchPluginService;
-
-/**
- * Implements getType() in CapabilityToken subclasses.
- *
- * Using the class's signature to determine the generic type of TypeToken, and then implements getType() using that value.
- *
- * Example:
- *
- * new CapabilityToken<String>(){}
- * Has the signature "CapabilityToken<Ljava/lang/String;>"
- *
- * Implements the method:
- * public String getType() {
- * return "java/lang/String";
- * }
- *
- */
-public class CapabilityTokenSubclass implements ILaunchPluginService {
-
- private final String FUNC_NAME = "getType";
- private final String FUNC_DESC = "()Ljava/lang/String;";
- private final String CAP_INJECT = "net/neoforged/neoforge/common/capabilities/CapabilityToken"; //Don't directly reference this to prevent class loading.
-
- @Override
- public String name() {
- return "capability_token_subclass";
- }
-
- private static final EnumSet YAY = EnumSet.of(Phase.AFTER);
- private static final EnumSet NAY = EnumSet.noneOf(Phase.class);
-
- @Override
- public EnumSet handlesClass(Type classType, boolean isEmpty)
- {
- return isEmpty ? NAY : YAY;
- }
-
- @Override
- public int processClassWithFlags(final Phase phase, final ClassNode classNode, final Type classType, final String reason)
- {
- if (CAP_INJECT.equals(classNode.name))
- {
- for (MethodNode mtd : classNode.methods)
- {
- if (FUNC_NAME.equals(mtd.name) && FUNC_DESC.equals(mtd.desc))
- {
- mtd.access &= ~Opcodes.ACC_FINAL; // We have it final in code so people don't override it, cuz that'd be stupid, and make our transformer more complicated.
- }
- }
- return ComputeFlags.SIMPLE_REWRITE;
- }
- else if (CAP_INJECT.equals(classNode.superName))
- {
- Holder cls = new Holder();
-
- SignatureReader reader = new SignatureReader(classNode.signature); // Having a node version of this would probably be useful.
- reader.accept(new SignatureVisitor(Opcodes.ASM9)
- {
- Deque stack = new ArrayDeque<>();
-
- @Override
- public void visitClassType(final String name)
- {
- stack.push(name);
- }
-
- @Override
- public void visitInnerClassType(final String name)
- {
- stack.push(stack.pop() + '$' + name);
- }
-
- @Override
- public void visitEnd()
- {
- var val = stack.pop();
- if (!stack.isEmpty() && CAP_INJECT.equals(stack.peek()))
- cls.value = val;
- }
- });
-
- if (cls.value == null)
- throw new IllegalStateException("Could not find signature for CapabilityToken on " + classNode.name + " from " + classNode.signature);
-
- var mtd = classNode.visitMethod(Opcodes.ACC_PUBLIC, FUNC_NAME, FUNC_DESC, null, new String[0]);
- mtd.visitLdcInsn(cls.value);
- mtd.visitInsn(Opcodes.ARETURN);
- mtd.visitEnd();
- return ComputeFlags.COMPUTE_MAXS;
- }
- else
- {
- return ComputeFlags.NO_REWRITE;
- }
- }
-
- private static class Holder {
- String value;
- }
-
-}
diff --git a/loader/src/main/java/net/neoforged/fml/common/asm/ObjectHolderDefinalize.java b/loader/src/main/java/net/neoforged/fml/common/asm/ObjectHolderDefinalize.java
deleted file mode 100644
index 6fdc5e391..000000000
--- a/loader/src/main/java/net/neoforged/fml/common/asm/ObjectHolderDefinalize.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) Forge Development LLC and contributors
- * SPDX-License-Identifier: LGPL-2.1-only
- */
-
-package net.neoforged.fml.common.asm;
-
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
-
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-import org.objectweb.asm.tree.AnnotationNode;
-import org.objectweb.asm.tree.ClassNode;
-import cpw.mods.modlauncher.serviceapi.ILaunchPluginService;
-
-/**
- * Removes the final modifier from fields with the @ObjectHolder annotation, prevents the JITer from in lining them so our runtime replacements can work.
- * Will also de-finalize all fields in on class level annotations.
- */
-public class ObjectHolderDefinalize implements ILaunchPluginService {
- // Hardcoded map of vanilla classes that should have object holders for each field of the given registry type.
- // IMPORTANT: Updates to this collection must be reflected in ObjectHolderRegistry. Duplicated cuz classloaders, yay!
- // Classnames are validated in ObjectHolderRegistry.
- private static final Map VANILLA_OBJECT_HOLDERS = Stream.of(
- new VanillaObjectHolderData("net.minecraft.world.level.block.Blocks", "block", "net.minecraft.world.level.block.Block"),
- new VanillaObjectHolderData("net.minecraft.world.item.Items", "item", "net.minecraft.world.item.Item"),
- new VanillaObjectHolderData("net.minecraft.world.item.enchantment.Enchantments", "enchantment", "net.minecraft.world.item.enchantment.Enchantment"),
- new VanillaObjectHolderData("net.minecraft.world.effect.MobEffects", "mob_effect", "net.minecraft.world.effect.MobEffect"),
- new VanillaObjectHolderData("net.minecraft.core.particles.ParticleTypes", "particle_type", "net.minecraft.core.particles.ParticleType"),
- new VanillaObjectHolderData("net.minecraft.sounds.SoundEvents", "sound_event", "net.minecraft.sounds.SoundEvent")
- ).collect(Collectors.toMap(VanillaObjectHolderData::holderClass, Function.identity()));
- private final String OBJECT_HOLDER = "Lnet/neoforged/neoforge/registries/ObjectHolder;"; //Don't directly reference this to prevent class loading.
-
- @Override
- public String name() {
- return "object_holder_definalize";
- }
-
- private static final EnumSet YAY = EnumSet.of(Phase.AFTER);
- private static final EnumSet NAY = EnumSet.noneOf(Phase.class);
-
- @Override
- public EnumSet handlesClass(Type classType, boolean isEmpty)
- {
- return isEmpty ? NAY : YAY;
- }
-
- private boolean hasHolder(List lst)
- {
- return lst != null && lst.stream().anyMatch(n -> n.desc.equals(OBJECT_HOLDER));
- }
-
- private String getValue(List lst)
- {
- AnnotationNode ann = lst.stream().filter(n -> n.desc.equals(OBJECT_HOLDER)).findFirst().get();
- if (ann.values != null)
- {
- for (int x = 0; x < ann.values.size() - 1; x += 2) {
- if (ann.values.get(x).equals("value")) {
- return (String)ann.values.get(x + 1);
- }
- }
- }
- return null;
- }
-
- @Override
- public int processClassWithFlags(final Phase phase, final ClassNode classNode, final Type classType, final String reason)
- {
- final AtomicBoolean changes = new AtomicBoolean();
- //Must be public static finals, and non-array objects
- final int flags = Opcodes.ACC_PUBLIC | Opcodes.ACC_STATIC | Opcodes.ACC_FINAL;
-
- //Fix Annotated Fields before injecting from class level
- classNode.fields.stream().filter(f -> ((f.access & flags) == flags) && f.desc.startsWith("L") && hasHolder(f.visibleAnnotations)).forEach(f ->
- {
- int prev = f.access;
- f.access &= ~Opcodes.ACC_FINAL; //Strip final
- f.access |= Opcodes.ACC_SYNTHETIC; //Add Synthetic so we can check in runtime. ? Good idea?
- changes.compareAndSet(false, prev != f.access);
- });
-
- if (VANILLA_OBJECT_HOLDERS.containsKey(classType.getClassName())) //Class level, de-finalize all fields and add @ObjectHolder to them!
- {
- classNode.fields.stream().filter(f -> ((f.access & flags) == flags) && f.desc.startsWith("L")).forEach(f ->
- {
- int prev = f.access;
- f.access &= ~Opcodes.ACC_FINAL;
- f.access |= Opcodes.ACC_SYNTHETIC;
- /*if (!hasHolder(f.visibleAnnotations)) //Add field level annotation, doesn't do anything until after we figure out how ASMDataTable is gatherered
- {
- if (value == null)
- f.visitAnnotation(OBJECT_HOLDER, true);
- else
- f.visitAnnotation(OBJECT_HOLDER, true).visit("value", value + ":" + f.name.toLowerCase());
- }*/
- changes.compareAndSet(false, prev != f.access);
- });
- }
- return changes.get() ? ComputeFlags.SIMPLE_REWRITE : ComputeFlags.NO_REWRITE;
- }
-
- private record VanillaObjectHolderData(String holderClass, String registryName, String registryType) {}
-}
diff --git a/loader/src/main/java/net/neoforged/fml/loading/RuntimeDistCleaner.java b/loader/src/main/java/net/neoforged/fml/common/asm/RuntimeDistCleaner.java
similarity index 99%
rename from loader/src/main/java/net/neoforged/fml/loading/RuntimeDistCleaner.java
rename to loader/src/main/java/net/neoforged/fml/common/asm/RuntimeDistCleaner.java
index 22146883c..7fef92a35 100644
--- a/loader/src/main/java/net/neoforged/fml/loading/RuntimeDistCleaner.java
+++ b/loader/src/main/java/net/neoforged/fml/common/asm/RuntimeDistCleaner.java
@@ -3,7 +3,7 @@
* SPDX-License-Identifier: LGPL-2.1-only
*/
-package net.neoforged.fml.loading;
+package net.neoforged.fml.common.asm;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/loader/src/main/java/net/neoforged/fml/loading/FMLLoader.java b/loader/src/main/java/net/neoforged/fml/loading/FMLLoader.java
index 9e86b7dd0..a1efb7d2e 100644
--- a/loader/src/main/java/net/neoforged/fml/loading/FMLLoader.java
+++ b/loader/src/main/java/net/neoforged/fml/loading/FMLLoader.java
@@ -11,6 +11,7 @@
import cpw.mods.modlauncher.util.ServiceLoaderUtils;
import net.neoforged.accesstransformer.api.AccessTransformerEngine;
import net.neoforged.accesstransformer.ml.AccessTransformerService;
+import net.neoforged.fml.common.asm.RuntimeDistCleaner;
import net.neoforged.fml.loading.mixin.DeferredMixinConfigRegistration;
import net.neoforged.fml.loading.moddiscovery.BackgroundScanHandler;
import net.neoforged.fml.loading.moddiscovery.ModDiscoverer;
@@ -20,7 +21,6 @@
import net.neoforged.fml.loading.targets.CommonLaunchHandler;
import net.neoforged.neoforgespi.Environment;
import net.neoforged.neoforgespi.coremod.ICoreModProvider;
-import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import java.io.IOException;
diff --git a/loader/src/main/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService b/loader/src/main/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService
index 22f91d676..580f7de7c 100644
--- a/loader/src/main/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService
+++ b/loader/src/main/resources/META-INF/services/cpw.mods.modlauncher.serviceapi.ILaunchPluginService
@@ -1,5 +1,3 @@
net.neoforged.fml.loading.log4j.SLF4JFixerLaunchPluginService
-net.neoforged.fml.loading.RuntimeDistCleaner
-net.neoforged.fml.common.asm.RuntimeEnumExtender
-net.neoforged.fml.common.asm.ObjectHolderDefinalize
-net.neoforged.fml.common.asm.CapabilityTokenSubclass
\ No newline at end of file
+net.neoforged.fml.common.asm.RuntimeDistCleaner
+net.neoforged.fml.common.asm.RuntimeEnumExtender
\ No newline at end of file