-
Notifications
You must be signed in to change notification settings - Fork 65
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
various patches to optimize loading time (#89)
* nuke basemod check modloader is dead long before 1.7.10 comes to be. This accounts for 3.7 second of loading time. * optimize ASMDataTable getAnnotationsFor This accounts for 2.7 second loading time * spotlessApply (#90) Co-authored-by: Glease <[email protected]> Co-authored-by: GitHub GTNH Actions <> * suppress configuration not found warnings Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
- Loading branch information
1 parent
b0c46b5
commit bf4151d
Showing
6 changed files
with
208 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
jar { | ||
manifest { | ||
// I need a place to call add this IClassTransformer before CoFHCore loads its transformation target | ||
attributes "CCTransformer": "com.mitchej123.hodgepodge.asm.EarlyClassTransformer" | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
src/main/java/com/mitchej123/hodgepodge/asm/EarlyASMCallHooks.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.mitchej123.hodgepodge.asm; | ||
|
||
import static cpw.mods.fml.common.ModContainerFactory.modTypes; | ||
|
||
import cpw.mods.fml.common.FMLLog; | ||
import cpw.mods.fml.common.ModContainer; | ||
import cpw.mods.fml.common.discovery.ModCandidate; | ||
import cpw.mods.fml.common.discovery.asm.ASMModParser; | ||
import cpw.mods.fml.common.discovery.asm.ModAnnotation; | ||
import java.io.File; | ||
import org.apache.logging.log4j.Level; | ||
|
||
public class EarlyASMCallHooks { | ||
public static ModContainer build(ASMModParser modParser, File modSource, ModCandidate container) { | ||
String className = modParser.getASMType().getClassName(); | ||
|
||
for (ModAnnotation ann : modParser.getAnnotations()) { | ||
if (modTypes.containsKey(ann.getASMType())) { | ||
FMLLog.fine("Identified a mod of type %s (%s) - loading", ann.getASMType(), className); | ||
try { | ||
return modTypes.get(ann.getASMType()).newInstance(className, container, ann.getValues()); | ||
} catch (Exception e) { | ||
FMLLog.log( | ||
Level.ERROR, | ||
e, | ||
"Unable to construct %s container", | ||
ann.getASMType().getClassName()); | ||
return null; | ||
} | ||
} | ||
} | ||
|
||
return null; | ||
} | ||
} |
106 changes: 106 additions & 0 deletions
106
src/main/java/com/mitchej123/hodgepodge/asm/EarlyClassTransformer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package com.mitchej123.hodgepodge.asm; | ||
|
||
import static org.objectweb.asm.Opcodes.*; | ||
|
||
import java.io.*; | ||
import java.util.Properties; | ||
import net.minecraft.launchwrapper.IClassTransformer; | ||
import net.minecraft.launchwrapper.Launch; | ||
import org.apache.logging.log4j.LogManager; | ||
import org.apache.logging.log4j.Logger; | ||
import org.objectweb.asm.*; | ||
|
||
/** | ||
* This class transformer will be loaded by CodeChickenCore, if it is present. | ||
* It runs much earlier than the rest of class transformers and mixins do and can modify more of forge's and fml's classes. | ||
* <p> | ||
* Due to peculiarity with CCC, and to prevent loading too many classes from messing up the delicate class loading order, | ||
* we will try to minimize the class dependencies on this class, meaning we will not use the usual Configuration class to | ||
* handle configurations | ||
*/ | ||
public class EarlyClassTransformer implements IClassTransformer { | ||
private static final boolean noNukeBaseMod; | ||
private static final Logger LOGGER = LogManager.getLogger("HodgePodgeEarly"); | ||
|
||
static { | ||
Properties config = new Properties(); | ||
File configLocation = new File(Launch.minecraftHome, "config/hodgepodgeEarly.properties"); | ||
try (Reader r = new BufferedReader(new FileReader(configLocation))) { | ||
config.load(r); | ||
} catch (FileNotFoundException e) { | ||
LOGGER.debug("No existing configuration file. Will use defaults"); | ||
} catch (IOException e) { | ||
LOGGER.error("Error reading configuration file. Will use defaults", e); | ||
} | ||
noNukeBaseMod = Boolean.parseBoolean(config.getProperty("noNukeBaseMod")); | ||
config.setProperty("noNukeBaseMod", String.valueOf(noNukeBaseMod)); | ||
try (Writer r = new BufferedWriter(new FileWriter(configLocation))) { | ||
config.store(r, "Configuration file for early hodgepodge class transformers"); | ||
} catch (IOException e) { | ||
LOGGER.error("Error reading configuration file. Will use defaults", e); | ||
} | ||
} | ||
|
||
@Override | ||
public byte[] transform(String name, String transformedName, byte[] basicClass) { | ||
if (basicClass == null || name == null) return basicClass; | ||
switch (name) { | ||
case "cpw.mods.fml.common.ModContainerFactory": | ||
if (noNukeBaseMod) return basicClass; | ||
return transformModContainerFactory(basicClass); | ||
default: | ||
return basicClass; | ||
} | ||
} | ||
|
||
private static byte[] transformModContainerFactory(byte[] basicClass) { | ||
ClassReader cr = new ClassReader(basicClass); | ||
ClassWriter cw = new ClassWriter(0); | ||
ClassVisitor cv = new ClassVisitor(ASM5, cw) { | ||
@Override | ||
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) { | ||
// we no longer need to check for basemod, so this regex is also useless now. remove it. | ||
if ("modClass".equals(name)) return null; | ||
return super.visitField(access, name, desc, signature, value); | ||
} | ||
|
||
@Override | ||
public MethodVisitor visitMethod( | ||
int access, String name, String desc, String signature, String[] exceptions) { | ||
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); | ||
switch (name) { | ||
case "build": | ||
// inject callhook | ||
mv.visitVarInsn(ALOAD, 1); | ||
mv.visitVarInsn(ALOAD, 2); | ||
mv.visitVarInsn(ALOAD, 3); | ||
mv.visitMethodInsn( | ||
INVOKESTATIC, | ||
"com/mitchej123/hodgepodge/asm/EarlyASMCallHooks", | ||
"build", | ||
"(Lcpw/mods/fml/common/discovery/asm/ASMModParser;Ljava/io/File;Lcpw/mods/fml/common/discovery/ModCandidate;)Lcpw/mods/fml/common/ModContainer;", | ||
false); | ||
mv.visitInsn(ARETURN); | ||
mv.visitMaxs(3, 4); | ||
mv.visitEnd(); | ||
return null; | ||
case "<clinit>": | ||
mv = new MethodVisitor(ASM5, mv) { | ||
@Override | ||
public void visitFieldInsn(int opcode, String owner, String name, String desc) { | ||
if (name.equals("modClass")) { | ||
// remove access to modClass | ||
super.visitInsn(POP); | ||
} else { | ||
super.visitFieldInsn(opcode, owner, name, desc); | ||
} | ||
} | ||
}; | ||
} | ||
return mv; | ||
} | ||
}; | ||
cr.accept(cv, 0); | ||
return cw.toByteArray(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
52 changes: 52 additions & 0 deletions
52
src/main/java/com/mitchej123/hodgepodge/mixins/forge/MixinASMDataTable.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
package com.mitchej123.hodgepodge.mixins.forge; | ||
|
||
import com.google.common.collect.HashMultimap; | ||
import com.google.common.collect.Multimap; | ||
import com.google.common.collect.Multimaps; | ||
import com.google.common.collect.SetMultimap; | ||
import cpw.mods.fml.common.ModContainer; | ||
import cpw.mods.fml.common.discovery.ASMDataTable; | ||
import cpw.mods.fml.common.discovery.ASMDataTable.ASMData; | ||
import java.io.File; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Map.Entry; | ||
import org.spongepowered.asm.mixin.Mixin; | ||
import org.spongepowered.asm.mixin.Overwrite; | ||
import org.spongepowered.asm.mixin.Shadow; | ||
|
||
@Mixin(ASMDataTable.class) | ||
public class MixinASMDataTable { | ||
@Shadow(remap = false) | ||
private SetMultimap<String, ASMData> globalAnnotationData; | ||
|
||
@Shadow(remap = false) | ||
private Map<ModContainer, SetMultimap<String, ASMData>> containerAnnotationData; | ||
|
||
@Shadow(remap = false) | ||
private List<ModContainer> containers; | ||
/** | ||
* We will forget the guava immutable collections now, since everyone thought they are immutable and won't attempt | ||
* to mutate it. | ||
* @author glee8e | ||
* @reason to optimize the embarrassingly inefficient containerAnnotationData build process | ||
*/ | ||
@Overwrite(remap = false) | ||
public SetMultimap<String, ASMData> getAnnotationsFor(ModContainer container) { | ||
if (containerAnnotationData == null) { | ||
Map<ModContainer, SetMultimap<String, ASMData>> mapBuilder = new HashMap<>(); | ||
Multimap<File, ModContainer> containersMap = Multimaps.index(containers, ModContainer::getSource); | ||
for (Entry<String, ASMData> entry : globalAnnotationData.entries()) { | ||
for (ModContainer modContainer : | ||
containersMap.get(entry.getValue().getCandidate().getModContainer())) { | ||
mapBuilder | ||
.computeIfAbsent(modContainer, map -> HashMultimap.create()) | ||
.put(entry.getKey(), entry.getValue()); | ||
} | ||
} | ||
containerAnnotationData = mapBuilder; | ||
} | ||
return containerAnnotationData.get(container); | ||
} | ||
} |