From 118ef1d507aa1a5bff1a3b286fd0c93f6b5f4087 Mon Sep 17 00:00:00 2001 From: CoolMineman <62723322+CoolMineman@users.noreply.github.com> Date: Fri, 16 Dec 2022 22:19:00 -0600 Subject: [PATCH] param mapping lvt fix --- .../brachyura/fabric/FabricContext.java | 13 +- .../tinyremapper/RemapperProcessor.java | 7 +- .../brachyura/quilt/QuiltContext.java | 2 +- .../remapper/MappingIoMappings.java | 46 ++++- .../recombobulator/remapper/Mappings.java | 8 + .../remapper/RecombobulatorRemapper.java | 183 +++++++++++++++++- 6 files changed, 243 insertions(+), 16 deletions(-) diff --git a/brachyura-minecraft/src/main/java/io/github/coolcrabs/brachyura/fabric/FabricContext.java b/brachyura-minecraft/src/main/java/io/github/coolcrabs/brachyura/fabric/FabricContext.java index 32f91de1..593161bd 100644 --- a/brachyura-minecraft/src/main/java/io/github/coolcrabs/brachyura/fabric/FabricContext.java +++ b/brachyura-minecraft/src/main/java/io/github/coolcrabs/brachyura/fabric/FabricContext.java @@ -163,7 +163,8 @@ public Map getRemappedClasses(BuildModule... modu getCompileDependencies(), compmappings, compmappings.getNamespaceId(Namespaces.NAMED), - compmappings.getNamespaceId(Namespaces.INTERMEDIARY) + compmappings.getNamespaceId(Namespaces.INTERMEDIARY), + false ) ).apply( (in, id) -> sm.get(id).sink(in, id), @@ -329,7 +330,7 @@ public byte remappedModsLogicVersion() { } public ProcessorChain modRemapChainOverrideOnlyIfYouOverrideRemappedModsRootPathAndLogicVersion(MappingTree tree, String src, String dst, List cp, Map c) { - RemapperProcessor rp = new RemapperProcessor(cp, tree, tree.getNamespaceId(src), tree.getNamespaceId(dst)); + RemapperProcessor rp = new RemapperProcessor(cp, tree, tree.getNamespaceId(src), tree.getNamespaceId(dst), false); return new ProcessorChain( rp, new MetaInfFixer(rp), @@ -633,7 +634,7 @@ protected RemappedJar createIntermediaryJar() { Path result = fabricCache().resolve("intermediary").resolve(versionMeta.get().version + "-r" + Recombobulator.getVersion() + "-intermediary-" + intermediaryHash + ".jar"); if (!Files.isRegularFile(result)) { try (AtomicFile atomicFile = new AtomicFile(result)) { - remapJar(intermediary.get(), Namespaces.OBF, Namespaces.INTERMEDIARY, mergedJar, atomicFile.tempPath, mcClasspathPaths.get()); + remapJar(intermediary.get(), Namespaces.OBF, Namespaces.INTERMEDIARY, mergedJar, atomicFile.tempPath, mcClasspathPaths.get(), false); atomicFile.commit(); } } @@ -649,7 +650,7 @@ protected RemappedJar createRemappedNamedJar() { Path result = fabricCache().resolve("named").resolve(versionMeta.get().version + "-r" + Recombobulator.getVersion() + "-named-" + mappingHash + ".jar"); if (!Files.isRegularFile(result)) { try (AtomicFile atomicFile = new AtomicFile(result)) { - remapJar(mappings.get(), Namespaces.INTERMEDIARY, Namespaces.NAMED, intermediaryjar.get().jar, atomicFile.tempPath, mcClasspathPaths.get()); + remapJar(mappings.get(), Namespaces.INTERMEDIARY, Namespaces.NAMED, intermediaryjar.get().jar, atomicFile.tempPath, mcClasspathPaths.get(), true); atomicFile.commit(); } } @@ -700,7 +701,7 @@ protected JavaJarDependency createDecompiledJar() { return decompiler.getDecompiled(named.jar, decompClasspath(), resultDir, mappings.get(), Namespaces.NAMED).toJavaJarDep(null); } - public void remapJar(MappingTree mappings, String src, String dst, Path inputJar, Path outputJar, List classpath) { + public void remapJar(MappingTree mappings, String src, String dst, Path inputJar, Path outputJar, List classpath, boolean replaceLvt) { // TinyRemapper.Builder remapperBuilder = TinyRemapper.newRemapper() // .withMappings(new MappingTreeMappingProvider(mappings, src, dst)) // .withMappings(Jsr2JetbrainsMappingProvider.INSTANCE) @@ -716,7 +717,7 @@ public void remapJar(MappingTree mappings, String src, String dst, Path inputJar ZipProcessingSource source = new ZipProcessingSource(inputJar); ZipProcessingSink sink = new ZipProcessingSink(outputJar); ) { - new ProcessorChain(new RemapperProcessor(classpath, mappings, mappings.getNamespaceId(src), mappings.getNamespaceId(dst))).apply(sink, source); + new ProcessorChain(new RemapperProcessor(classpath, mappings, mappings.getNamespaceId(src), mappings.getNamespaceId(dst), replaceLvt)).apply(sink, source); } } diff --git a/brachyura-minecraft/src/main/java/io/github/coolcrabs/brachyura/mappings/tinyremapper/RemapperProcessor.java b/brachyura-minecraft/src/main/java/io/github/coolcrabs/brachyura/mappings/tinyremapper/RemapperProcessor.java index 39a83854..286c2327 100644 --- a/brachyura-minecraft/src/main/java/io/github/coolcrabs/brachyura/mappings/tinyremapper/RemapperProcessor.java +++ b/brachyura-minecraft/src/main/java/io/github/coolcrabs/brachyura/mappings/tinyremapper/RemapperProcessor.java @@ -47,12 +47,14 @@ public class RemapperProcessor implements Processor { final MappingTree mappingTree; final int src; final int dst; + final boolean replaceLvt; - public RemapperProcessor(List classpath, MappingTree mappingTree, int src, int dst) { + public RemapperProcessor(List classpath, MappingTree mappingTree, int src, int dst, boolean replaceLvt) { this.classpath = classpath; this.mappingTree = mappingTree; this.src = src; this.dst = dst; + this.replaceLvt = replaceLvt; } @Override @@ -114,6 +116,9 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO RecombobulatorRemapper remapper = new RecombobulatorRemapper(); remapper.setClasses(ins); remapper.setMappings(mappings); + if (replaceLvt) { + remapper.replaceLvtAndParams(); + } ConcurrentLinkedQueue o = new ConcurrentLinkedQueue<>(); remapper.setOutput(new RemapperOutputConsumer() { public void outputClass(String path, ClassInfo ci, Object tag) { diff --git a/brachyura-minecraft/src/main/java/io/github/coolcrabs/brachyura/quilt/QuiltContext.java b/brachyura-minecraft/src/main/java/io/github/coolcrabs/brachyura/quilt/QuiltContext.java index 1073cb71..19bc403b 100644 --- a/brachyura-minecraft/src/main/java/io/github/coolcrabs/brachyura/quilt/QuiltContext.java +++ b/brachyura-minecraft/src/main/java/io/github/coolcrabs/brachyura/quilt/QuiltContext.java @@ -85,7 +85,7 @@ public byte remappedModsLogicVersion() { @Override public ProcessorChain modRemapChainOverrideOnlyIfYouOverrideRemappedModsRootPathAndLogicVersion(MappingTree tree, String src, String dst, List cp, Map c) { - RemapperProcessor rp = new RemapperProcessor(cp, tree, tree.getNamespaceId(src), tree.getNamespaceId(dst)); + RemapperProcessor rp = new RemapperProcessor(cp, tree, tree.getNamespaceId(src), tree.getNamespaceId(dst), false); return new ProcessorChain( rp, new MetaInfFixer(rp), diff --git a/recombobulator/src/main/java/io/github/coolcrabs/brachyura/recombobulator/remapper/MappingIoMappings.java b/recombobulator/src/main/java/io/github/coolcrabs/brachyura/recombobulator/remapper/MappingIoMappings.java index 5620a3ef..3b7ca592 100644 --- a/recombobulator/src/main/java/io/github/coolcrabs/brachyura/recombobulator/remapper/MappingIoMappings.java +++ b/recombobulator/src/main/java/io/github/coolcrabs/brachyura/recombobulator/remapper/MappingIoMappings.java @@ -19,15 +19,20 @@ import io.github.coolcrabs.brachyura.recombobulator.AccessFlags; import io.github.coolcrabs.brachyura.recombobulator.Mutf8Slice; import io.github.coolcrabs.brachyura.recombobulator.remapper.InheritanceMap.InheritanceGroup; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import net.fabricmc.mappingio.tree.MappingTree; import net.fabricmc.mappingio.tree.MappingTree.ClassMapping; import net.fabricmc.mappingio.tree.MappingTree.FieldMapping; +import net.fabricmc.mappingio.tree.MappingTree.MethodArgMapping; import net.fabricmc.mappingio.tree.MappingTree.MethodMapping; public class MappingIoMappings implements Mappings { + public static final boolean LOG_PARAM_CONFLICS = Boolean.getBoolean("recombobulator.logparamconflicts"); + private final Map classMap; final Int2ObjectOpenHashMap methodMap; + final Int2ObjectOpenHashMap> methodArgMap; private final InheritanceMap inheritanceMap; private final ConcurrentHashMap> fieldMap; @@ -73,9 +78,11 @@ public MappingIoMappings(MappingTree tree, int src, int dst, InheritanceMap inhe class IntNameDescPairPair { int key; NameDescPair value; + Int2ObjectOpenHashMap params; } int size = inheritanceMap.curId; methodMap = new Int2ObjectOpenHashMap<>(size); + methodArgMap = new Int2ObjectOpenHashMap<>(size); boolean conflict = false; ArrayList>> futures1 = new ArrayList<>(size); for (ClassMapping c : tree.getClasses()) { @@ -102,6 +109,19 @@ class IntNameDescPairPair { IntNameDescPairPair indpp = new IntNameDescPairPair(); indpp.key = igroup.id; indpp.value = mdst; + int s = 0; + for (MethodArgMapping mam : m.getArgs()) { + if (mam.getName(dst) != null) s++; + } + if (s > 0) { + indpp.params = new Int2ObjectOpenHashMap<>(s); + for (MethodArgMapping mam : m.getArgs()) { + String mamn = mam.getName(dst); + if (mamn != null) { + indpp.params.put(mam.getLvIndex(), new Mutf8Slice(mamn)); + } + } + } r.add(indpp); } return r; @@ -113,9 +133,22 @@ class IntNameDescPairPair { for (IntNameDescPairPair indpp : indpps) { NameDescPair old = methodMap.put(indpp.key, indpp.value); if (old != null && !old.equals(indpp.value)) { - Logger.error("Method mapping confllict {} {} {}", indpp.key, old, indpp.value); + Logger.error("Method mapping confllict {} {} {}", indpp.value, old, indpp.value); conflict = true; } + if (indpp.params != null) { + methodArgMap.compute(indpp.key, (k, v) -> { + if (v == null) return indpp.params; + for (Int2ObjectMap.Entry e : indpp.params.int2ObjectEntrySet()) { + Mutf8Slice o = v.put(e.getIntKey(), e.getValue()); + if (o != null && !o.equals(e.getValue())) { + if (LOG_PARAM_CONFLICS) Logger.warn("Param conflict {} {} {}", indpp.value, o, e.getValue()); + v.put(e.getIntKey(), o.compareTo(e.getValue()) > 0 ? o : e.getValue()); + } + } + return v; + }); + } } } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); @@ -192,4 +225,15 @@ public NameDescPair mapField(Mutf8Slice srcCls, NameDescPair srcField) { } return new NameDescPair(srcField.name, Mappings.remapFieldDescriptor(this, srcField.desc)); } + + @Override + public @Nullable Mutf8Slice mapParam(Mutf8Slice srcCls, NameDescPair srcMethod, int lvtIndex) { + InheritanceGroup ig = mapMethod0(srcCls, srcMethod, true); + if (ig != null) { + Int2ObjectOpenHashMap r1 = methodArgMap.get(ig.id); + if (r1 == null) return null; + return r1.get(lvtIndex); + } + return null; + } } diff --git a/recombobulator/src/main/java/io/github/coolcrabs/brachyura/recombobulator/remapper/Mappings.java b/recombobulator/src/main/java/io/github/coolcrabs/brachyura/recombobulator/remapper/Mappings.java index 06a91fcd..aef9f55d 100644 --- a/recombobulator/src/main/java/io/github/coolcrabs/brachyura/recombobulator/remapper/Mappings.java +++ b/recombobulator/src/main/java/io/github/coolcrabs/brachyura/recombobulator/remapper/Mappings.java @@ -2,19 +2,27 @@ import java.nio.ByteBuffer; +import org.jetbrains.annotations.Nullable; + import io.github.coolcrabs.brachyura.recombobulator.ByteBufferUtil; import io.github.coolcrabs.brachyura.recombobulator.Mutf8Slice; import it.unimi.dsi.fastutil.bytes.ByteArrayList; public interface Mappings { Mutf8Slice mapClass(Mutf8Slice srcCls); + default NameDescPair mapField(Mutf8Slice srcCls, NameDescPair srcField) { return new NameDescPair(srcField.name, remapFieldDescriptor(this, srcField.desc)); } + default NameDescPair mapMethod(Mutf8Slice srcCls, NameDescPair srcMethod) { return new NameDescPair(srcMethod.name, remapMethodDescriptor(this, srcMethod.desc)); } + default @Nullable Mutf8Slice mapParam(Mutf8Slice srcCls, NameDescPair srcMethod, int lvtIndex) { + return null; + } + public static Mutf8Slice remapFieldDescriptor(Mappings mappings, Mutf8Slice desc) { ByteBuffer b = desc.b; int start = b.position(); diff --git a/recombobulator/src/main/java/io/github/coolcrabs/brachyura/recombobulator/remapper/RecombobulatorRemapper.java b/recombobulator/src/main/java/io/github/coolcrabs/brachyura/recombobulator/remapper/RecombobulatorRemapper.java index 3ecfbda4..fba5cad5 100644 --- a/recombobulator/src/main/java/io/github/coolcrabs/brachyura/recombobulator/remapper/RecombobulatorRemapper.java +++ b/recombobulator/src/main/java/io/github/coolcrabs/brachyura/recombobulator/remapper/RecombobulatorRemapper.java @@ -3,6 +3,7 @@ import java.io.InputStream; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.BitSet; import java.util.Collection; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; @@ -12,6 +13,7 @@ import org.tinylog.Logger; +import io.github.coolcrabs.brachyura.recombobulator.AccessFlags; import io.github.coolcrabs.brachyura.recombobulator.ByteBufferUtil; import io.github.coolcrabs.brachyura.recombobulator.ClassInfo; import io.github.coolcrabs.brachyura.recombobulator.ConstantClass; @@ -117,6 +119,9 @@ public class RecombobulatorRemapper { Collection toRead = new ArrayList<>(); Collection toOutput = new ArrayList<>(); Mappings mappings; + boolean replaceLvtAndParams; + + static final Mutf8Slice THIS_STR = new Mutf8Slice("this"); public void setClasses(Collection classes) { toRead = classes; @@ -134,6 +139,10 @@ public void setOutput(RemapperOutputConsumer out) { this.output = out; } + public void replaceLvtAndParams() { + this.replaceLvtAndParams = true; + } + public static class Input { Supplier readSup; String path; @@ -538,7 +547,7 @@ public void visitAttributeSynthetic(AttributeSynthetic el) { @Override public void visitEntryParameters(EntryParameters el) { - //noop + refs.ref(el.name_index, -1); } @Override @@ -558,6 +567,7 @@ public void visitEntryParameterAnnotations(EntryParameterAnnotations el) { @Override public void visitEntryLocalVariableTypeTable(EntryLocalVariableTypeTable el) { + refs.ref(el.name_index, -1); refs.ref(el.signature_index, -1); } @@ -583,6 +593,7 @@ public void visitEntryLineNumberTable(EntryLineNumberTable el) { @Override public void visitEntryLocalVariableTable(EntryLocalVariableTable el) { + refs.ref(el.name_index, -1); refs.ref(el.descriptor_index, -1); } @@ -597,7 +608,7 @@ public void visitEntryRequires(EntryRequires el) { } } - public static class RemapVisitor implements RecombobulatorVisitor { + public class RemapVisitor implements RecombobulatorVisitor { final ConstantPool cp; final ConstantPool newCp; final Mappings mappings; @@ -724,16 +735,55 @@ public void visitClassInfo(ClassInfo el) { } } + AttributeMethodParameters params; + boolean isDynamic; + int[] lvtp; + @Override public void visitMethodInfo(MethodInfo el) { + isDynamic = (el.access_flags & AccessFlags.ACC_STATIC) == 0; NameDescPair unmapped = new NameDescPair(utf8(cp, el.name_index), utf8(cp, el.descriptor_index)); NameDescPair mapped = mappings.mapMethod(clsName, unmapped); - if (mapped == null) { - el.name_index = getUtf8Index(cp, newCp, utf8Map, openSlots, unmapped.name); - el.descriptor_index = getUtf8Index(cp, newCp, utf8Map, openSlots, Mappings.remapMethodDescriptor(mappings, unmapped.desc)); + el.name_index = getUtf8Index(cp, newCp, utf8Map, openSlots, mapped.name); + el.descriptor_index = getUtf8Index(cp, newCp, utf8Map, openSlots, mapped.desc); + params = null; + for (Attribute a : el.attributes) { + if (a instanceof AttributeMethodParameters) params = (AttributeMethodParameters) a; + } + int pcount = countParams(mapped.desc); + int[] plvt = new int[pcount]; + p2lvt(mapped.desc, plvt, isDynamic); + if (plvt.length == 0) { + lvtp = new int[0]; } else { - el.name_index = getUtf8Index(cp, newCp, utf8Map, openSlots, mapped.name); - el.descriptor_index = getUtf8Index(cp, newCp, utf8Map, openSlots, mapped.desc); + lvtp = new int[plvt[plvt.length - 1] + 1]; + for (int i = 0; i < pcount; i++) { + lvtp[plvt[i]] = i; + } + } + if (params == null) { + ArrayList p = new ArrayList<>(pcount); + params = new AttributeMethodParameters(getUtf8Index(cp, newCp, utf8Map, openSlots, AttributeMethodParameters.NAME), p); + el.attributes.add(params); + } + while (params.parameters.size() < pcount) { + params.parameters.add(new EntryParameters(0, 0)); + } + BitSet mappedp = new BitSet(params.parameters.size()); + if (replaceLvtAndParams) { + for (int i = 0; i < pcount; i++) { + int lvi = plvt[i]; + Mutf8Slice pm = mappings.mapParam(clsName, unmapped, lvi); + if (pm == null) continue; + mappedp.set(i); + params.parameters.get(i).name_index = getUtf8Index(cp, newCp, utf8Map, openSlots, pm); + } + } + for (int i = 0; i < params.parameters.size(); i++) { + if (!mappedp.get(i)) { + EntryParameters ep = params.parameters.get(i); + ep.name_index = ep.name_index == 0 ? 0 : getUtf8Index(cp, newCp, utf8Map, openSlots, utf8(cp, ep.name_index)); + } } } @@ -1082,6 +1132,18 @@ public void visitEntryParameterAnnotations(EntryParameterAnnotations el) { @Override public void visitEntryLocalVariableTypeTable(EntryLocalVariableTypeTable el) { el.signature_index = getUtf8Index(cp, newCp, utf8Map, openSlots, Mappings.remapSignature(mappings, utf8(cp, el.signature_index))); + if (isDynamic && el.index == 0) { + el.name_index = getUtf8Index(cp, newCp, utf8Map, openSlots, THIS_STR); + } else if (el.index < lvtp.length) { + el.name_index = params.parameters.get(lvtp[el.index]).name_index; + if (el.name_index == 0) { + el.name_index = getUtf8Index(cp, newCp, utf8Map, openSlots, new Mutf8Slice("param" + lvtp[el.index])); + } + } else if (replaceLvtAndParams) { + el.name_index = getUtf8Index(cp, newCp, utf8Map, openSlots, new Mutf8Slice("lv" + el.index)); + } else { + el.name_index = getUtf8Index(cp, newCp, utf8Map, openSlots, utf8(cp, el.name_index)); + } } @Override @@ -1119,6 +1181,18 @@ public void visitEntryLineNumberTable(EntryLineNumberTable el) { @Override public void visitEntryLocalVariableTable(EntryLocalVariableTable el) { el.descriptor_index = getUtf8Index(cp, newCp, utf8Map, openSlots, Mappings.remapFieldDescriptor(mappings, utf8(cp, el.descriptor_index))); + if (isDynamic && el.index == 0) { + el.name_index = getUtf8Index(cp, newCp, utf8Map, openSlots, THIS_STR); + } else if (el.index < lvtp.length) { + el.name_index = params.parameters.get(lvtp[el.index]).name_index; + if (el.name_index == 0) { + el.name_index = getUtf8Index(cp, newCp, utf8Map, openSlots, new Mutf8Slice("param" + lvtp[el.index])); + } + } else if (replaceLvtAndParams) { + el.name_index = getUtf8Index(cp, newCp, utf8Map, openSlots, new Mutf8Slice("lv" + el.index)); + } else { + el.name_index = getUtf8Index(cp, newCp, utf8Map, openSlots, utf8(cp, el.name_index)); + } } @Override @@ -1229,4 +1303,99 @@ static Mutf8Slice cls2Utf8(ConstantPool pool, int index) { static Mutf8Slice utf8(ConstantPool pool, int index) { return ((ConstantUtf8)pool.getEntry(index)).slice; } + + static int countParams(Mutf8Slice desc) { + int r = 0; + ByteBuffer b = desc.b; + int start = b.position() + 1; + int end = b.limit(); + for (int i = start; i < end; i++) { + byte character = b.get(i); + switch (character) { + case ')': + return r; + case 'V': + case 'B': + case 'C': + case 'D': + case 'F': + case 'I': + case 'J': + case 'S': + case 'Z': + r += 1; + break; + case '[': + break; + case 'L': + int classEnd = -1; + for (int j = i + 1; j < end; j++) { + if (b.get(j) == ';') { + classEnd = j; + break; + } + } + i = classEnd; + r += 1; + break; + default: + throw new RuntimeException("Illegal desc: " + desc.toString() + " " + ((char)character)); + } + } + throw new RuntimeException("Illegal desc: " + desc.toString()); + } + + static void p2lvt(Mutf8Slice desc, int[] p2lvt, boolean isDynamic) { + ByteBuffer b = desc.b; + int start = b.position() + 1; + int end = b.limit(); + int ppos = 0; + int plvt = isDynamic ? 1 : 0; + boolean inArray = false; + for (int i = start; i < end; i++) { + byte character = b.get(i); + switch (character) { + case ')': + return; + case 'V': + case 'B': + case 'C': + case 'F': + case 'I': + case 'S': + case 'Z': + p2lvt[ppos++] = plvt++; + inArray = false; + break; + case 'D': + case 'J': + if (inArray) { + p2lvt[ppos++] = plvt++; + inArray = false; + } else { + p2lvt[ppos++] = plvt; + plvt += 2; + } + break; + case '[': + inArray = true; + break; + case 'L': + int classEnd = -1; + for (int j = i + 1; j < end; j++) { + if (b.get(j) == ';') { + classEnd = j; + break; + } + } + i = classEnd; + p2lvt[ppos++] = plvt++; + inArray = false; + break; + default: + throw new RuntimeException("Illegal desc: " + desc.toString() + " " + ((char)character)); + } + } + throw new RuntimeException("Illegal desc: " + desc.toString()); + } }