Improve class transformer cache
This commit is contained in:
parent
95d7410722
commit
23b4652864
|
|
@ -4,8 +4,12 @@ import java.io.*;
|
||||||
import java.lang.reflect.Array;
|
import java.lang.reflect.Array;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.security.MessageDigest;
|
||||||
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.ForkJoinPool;
|
import java.util.concurrent.ForkJoinPool;
|
||||||
|
|
||||||
import cpw.mods.modlauncher.api.ITransformer;
|
import cpw.mods.modlauncher.api.ITransformer;
|
||||||
|
|
@ -44,6 +48,14 @@ public class ModernFixCachingClassTransformer extends ClassTransformer {
|
||||||
|
|
||||||
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
|
public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];
|
||||||
|
|
||||||
|
public static ThreadLocal<MessageDigest> systemHasher = ThreadLocal.withInitial(() -> {
|
||||||
|
try {
|
||||||
|
return MessageDigest.getInstance("SHA-256");
|
||||||
|
} catch(NoSuchAlgorithmException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
private static File childFile(File file) {
|
private static File childFile(File file) {
|
||||||
file.getParentFile().mkdirs();
|
file.getParentFile().mkdirs();
|
||||||
return file;
|
return file;
|
||||||
|
|
@ -82,12 +94,12 @@ public class ModernFixCachingClassTransformer extends ClassTransformer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private ArrayList<byte[]> computeHash(String className, boolean isEmpty, String reason) {
|
private ArrayList<byte[]> computeHash(String className, byte[] inputClass, String reason) {
|
||||||
final String internalName = className.replace('.', '/');
|
final String internalName = className.replace('.', '/');
|
||||||
final Type classDesc = Type.getObjectType(internalName);
|
final Type classDesc = Type.getObjectType(internalName);
|
||||||
ArrayList<ILaunchPluginService> pluginList = new ArrayList<>();
|
ArrayList<ILaunchPluginService> pluginList = new ArrayList<>();
|
||||||
for(ILaunchPluginService plugin : plugins.values()) {
|
for(ILaunchPluginService plugin : plugins.values()) {
|
||||||
if(!plugin.handlesClass(classDesc, isEmpty, reason).isEmpty()) {
|
if(!plugin.handlesClass(classDesc, inputClass.length == 0, reason).isEmpty()) {
|
||||||
pluginList.add(plugin);
|
pluginList.add(plugin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -117,6 +129,10 @@ public class ModernFixCachingClassTransformer extends ClassTransformer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* Hash the class itself last, so that we bail out early if plugins can't hash */
|
||||||
|
MessageDigest hasher = systemHasher.get();
|
||||||
|
hasher.reset();
|
||||||
|
hashList.add(hasher.digest(inputClass));
|
||||||
return hashList;
|
return hashList;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -132,42 +148,52 @@ public class ModernFixCachingClassTransformer extends ClassTransformer {
|
||||||
public byte[] transform(byte[] inputClass, String className, String reason) {
|
public byte[] transform(byte[] inputClass, String className, String reason) {
|
||||||
/* We only want to cache actual transformations */
|
/* We only want to cache actual transformations */
|
||||||
if(ITransformerActivity.CLASSLOADING_REASON.equals(reason)) {
|
if(ITransformerActivity.CLASSLOADING_REASON.equals(reason)) {
|
||||||
ArrayList<byte[]> hashList = computeHash(className, inputClass.length == 0, reason);
|
final byte[] classToHash = inputClass;
|
||||||
if(hashList != null) {
|
CompletableFuture<ArrayList<byte[]>> futureHashList = CompletableFuture.supplyAsync(() -> computeHash(className, classToHash, reason), ForkJoinPool.commonPool());
|
||||||
/* Check if the cache contains a transformed class matching these hashes */
|
ArrayList<byte[]> hashList = null;
|
||||||
/* TODO maybe sanitize the class name? */
|
/* Check if the cache contains a transformed class matching these hashes */
|
||||||
File cacheLocation = new File(CLASS_CACHE_FOLDER, className.replace('.', '/'));
|
/* TODO maybe sanitize the class name? */
|
||||||
boolean hashesMatch = true;
|
File cacheLocation = new File(CLASS_CACHE_FOLDER, className.replace('.', '/'));
|
||||||
try(ObjectInputStream stream = new ObjectInputStream(new FileInputStream(cacheLocation))) {
|
boolean hashesMatch = true;
|
||||||
ArrayList<byte[]> savedHash = (ArrayList<byte[]>)stream.readObject();
|
try(ObjectInputStream stream = new ObjectInputStream(new FileInputStream(cacheLocation))) {
|
||||||
|
ArrayList<byte[]> savedHash = (ArrayList<byte[]>)stream.readObject();
|
||||||
|
byte[] savedInputClass = (byte[])stream.readObject();
|
||||||
|
hashList = futureHashList.get();
|
||||||
|
if(hashList != null) {
|
||||||
for(int i = 0; i < savedHash.size(); i++) {
|
for(int i = 0; i < savedHash.size(); i++) {
|
||||||
if(!Arrays.equals(savedHash.get(i), hashList.get(i))) {
|
if(!Arrays.equals(savedHash.get(i), hashList.get(i))) {
|
||||||
hashesMatch = false;
|
hashesMatch = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(hashesMatch)
|
} else
|
||||||
inputClass = (byte[])stream.readObject();
|
|
||||||
} catch(IOException | ClassNotFoundException | ClassCastException e) {
|
|
||||||
if(!(e instanceof FileNotFoundException))
|
|
||||||
e.printStackTrace();
|
|
||||||
hashesMatch = false;
|
hashesMatch = false;
|
||||||
}
|
if(hashesMatch)
|
||||||
if(!hashesMatch) {
|
inputClass = savedInputClass;
|
||||||
inputClass = super.transform(inputClass, className, reason);
|
} catch(IOException | ClassNotFoundException | ClassCastException | InterruptedException |
|
||||||
|
ExecutionException e) {
|
||||||
|
if(!(e instanceof FileNotFoundException))
|
||||||
|
e.printStackTrace();
|
||||||
|
hashesMatch = false;
|
||||||
|
}
|
||||||
|
if(!hashesMatch) {
|
||||||
|
inputClass = super.transform(inputClass, className, reason);
|
||||||
|
if(hashList != null) {
|
||||||
final byte[] classToSave = inputClass;
|
final byte[] classToSave = inputClass;
|
||||||
|
final ArrayList<byte[]> hashListToSave = hashList;
|
||||||
classSaverPool.submit(() -> {
|
classSaverPool.submit(() -> {
|
||||||
cacheLocation.getParentFile().mkdirs();
|
cacheLocation.getParentFile().mkdirs();
|
||||||
try(ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(cacheLocation))) {
|
try(ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(cacheLocation))) {
|
||||||
stream.writeObject(hashList);
|
stream.writeObject(hashListToSave);
|
||||||
stream.writeObject(classToSave);
|
stream.writeObject(classToSave);
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return inputClass;
|
|
||||||
}
|
}
|
||||||
|
return inputClass;
|
||||||
}
|
}
|
||||||
return super.transform(inputClass, className, reason);
|
return super.transform(inputClass, className, reason);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
package org.embeddedt.modernfix.classloading.hashers;
|
package org.embeddedt.modernfix.classloading.hashers;
|
||||||
|
|
||||||
|
import cpw.mods.modlauncher.ModernFixCachingClassTransformer;
|
||||||
import net.minecraftforge.coremod.CoreMod;
|
import net.minecraftforge.coremod.CoreMod;
|
||||||
import net.minecraftforge.coremod.transformer.CoreModBaseTransformer;
|
import net.minecraftforge.coremod.transformer.CoreModBaseTransformer;
|
||||||
|
|
||||||
|
|
@ -13,13 +14,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
public class CoreModTransformerHasher {
|
public class CoreModTransformerHasher {
|
||||||
private static final ConcurrentHashMap<CoreMod, byte[]> hashForCoremod;
|
private static final ConcurrentHashMap<CoreMod, byte[]> hashForCoremod;
|
||||||
private static Field coremodField;
|
private static Field coremodField;
|
||||||
private static ThreadLocal<MessageDigest> coremodHasher = ThreadLocal.withInitial(() -> {
|
|
||||||
try {
|
|
||||||
return MessageDigest.getInstance("SHA-256");
|
|
||||||
} catch(NoSuchAlgorithmException e) {
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
static {
|
static {
|
||||||
hashForCoremod = new ConcurrentHashMap<>();
|
hashForCoremod = new ConcurrentHashMap<>();
|
||||||
|
|
@ -38,10 +32,9 @@ public class CoreModTransformerHasher {
|
||||||
} catch(IOException e) {
|
} catch(IOException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
MessageDigest hasher = coremodHasher.get();
|
MessageDigest hasher = ModernFixCachingClassTransformer.systemHasher.get();
|
||||||
byte[] hash = hasher.digest(coreModContents);
|
|
||||||
hasher.reset();
|
hasher.reset();
|
||||||
return hash;
|
return hasher.digest(coreModContents);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static byte[] obtainHash(CoreModBaseTransformer<?> transformer) {
|
public static byte[] obtainHash(CoreModBaseTransformer<?> transformer) {
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
package org.embeddedt.modernfix.classloading.hashers;
|
package org.embeddedt.modernfix.classloading.hashers;
|
||||||
|
|
||||||
import com.google.common.collect.HashMultimap;
|
|
||||||
import com.google.common.io.Resources;
|
import com.google.common.io.Resources;
|
||||||
import cpw.mods.modlauncher.ModernFixCachingClassTransformer;
|
import cpw.mods.modlauncher.ModernFixCachingClassTransformer;
|
||||||
import org.spongepowered.asm.launch.IClassProcessor;
|
import org.spongepowered.asm.launch.IClassProcessor;
|
||||||
import org.spongepowered.asm.launch.MixinLaunchPluginLegacy;
|
import org.spongepowered.asm.launch.MixinLaunchPluginLegacy;
|
||||||
|
import org.spongepowered.asm.mixin.MixinEnvironment;
|
||||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||||
import org.spongepowered.asm.service.MixinService;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
@ -19,6 +18,10 @@ public class MixinTransformerHasher {
|
||||||
private static HashMap<String, byte[]> hashesByClass = null;
|
private static HashMap<String, byte[]> hashesByClass = null;
|
||||||
private final static MessageDigest hasher;
|
private final static MessageDigest hasher;
|
||||||
|
|
||||||
|
private static Field processorsListField, transformerField, processorField, environmentField;
|
||||||
|
|
||||||
|
private static final byte[] NO_MIXINS = new byte[] {(byte)0xde, (byte)0xad, (byte)0xbe, (byte)0xef};
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
hasher = MessageDigest.getInstance("SHA-256");
|
hasher = MessageDigest.getInstance("SHA-256");
|
||||||
|
|
@ -31,12 +34,12 @@ public class MixinTransformerHasher {
|
||||||
/* FIXME runs too early right now, and therefore doesn't pick up the list of mixins correctly */
|
/* FIXME runs too early right now, and therefore doesn't pick up the list of mixins correctly */
|
||||||
synchronized (MixinTransformerHasher.class) {
|
synchronized (MixinTransformerHasher.class) {
|
||||||
if(hashesByClass == null) {
|
if(hashesByClass == null) {
|
||||||
hashesByClass = new HashMap<>();
|
|
||||||
HashMap<String, ArrayList<IMixinInfo>> mixinsByClass = new HashMap<>();
|
|
||||||
try {
|
try {
|
||||||
Field processorsField = MixinLaunchPluginLegacy.class.getDeclaredField("processors");
|
if(processorsListField == null) {
|
||||||
processorsField.setAccessible(true);
|
processorsListField = MixinLaunchPluginLegacy.class.getDeclaredField("processors");
|
||||||
List<IClassProcessor> processors = (List<IClassProcessor>)processorsField.get(plugin);
|
processorsListField.setAccessible(true);
|
||||||
|
}
|
||||||
|
List<IClassProcessor> processors = (List<IClassProcessor>) processorsListField.get(plugin);
|
||||||
Object transformHandler = null;
|
Object transformHandler = null;
|
||||||
for(IClassProcessor processor : processors) {
|
for(IClassProcessor processor : processors) {
|
||||||
if(processor.getClass().getName().equals("org.spongepowered.asm.service.modlauncher.MixinTransformationHandler")) {
|
if(processor.getClass().getName().equals("org.spongepowered.asm.service.modlauncher.MixinTransformationHandler")) {
|
||||||
|
|
@ -46,12 +49,24 @@ public class MixinTransformerHasher {
|
||||||
}
|
}
|
||||||
if(transformHandler == null)
|
if(transformHandler == null)
|
||||||
throw new IllegalStateException("Mixin transform handler not found");
|
throw new IllegalStateException("Mixin transform handler not found");
|
||||||
Field transformerField = transformHandler.getClass().getDeclaredField("transformer");
|
if(transformerField == null) {
|
||||||
transformerField.setAccessible(true);
|
transformerField = transformHandler.getClass().getDeclaredField("transformer");
|
||||||
|
transformerField.setAccessible(true);
|
||||||
|
}
|
||||||
Object transformer = transformerField.get(transformHandler);
|
Object transformer = transformerField.get(transformHandler);
|
||||||
Field processorField = transformer.getClass().getDeclaredField("processor");
|
if(processorField == null) {
|
||||||
processorField.setAccessible(true);
|
processorField = transformer.getClass().getDeclaredField("processor");
|
||||||
|
processorField.setAccessible(true);
|
||||||
|
}
|
||||||
Object processor = processorField.get(transformer);
|
Object processor = processorField.get(transformer);
|
||||||
|
if(environmentField == null) {
|
||||||
|
environmentField = processor.getClass().getDeclaredField("currentEnvironment");
|
||||||
|
environmentField.setAccessible(true);
|
||||||
|
}
|
||||||
|
MixinEnvironment currentEnv = (MixinEnvironment)environmentField.get(processor);
|
||||||
|
if(currentEnv == null || currentEnv.getPhase() != MixinEnvironment.Phase.DEFAULT) {
|
||||||
|
return null; /* no hash obtained until mixin is ready */
|
||||||
|
}
|
||||||
Field configsField = processor.getClass().getDeclaredField("configs");
|
Field configsField = processor.getClass().getDeclaredField("configs");
|
||||||
configsField.setAccessible(true);
|
configsField.setAccessible(true);
|
||||||
List<?> configs = (List<?>)configsField.get(processor);
|
List<?> configs = (List<?>)configsField.get(processor);
|
||||||
|
|
@ -60,6 +75,7 @@ public class MixinTransformerHasher {
|
||||||
/* getTargetClasses can't be used because it's package-private */
|
/* getTargetClasses can't be used because it's package-private */
|
||||||
Field classNamesField = Class.forName("org.spongepowered.asm.mixin.transformer.MixinInfo").getDeclaredField("targetClassNames");
|
Field classNamesField = Class.forName("org.spongepowered.asm.mixin.transformer.MixinInfo").getDeclaredField("targetClassNames");
|
||||||
classNamesField.setAccessible(true);
|
classNamesField.setAccessible(true);
|
||||||
|
HashMap<String, ArrayList<IMixinInfo>> mixinsByClass = new HashMap<>();
|
||||||
for(Object config : configs) {
|
for(Object config : configs) {
|
||||||
List<? extends IMixinInfo> mixins = (List<? extends IMixinInfo>)mixinsField.get(config);
|
List<? extends IMixinInfo> mixins = (List<? extends IMixinInfo>)mixinsField.get(config);
|
||||||
for(IMixinInfo mixin : mixins) {
|
for(IMixinInfo mixin : mixins) {
|
||||||
|
|
@ -73,6 +89,7 @@ public class MixinTransformerHasher {
|
||||||
infos.sort((info1, info2) -> Comparator.<String>naturalOrder().compare(info1.getClassName(), info2.getClassName()));
|
infos.sort((info1, info2) -> Comparator.<String>naturalOrder().compare(info1.getClassName(), info2.getClassName()));
|
||||||
}
|
}
|
||||||
/* Now go through each class name and hash it */
|
/* Now go through each class name and hash it */
|
||||||
|
HashMap<String, byte[]> hashesByClassInit = new HashMap<>();
|
||||||
for(Map.Entry<String, ArrayList<IMixinInfo>> mixinsForClass : mixinsByClass.entrySet()) {
|
for(Map.Entry<String, ArrayList<IMixinInfo>> mixinsForClass : mixinsByClass.entrySet()) {
|
||||||
hasher.reset();
|
hasher.reset();
|
||||||
for(IMixinInfo mixin : mixinsForClass.getValue()) {
|
for(IMixinInfo mixin : mixinsForClass.getValue()) {
|
||||||
|
|
@ -87,13 +104,14 @@ public class MixinTransformerHasher {
|
||||||
}
|
}
|
||||||
hasher.update(bytecode);
|
hasher.update(bytecode);
|
||||||
}
|
}
|
||||||
hashesByClass.put(mixinsForClass.getKey().replace('/', '.'), hasher.digest());
|
hashesByClassInit.put(mixinsForClass.getKey().replace('/', '.'), hasher.digest());
|
||||||
}
|
}
|
||||||
|
hashesByClass = hashesByClassInit;
|
||||||
} catch(ReflectiveOperationException e) {
|
} catch(ReflectiveOperationException e) {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hashesByClass.getOrDefault(className, ModernFixCachingClassTransformer.EMPTY_BYTE_ARRAY);
|
return hashesByClass.getOrDefault(className, NO_MIXINS);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,23 +59,6 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin {
|
||||||
throw new IllegalStateException("Expected a TransformingClassLoader");
|
throw new IllegalStateException("Expected a TransformingClassLoader");
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if(isOptionEnabled("launch.transformer_cache.ModernFixClassTransformer")) {
|
|
||||||
Field classTransformerField = TransformingClassLoader.class.getDeclaredField("classTransformer");
|
|
||||||
classTransformerField.setAccessible(true);
|
|
||||||
ClassTransformer t = (ClassTransformer)classTransformerField.get(loader);
|
|
||||||
TransformStore store = ObfuscationReflectionHelper.getPrivateValue(ClassTransformer.class, t, "transformers");
|
|
||||||
LaunchPluginHandler pluginHandler = ObfuscationReflectionHelper.getPrivateValue(ClassTransformer.class, t, "pluginHandler");
|
|
||||||
TransformerAuditTrail trail = ObfuscationReflectionHelper.getPrivateValue(ClassTransformer.class, t, "auditTrail");
|
|
||||||
injectClassIntoSystemLoader("org.embeddedt.modernfix.classloading.api.IHashableTransformer");
|
|
||||||
injectClassIntoSystemLoader("org.embeddedt.modernfix.classloading.hashers.CoreModTransformerHasher");
|
|
||||||
injectClassIntoSystemLoader("org.embeddedt.modernfix.classloading.hashers.MixinTransformerHasher");
|
|
||||||
Class<?> newTransformerClass = injectClassIntoSystemLoader("cpw.mods.modlauncher.ModernFixCachingClassTransformer");
|
|
||||||
Constructor<?> constructor = newTransformerClass.getConstructor(TransformStore.class, LaunchPluginHandler.class, TransformingClassLoader.class, TransformerAuditTrail.class);
|
|
||||||
ClassTransformer newTransformer = (ClassTransformer)constructor.newInstance(store, pluginHandler, loader, trail);
|
|
||||||
classTransformerField.set(loader, newTransformer);
|
|
||||||
|
|
||||||
logger.info("Successfully injected caching transformer");
|
|
||||||
}
|
|
||||||
if(isOptionEnabled("launch.class_search_cache.ModernFixResourceFinder")) {
|
if(isOptionEnabled("launch.class_search_cache.ModernFixResourceFinder")) {
|
||||||
Field resourceFinderField = TransformingClassLoader.class.getDeclaredField("resourceFinder");
|
Field resourceFinderField = TransformingClassLoader.class.getDeclaredField("resourceFinder");
|
||||||
/* Construct a new list of resource finders, using similar logic to ML */
|
/* Construct a new list of resource finders, using similar logic to ML */
|
||||||
|
|
@ -88,7 +71,7 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin {
|
||||||
resourceFinder = EnumerationHelper.mergeFunctors(resourceFinder, LamdbaExceptionUtils.rethrowFunction(dcl::findResources));
|
resourceFinder = EnumerationHelper.mergeFunctors(resourceFinder, LamdbaExceptionUtils.rethrowFunction(dcl::findResources));
|
||||||
resourceFinderField.set(loader, resourceFinder);
|
resourceFinderField.set(loader, resourceFinder);
|
||||||
}
|
}
|
||||||
} catch(RuntimeException | ReflectiveOperationException | IOException e) {
|
} catch(RuntimeException | ReflectiveOperationException e) {
|
||||||
logger.error("Failed to make classloading changes", e);
|
logger.error("Failed to make classloading changes", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -127,7 +110,28 @@ public class ModernFixMixinPlugin implements IMixinConfigPlugin {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoad(String mixinPackage) {
|
public void onLoad(String mixinPackage) {
|
||||||
|
try {
|
||||||
|
if(isOptionEnabled("launch.transformer_cache.ModernFixClassTransformer")) {
|
||||||
|
ClassLoader loader = Thread.currentThread().getContextClassLoader();
|
||||||
|
Field classTransformerField = TransformingClassLoader.class.getDeclaredField("classTransformer");
|
||||||
|
classTransformerField.setAccessible(true);
|
||||||
|
ClassTransformer t = (ClassTransformer)classTransformerField.get(loader);
|
||||||
|
TransformStore store = ObfuscationReflectionHelper.getPrivateValue(ClassTransformer.class, t, "transformers");
|
||||||
|
LaunchPluginHandler pluginHandler = ObfuscationReflectionHelper.getPrivateValue(ClassTransformer.class, t, "pluginHandler");
|
||||||
|
TransformerAuditTrail trail = ObfuscationReflectionHelper.getPrivateValue(ClassTransformer.class, t, "auditTrail");
|
||||||
|
injectClassIntoSystemLoader("org.embeddedt.modernfix.classloading.api.IHashableTransformer");
|
||||||
|
injectClassIntoSystemLoader("org.embeddedt.modernfix.classloading.hashers.CoreModTransformerHasher");
|
||||||
|
injectClassIntoSystemLoader("org.embeddedt.modernfix.classloading.hashers.MixinTransformerHasher");
|
||||||
|
Class<?> newTransformerClass = injectClassIntoSystemLoader("cpw.mods.modlauncher.ModernFixCachingClassTransformer");
|
||||||
|
Constructor<?> constructor = newTransformerClass.getConstructor(TransformStore.class, LaunchPluginHandler.class, TransformingClassLoader.class, TransformerAuditTrail.class);
|
||||||
|
ClassTransformer newTransformer = (ClassTransformer)constructor.newInstance(store, pluginHandler, loader, trail);
|
||||||
|
classTransformerField.set(loader, newTransformer);
|
||||||
|
|
||||||
|
logger.info("Successfully injected caching transformer");
|
||||||
|
}
|
||||||
|
} catch(RuntimeException | ReflectiveOperationException | IOException e) {
|
||||||
|
logger.error("Failed to make classloading changes", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ public class ModernFixEarlyConfig {
|
||||||
this.addMixinRule("perf.async_jei", true);
|
this.addMixinRule("perf.async_jei", true);
|
||||||
this.addMixinRule("perf.thread_priorities", true);
|
this.addMixinRule("perf.thread_priorities", true);
|
||||||
this.addMixinRule("perf.preload_block_classes", false);
|
this.addMixinRule("perf.preload_block_classes", false);
|
||||||
this.addMixinRule("perf.parallel_potentially_unsafe", false);
|
this.addMixinRule("perf.defer_voxelshape_optimize", false);
|
||||||
this.addMixinRule("perf.parallel_blockstate_cache_rebuild", true);
|
this.addMixinRule("perf.parallel_blockstate_cache_rebuild", true);
|
||||||
this.addMixinRule("perf.deduplicate_location", true);
|
this.addMixinRule("perf.deduplicate_location", true);
|
||||||
this.addMixinRule("safety", true);
|
this.addMixinRule("safety", true);
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
package org.embeddedt.modernfix.mixin.perf.parallel_potentially_unsafe.parallel_deferred_suppliers;
|
|
||||||
|
|
||||||
import net.minecraftforge.registries.DeferredRegister;
|
|
||||||
import net.minecraftforge.registries.IForgeRegistry;
|
|
||||||
import org.embeddedt.modernfix.registry.DeferredRegisterBaker;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyArg;
|
|
||||||
|
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
@Mixin(DeferredRegister.class)
|
|
||||||
public class DeferredRegisterMixin {
|
|
||||||
@Shadow(remap = false) private IForgeRegistry type;
|
|
||||||
|
|
||||||
@Shadow(remap = false) @Final private String modid;
|
|
||||||
|
|
||||||
@ModifyArg(method = "register(Ljava/lang/String;Ljava/util/function/Supplier;)Lnet/minecraftforge/fml/RegistryObject;", at = @At(value = "INVOKE", target = "Ljava/util/Map;putIfAbsent(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"), index = 1, remap = false)
|
|
||||||
private Object swapForCachedSupplier(Object original) {
|
|
||||||
if(this.type != null)
|
|
||||||
return DeferredRegisterBaker.cacheForComputationLater(this.type.getRegistryName(), this.modid, (Supplier<?>)original);
|
|
||||||
else
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,24 +0,0 @@
|
||||||
package org.embeddedt.modernfix.mixin.perf.parallel_potentially_unsafe.parallel_deferred_suppliers;
|
|
||||||
|
|
||||||
import net.minecraft.block.DispenserBlock;
|
|
||||||
import net.minecraft.dispenser.IDispenseItemBehavior;
|
|
||||||
import net.minecraft.item.Item;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
@Mixin(DispenserBlock.class)
|
|
||||||
public class DispenserBlockMixin {
|
|
||||||
@Shadow private static Map<Item, IDispenseItemBehavior> DISPENSER_REGISTRY;
|
|
||||||
|
|
||||||
@Inject(method = "<clinit>", at = @At("TAIL"))
|
|
||||||
private static void makeMapConcurrent(CallbackInfo ci) {
|
|
||||||
DISPENSER_REGISTRY = new ConcurrentHashMap<>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
package org.embeddedt.modernfix.mixin.perf.parallel_potentially_unsafe.parallel_deferred_suppliers;
|
|
||||||
|
|
||||||
import net.minecraft.util.ResourceLocation;
|
|
||||||
import net.minecraftforge.event.RegistryEvent;
|
|
||||||
import net.minecraftforge.registries.DeferredRegister;
|
|
||||||
import net.minecraftforge.registries.IForgeRegistry;
|
|
||||||
import org.embeddedt.modernfix.registry.DeferredRegisterBaker;
|
|
||||||
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.CallbackInfo;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
@Mixin(DeferredRegister.EventDispatcher.class)
|
|
||||||
public class EventDispatcherMixin {
|
|
||||||
private static HashMap<ResourceLocation, Boolean> hasRegistryBaked = new HashMap<>();
|
|
||||||
@Inject(method = "handleEvent", at = @At("HEAD"), remap = false)
|
|
||||||
private void bakeIfNeeded(RegistryEvent.Register<?> event, CallbackInfo ci) {
|
|
||||||
IForgeRegistry<?> registry = event.getRegistry();
|
|
||||||
if(registry == null)
|
|
||||||
return;
|
|
||||||
ResourceLocation location = registry.getRegistryName();
|
|
||||||
if(location == null || !(location.getNamespace().equals("minecraft") && location.getPath().equals("block")))
|
|
||||||
return;
|
|
||||||
if(!hasRegistryBaked.getOrDefault(location, false)) {
|
|
||||||
DeferredRegisterBaker.bakeSuppliers(location);
|
|
||||||
hasRegistryBaked.put(location, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,3 +2,4 @@ public net.minecraft.client.Minecraft$WorldSelectionType
|
||||||
public net.minecraft.client.renderer.RenderType$Type
|
public net.minecraft.client.renderer.RenderType$Type
|
||||||
public net.minecraft.client.renderer.RenderType$Type <init>(Ljava/lang/String;Lnet/minecraft/client/renderer/vertex/VertexFormat;IIZZLnet/minecraft/client/renderer/RenderType$State;)V
|
public net.minecraft.client.renderer.RenderType$Type <init>(Ljava/lang/String;Lnet/minecraft/client/renderer/vertex/VertexFormat;IIZZLnet/minecraft/client/renderer/RenderType$State;)V
|
||||||
public net.minecraft.block.AbstractBlock$AbstractBlockState$Cache
|
public net.minecraft.block.AbstractBlock$AbstractBlockState$Cache
|
||||||
|
public net.minecraft.util.math.shapes.VoxelShape <init>(Lnet/minecraft/util/math/shapes/VoxelShapePart;)V # <init>
|
||||||
|
|
@ -19,12 +19,9 @@
|
||||||
"perf.boost_worker_count.UtilMixin",
|
"perf.boost_worker_count.UtilMixin",
|
||||||
"perf.thread_priorities.UtilMixin",
|
"perf.thread_priorities.UtilMixin",
|
||||||
"perf.preload_block_classes.GameDataMixin",
|
"perf.preload_block_classes.GameDataMixin",
|
||||||
"perf.parallel_potentially_unsafe.parallel_deferred_suppliers.DeferredRegisterMixin",
|
|
||||||
"perf.parallel_potentially_unsafe.parallel_deferred_suppliers.EventDispatcherMixin",
|
|
||||||
"perf.parallel_blockstate_cache_rebuild.BlocksMixin",
|
"perf.parallel_blockstate_cache_rebuild.BlocksMixin",
|
||||||
"perf.parallel_blockstate_cache_rebuild.BlockCallbacksMixin",
|
"perf.parallel_blockstate_cache_rebuild.BlockCallbacksMixin",
|
||||||
"perf.parallel_blockstate_cache_rebuild.ShapeCacheMixin",
|
"perf.parallel_blockstate_cache_rebuild.ShapeCacheMixin",
|
||||||
"perf.parallel_potentially_unsafe.parallel_deferred_suppliers.DispenserBlockMixin",
|
|
||||||
"perf.deduplicate_location.MixinResourceLocation"
|
"perf.deduplicate_location.MixinResourceLocation"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user