Deduplicate strings in ObfHelper (#6841)

This commit is contained in:
Jason Penilla 2021-11-04 17:23:06 -07:00
parent 280cf8d8db
commit 130e21da7e
4 changed files with 77 additions and 74 deletions

View file

@ -56,14 +56,14 @@ paperweight {
minecraftVersion.set(providers.gradleProperty("mcVersion")) minecraftVersion.set(providers.gradleProperty("mcVersion"))
serverProject.set(project(":Paper-Server")) serverProject.set(project(":Paper-Server"))
paramMappingsRepo.set("https://maven.quiltmc.org/repository/release/")
remapRepo.set("https://maven.fabricmc.net/")
decompileRepo.set("https://files.minecraftforge.net/maven/")
paper { paper {
spigotApiPatchDir.set(layout.projectDirectory.dir("patches/api")) spigotApiPatchDir.set(layout.projectDirectory.dir("patches/api"))
spigotServerPatchDir.set(layout.projectDirectory.dir("patches/server")) spigotServerPatchDir.set(layout.projectDirectory.dir("patches/server"))
paramMappingsRepo.set("https://maven.quiltmc.org/repository/release/")
remapRepo.set("https://maven.fabricmc.net/")
decompileRepo.set("https://files.minecraftforge.net/maven/")
mappingsPatch.set(layout.projectDirectory.file("build-data/mappings-patch.tiny")) mappingsPatch.set(layout.projectDirectory.file("build-data/mappings-patch.tiny"))
reobfMappingsPatch.set(layout.projectDirectory.file("build-data/reobf-mappings-patch.tiny")) reobfMappingsPatch.set(layout.projectDirectory.file("build-data/reobf-mappings-patch.tiny"))
@ -86,18 +86,15 @@ paperweight {
tasks.generateDevelopmentBundle { tasks.generateDevelopmentBundle {
apiCoordinates.set("io.papermc.paper:paper-api") apiCoordinates.set("io.papermc.paper:paper-api")
mojangApiCoordinates.set("io.papermc.paper:paper-mojangapi") mojangApiCoordinates.set("io.papermc.paper:paper-mojangapi")
libraryRepositories.set( libraryRepositories.addAll(
listOf( "https://repo.maven.apache.org/maven2/",
"https://repo.maven.apache.org/maven2/", "https://libraries.minecraft.net/",
"https://libraries.minecraft.net/", "https://papermc.io/repo/repository/maven-public/",
"https://papermc.io/repo/repository/maven-public/",
"https://maven.quiltmc.org/repository/release/",
)
) )
} }
publishing { publishing {
if (project.hasProperty("publishDevBundle")) { if (project.providers.gradleProperty("publishDevBundle").forUseAtConfigurationTime().isPresent) {
publications.create<MavenPublication>("devBundle") { publications.create<MavenPublication>("devBundle") {
artifact(tasks.generateDevelopmentBundle) { artifact(tasks.generateDevelopmentBundle) {
artifactId = "dev-bundle" artifactId = "dev-bundle"
@ -109,9 +106,8 @@ publishing {
allprojects { allprojects {
publishing { publishing {
repositories { repositories {
maven { maven("https://papermc.io/repo/repository/maven-snapshots/") {
name = "paperSnapshots" name = "paperSnapshots"
url = uri("https://papermc.io/repo/repository/maven-snapshots/")
credentials(PasswordCredentials::class) credentials(PasswordCredentials::class)
} }
} }

View file

@ -24,11 +24,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
repositories { repositories {
maven("https://libraries.minecraft.net/") maven("https://libraries.minecraft.net/")
+ // Paper start + // Paper start
+ maven("https://maven.quiltmc.org/repository/release/") { + maven("https://maven.fabricmc.net/") {
+ mavenContent { + mavenContent { includeModule("net.fabricmc", "mapping-io") }
+ releasesOnly()
+ includeModule("org.quiltmc", "tiny-mappings-parser")
+ }
+ } + }
+ // Paper end + // Paper end
} }
@ -38,11 +35,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
implementation("io.netty:netty-all:4.1.65.Final") // Paper implementation("io.netty:netty-all:4.1.65.Final") // Paper
+ implementation("org.quiltmc:tiny-mappings-parser:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation + implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation
+ +
testImplementation("junit:junit:4.13.1") testImplementation("junit:junit:4.13.1")
testImplementation("org.hamcrest:hamcrest-library:1.3") testImplementation("org.hamcrest:hamcrest-library:1.3")
} }
@@ -0,0 +0,0 @@ relocation {
relocate("org.jline:jline-terminal-jansi", "org.jline" to cb("jline"))
sequenceOf(
+ "net.fabricmc:mapping-io" to "net.fabricmc.mappingio", // Paper
"commons-codec:commons-codec" to "org.apache.commons.codec",
"commons-io:commons-io" to "org.apache.commons.io",
//"it.unimi.dsi:fastutil" to "it.unimi", // Paper - don't relocate fastutil
@@ -0,0 +0,0 @@ tasks.shadowJar { @@ -0,0 +0,0 @@ tasks.shadowJar {
transform(ModifiedLog4j2PluginsCacheFileTransformer::class.java) transform(ModifiedLog4j2PluginsCacheFileTransformer::class.java)
} }
@ -168,20 +173,20 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@
+package io.papermc.paper.util; +package io.papermc.paper.util;
+ +
+import com.google.common.base.Charsets;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.mojang.datafixers.util.Pair;
+import java.io.BufferedReader;
+import java.io.IOException; +import java.io.IOException;
+import java.io.InputStream; +import java.io.InputStream;
+import java.io.InputStreamReader; +import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map; +import java.util.Map;
+import java.util.Set; +import java.util.Set;
+import net.fabricmc.mapping.tree.ClassDef; +import java.util.function.Function;
+import net.fabricmc.mapping.tree.MethodDef; +import java.util.stream.Collectors;
+import net.fabricmc.mapping.tree.TinyMappingFactory; +import net.fabricmc.mappingio.MappingReader;
+import net.fabricmc.mapping.tree.TinyTree; +import net.fabricmc.mappingio.format.MappingFormat;
+import net.fabricmc.mappingio.tree.MappingTree;
+import net.fabricmc.mappingio.tree.MemoryMappingTree;
+import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable; +import org.checkerframework.checker.nullness.qual.Nullable;
+import org.checkerframework.framework.qual.DefaultQualifier; +import org.checkerframework.framework.qual.DefaultQualifier;
@ -199,8 +204,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ ObfHelper() { + ObfHelper() {
+ final @Nullable Set<ClassMapping> maps = loadMappingsIfPresent(); + final @Nullable Set<ClassMapping> maps = loadMappingsIfPresent();
+ if (maps != null) { + if (maps != null) {
+ this.mappingsByObfName = maps.stream().collect(ImmutableMap.toImmutableMap(ClassMapping::obfName, map -> map)); + this.mappingsByObfName = maps.stream().collect(Collectors.toUnmodifiableMap(ClassMapping::obfName, map -> map));
+ this.mappingsByMojangName = maps.stream().collect(ImmutableMap.toImmutableMap(ClassMapping::mojangName, map -> map)); + this.mappingsByMojangName = maps.stream().collect(Collectors.toUnmodifiableMap(ClassMapping::mojangName, map -> map));
+ } else { + } else {
+ this.mappingsByObfName = null; + this.mappingsByObfName = null;
+ this.mappingsByMojangName = null; + this.mappingsByMojangName = null;
@ -260,34 +265,33 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ if (mappingsInputStream == null) { + if (mappingsInputStream == null) {
+ return null; + return null;
+ } + }
+ final TinyTree tree = TinyMappingFactory.loadWithDetection(new BufferedReader(new InputStreamReader(mappingsInputStream, Charsets.UTF_8))); + final MemoryMappingTree tree = new MemoryMappingTree();
+ final var builder = ImmutableSet.<ClassMapping>builder(); + MappingReader.read(new InputStreamReader(mappingsInputStream, StandardCharsets.UTF_8), MappingFormat.TINY_2, tree);
+ final Set<ClassMapping> classes = new HashSet<>();
+ +
+ for (final ClassDef classDef : tree.getClasses()) { + final StringPool pool = new StringPool();
+ final String obfClassName = classDef.getName(SPIGOT_NAMESPACE).replace('/', '.'); + for (final MappingTree.ClassMapping cls : tree.getClasses()) {
+ final var methodMappings = ImmutableMap.<Pair<String, String>, MethodMapping>builder(); + final Map<String, String> methods = new HashMap<>();
+ +
+ for (final MethodDef methodDef : classDef.getMethods()) { + for (final MappingTree.MethodMapping methodMapping : cls.getMethods()) {
+ final MethodMapping method = new MethodMapping( + methods.put(
+ methodDef.getName(SPIGOT_NAMESPACE), + pool.string(methodKey(
+ methodDef.getName(MOJANG_PLUS_YARN_NAMESPACE), + methodMapping.getName(SPIGOT_NAMESPACE),
+ methodDef.getDescriptor(SPIGOT_NAMESPACE) + methodMapping.getDesc(SPIGOT_NAMESPACE)
+ ); + )),
+ methodMappings.put( + pool.string(methodMapping.getName(MOJANG_PLUS_YARN_NAMESPACE))
+ new Pair<>(method.obfName(), method.descriptor()),
+ method
+ ); + );
+ } + }
+ +
+ final ClassMapping map = new ClassMapping( + final ClassMapping map = new ClassMapping(
+ obfClassName, + cls.getName(SPIGOT_NAMESPACE).replace('/', '.'),
+ classDef.getName(MOJANG_PLUS_YARN_NAMESPACE).replace('/', '.'), + cls.getName(MOJANG_PLUS_YARN_NAMESPACE).replace('/', '.'),
+ methodMappings.build() + Map.copyOf(methods)
+ ); + );
+ builder.add(map); + classes.add(map);
+ } + }
+ +
+ return builder.build(); + return Set.copyOf(classes);
+ } catch (final IOException ex) { + } catch (final IOException ex) {
+ System.err.println("Failed to load mappings for stacktrace deobfuscation."); + System.err.println("Failed to load mappings for stacktrace deobfuscation.");
+ ex.printStackTrace(); + ex.printStackTrace();
@ -295,16 +299,22 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ } + }
+ +
+ public static String methodKey(final String obfName, final String obfDescriptor) {
+ return obfName + obfDescriptor;
+ }
+
+ private static final class StringPool {
+ private final Map<String, String> pool = new HashMap<>();
+
+ public String string(final String string) {
+ return this.pool.computeIfAbsent(string, Function.identity());
+ }
+ }
+
+ public record ClassMapping( + public record ClassMapping(
+ String obfName, + String obfName,
+ String mojangName, + String mojangName,
+ Map<Pair<String, String>, MethodMapping> methodMappings + Map<String, String> methodsByObf
+ ) {}
+
+ public record MethodMapping(
+ String obfName,
+ String mojangName,
+ String descriptor
+ ) {} + ) {}
+} +}
diff --git a/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java diff --git a/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java
@ -316,7 +326,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+package io.papermc.paper.util; +package io.papermc.paper.util;
+ +
+import com.destroystokyo.paper.PaperConfig; +import com.destroystokyo.paper.PaperConfig;
+import com.mojang.datafixers.util.Pair;
+import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntArrayList;
+import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.ints.IntList;
+import java.io.IOException; +import java.io.IOException;
@ -337,9 +346,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+public enum StacktraceDeobfuscator { +public enum StacktraceDeobfuscator {
+ INSTANCE; + INSTANCE;
+ +
+ private final Map<Class<?>, Map<Pair<String, String>, IntList>> lineMapCache = Collections.synchronizedMap(new LinkedHashMap<>(128, 0.75f, true) { + private final Map<Class<?>, Map<String, IntList>> lineMapCache = Collections.synchronizedMap(new LinkedHashMap<>(128, 0.75f, true) {
+ @Override + @Override
+ protected boolean removeEldestEntry(final Map.Entry<Class<?>, Map<Pair<String, String>, IntList>> eldest) { + protected boolean removeEldestEntry(final Map.Entry<Class<?>, Map<String, IntList>> eldest) {
+ return this.size() > 127; + return this.size() > 127;
+ } + }
+ }); + });
@ -387,17 +396,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } catch (final ClassNotFoundException ex) { + } catch (final ClassNotFoundException ex) {
+ throw new RuntimeException(ex); + throw new RuntimeException(ex);
+ } + }
+ final @Nullable Pair<String, String> nameDescriptorPair = this.determineMethodForLine(clazz, element.getLineNumber()); + final @Nullable String methodKey = this.determineMethodForLine(clazz, element.getLineNumber());
+ final ObfHelper.@Nullable MethodMapping methodMapping = nameDescriptorPair == null + final @Nullable String mappedMethodName = methodKey == null ? null : classMapping.methodsByObf().get(methodKey);
+ ? null
+ : classMapping.methodMappings().get(nameDescriptorPair);
+ +
+ result[i] = new StackTraceElement( + result[i] = new StackTraceElement(
+ element.getClassLoaderName(), + element.getClassLoaderName(),
+ element.getModuleName(), + element.getModuleName(),
+ element.getModuleVersion(), + element.getModuleVersion(),
+ classMapping.mojangName(), + classMapping.mojangName(),
+ methodMapping != null ? methodMapping.mojangName() : methodName, + mappedMethodName != null ? mappedMethodName : methodName,
+ sourceFileName(classMapping.mojangName()), + sourceFileName(classMapping.mojangName()),
+ element.getLineNumber() + element.getLineNumber()
+ ); + );
@ -405,15 +412,15 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return result; + return result;
+ } + }
+ +
+ private @Nullable Pair<String, String> determineMethodForLine(final Class<?> clazz, final int lineNumber) { + private @Nullable String determineMethodForLine(final Class<?> clazz, final int lineNumber) {
+ final Map<Pair<String, String>, IntList> lineMap = this.lineMapCache.computeIfAbsent(clazz, StacktraceDeobfuscator::buildLineMap); + final Map<String, IntList> lineMap = this.lineMapCache.computeIfAbsent(clazz, StacktraceDeobfuscator::buildLineMap);
+ for (final var entry : lineMap.entrySet()) { + for (final var entry : lineMap.entrySet()) {
+ final Pair<String, String> pair = entry.getKey(); + final String methodKey = entry.getKey();
+ final IntList lines = entry.getValue(); + final IntList lines = entry.getValue();
+ for (int i = 0, linesSize = lines.size(); i < linesSize; i++) { + for (int i = 0, linesSize = lines.size(); i < linesSize; i++) {
+ final int num = lines.getInt(i); + final int num = lines.getInt(i);
+ if (num == lineNumber) { + if (num == lineNumber) {
+ return pair; + return methodKey;
+ } + }
+ } + }
+ } + }
@ -429,8 +436,8 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return rootClassName + ".java"; + return rootClassName + ".java";
+ } + }
+ +
+ private static Map<Pair<String, String>, IntList> buildLineMap(final Class<?> key) { + private static Map<String, IntList> buildLineMap(final Class<?> key) {
+ final Map<Pair<String, String>, IntList> lineMap = new HashMap<>(); + final Map<String, IntList> lineMap = new HashMap<>();
+ final class LineCollectingMethodVisitor extends MethodVisitor { + final class LineCollectingMethodVisitor extends MethodVisitor {
+ private final IntList lines = new IntArrayList(); + private final IntList lines = new IntArrayList();
+ private final String name; + private final String name;
@ -451,7 +458,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ @Override + @Override
+ public void visitEnd() { + public void visitEnd() {
+ super.visitEnd(); + super.visitEnd();
+ lineMap.put(new Pair<>(this.name, this.descriptor), this.lines); + lineMap.put(ObfHelper.methodKey(this.name, this.descriptor), this.lines);
+ } + }
+ } + }
+ final ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM9) { + final ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM9) {

View file

@ -10,7 +10,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+++ b/build.gradle.kts +++ b/build.gradle.kts
@@ -0,0 +0,0 @@ dependencies { @@ -0,0 +0,0 @@ dependencies {
implementation("org.quiltmc:tiny-mappings-parser:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation
+ testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test + testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test
testImplementation("junit:junit:4.13.1") testImplementation("junit:junit:4.13.1")

View file

@ -11,7 +11,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
@@ -0,0 +0,0 @@ dependencies { @@ -0,0 +0,0 @@ dependencies {
implementation("io.netty:netty-all:4.1.65.Final") // Paper implementation("io.netty:netty-all:4.1.65.Final") // Paper
implementation("org.quiltmc:tiny-mappings-parser:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation implementation("net.fabricmc:mapping-io:0.3.0") // Paper - needed to read mappings for stacktrace deobfuscation
+ implementation("com.velocitypowered:velocity-native:1.1.0-SNAPSHOT") // Paper + implementation("com.velocitypowered:velocity-native:1.1.0-SNAPSHOT") // Paper
testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test testImplementation("io.github.classgraph:classgraph:4.8.47") // Paper - mob goal test