EarlyAccessTransformer

基本信息

属性 值
类 com.mitchej123.jarjar.rfb.transformer.EarlyAccessTransformer
Transformer ID jarjar-earlyaccesstransformer
RFB 排序 sortBefore = ["*"] — 最先运行
目标类(7 个) CoreModManager, CoreModManager.FMLPluginWrapper, CoreModManager$FMLPluginWrapper, ModListHelper, FMLInjectionData, ModCandidate, MetadataCollection

FML 1.7.10 的访问层级是 package-private,JarJar 的 V2 类需要访问这些字段/方法/内部类。Source-level jarjar_at.cfg 只在 access transformer 加载后生效,而 transformer 自身就需要这些字段,因此 JarJar 在 ASM 字节码层把它们改为 public。

操作

public void transformClass(loader, context, manifest, className, classNode) {
    final ClassNode cn = classNode.getNode();
    if (cn == null || cn.fields == null) return;

    cn.access &= ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED);
    cn.access |= Opcodes.ACC_PUBLIC;

    for (FieldNode field : cn.fields) {
        field.access &= ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED);
        field.access |= Opcodes.ACC_PUBLIC;
    }
    if (cn.methods != null) {
        for (MethodNode method : cn.methods) {
            method.access &= ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED);
            method.access |= Opcodes.ACC_PUBLIC;
        }
    }
    if (cn.innerClasses != null) {
        for (InnerClassNode innerClass : cn.innerClasses) {
            if (innerClass.name.endsWith("FMLPluginWrapper")) {
                innerClass.access &= ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED);
                innerClass.access |= Opcodes.ACC_PUBLIC;
            }
        }
    }
}

仅命中目标

shouldTransformClass 用 TARGET_CLASSES.contains(className) 限定,避免对所有类做无谓扫描。

private static final Set<String> TARGET_CLASSES = ImmutableSet.of(
    "cpw.mods.fml.relauncher.CoreModManager",
    "cpw.mods.fml.relauncher.CoreModManager.FMLPluginWrapper",
    "cpw.mods.fml.relauncher.CoreModManager$FMLPluginWrapper",
    "cpw.mods.fml.relauncher.ModListHelper",
    "cpw.mods.fml.relauncher.FMLInjectionData",
    "cpw.mods.fml.common.discovery.ModCandidate",
    "cpw.mods.fml.common.MetadataCollection");

设计意图

jarjar_at.cfg 中虽然也声明了同样的字段为 public,但 access transformer 必须等到 cpw.mods.fml.common.asm.transformers.ModAccessTransformer 加载,晚于 JarJar 自己的 transformer。所以 JarJar 必须用 ASM 直接修改访问标志。

后续 transformer(FMLTransformer、V2ConstructionReplacerTransformer)依赖这一修改后的可见性才能调用 INVOKESTATIC CoreModManager.somePrivate(...)。

相关条目