Move obfhelper/stack deobf diff into original patch

This commit is contained in:
Jason Penilla 2024-04-27 13:53:56 -07:00
parent e0adb01ddc
commit e20beef9c7
4 changed files with 112 additions and 347 deletions

View File

@ -10,13 +10,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/build.gradle.kts --- a/build.gradle.kts
+++ b/build.gradle.kts +++ b/build.gradle.kts
@@ -0,0 +0,0 @@ dependencies { @@ -0,0 +0,0 @@ dependencies {
implementation("org.ow2.asm:asm-commons:9.7") testImplementation("org.mockito:mockito-core:5.11.0")
implementation("org.spongepowered:configurate-yaml:4.2.0-SNAPSHOT") // Paper - config files testImplementation("org.ow2.asm:asm-tree:9.7")
implementation("commons-lang:commons-lang:2.6") testImplementation("org.junit-pioneer:junit-pioneer:2.2.0") // Paper - CartesianTest
+ implementation("net.fabricmc:mapping-io:0.5.0") // Paper - needed to read mappings for stacktrace deobfuscation + implementation("net.neoforged:srgutils:1.0.9") // Paper - mappings handling
runtimeOnly("com.lmax:disruptor:3.4.4") // Paper }
runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.6") val craftbukkitPackageVersion = "1_20_R4" // Paper
diff --git a/src/log4jPlugins/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java b/src/log4jPlugins/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java diff --git a/src/log4jPlugins/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java b/src/log4jPlugins/java/io/papermc/paper/logging/StacktraceDeobfuscatingRewritePolicy.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
@ -99,19 +99,13 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ +
+import java.io.IOException; +import java.io.IOException;
+import java.io.InputStream; +import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap; +import java.util.HashMap;
+import java.util.HashSet; +import java.util.HashSet;
+import java.util.Map; +import java.util.Map;
+import java.util.Objects; +import java.util.Objects;
+import java.util.Set; +import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors; +import java.util.stream.Collectors;
+import net.fabricmc.mappingio.MappingReader; +import net.neoforged.srgutils.IMappingFile;
+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;
@ -120,9 +114,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+public enum ObfHelper { +public enum ObfHelper {
+ INSTANCE; + INSTANCE;
+ +
+ public static final String MOJANG_PLUS_YARN_NAMESPACE = "mojang+yarn";
+ public static final String SPIGOT_NAMESPACE = "spigot";
+
+ private final @Nullable Map<String, ClassMapping> mappingsByObfName; + private final @Nullable Map<String, ClassMapping> mappingsByObfName;
+ private final @Nullable Map<String, ClassMapping> mappingsByMojangName; + private final @Nullable Map<String, ClassMapping> mappingsByMojangName;
+ +
@ -190,56 +181,74 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ if (mappingsInputStream == null) { + if (mappingsInputStream == null) {
+ return null; + return null;
+ } + }
+ final MemoryMappingTree tree = new MemoryMappingTree(); + final IMappingFile mappings = IMappingFile.load(mappingsInputStream); // Mappings are mojang->spigot
+ MappingReader.read(new InputStreamReader(mappingsInputStream, StandardCharsets.UTF_8), MappingFormat.TINY_2_FILE, tree);
+ final Set<ClassMapping> classes = new HashSet<>(); + final Set<ClassMapping> classes = new HashSet<>();
+ +
+ final StringPool pool = new StringPool(); + final StringPool pool = new StringPool();
+ for (final MappingTree.ClassMapping cls : tree.getClasses()) { + for (final IMappingFile.IClass cls : mappings.getClasses()) {
+ final Map<String, String> methods = new HashMap<>(); + final Map<String, String> methods = new HashMap<>();
+ final Map<String, String> fields = new HashMap<>();
+ final Map<String, String> strippedMethods = new HashMap<>();
+ +
+ for (final MappingTree.MethodMapping methodMapping : cls.getMethods()) { + for (final IMappingFile.IMethod methodMapping : cls.getMethods()) {
+ methods.put( + methods.put(
+ pool.string(methodKey( + pool.string(methodKey(
+ Objects.requireNonNull(methodMapping.getName(SPIGOT_NAMESPACE)), + Objects.requireNonNull(methodMapping.getMapped()),
+ Objects.requireNonNull(methodMapping.getDesc(SPIGOT_NAMESPACE)) + Objects.requireNonNull(methodMapping.getMappedDescriptor())
+ )), + )),
+ pool.string(Objects.requireNonNull(methodMapping.getName(MOJANG_PLUS_YARN_NAMESPACE))) + pool.string(Objects.requireNonNull(methodMapping.getOriginal()))
+ );
+
+ strippedMethods.put(
+ pool.string(pool.string(strippedMethodKey(
+ methodMapping.getMapped(),
+ methodMapping.getDescriptor()
+ ))),
+ pool.string(methodMapping.getOriginal())
+ );
+ }
+ for (final IMappingFile.IField field : cls.getFields()) {
+ fields.put(
+ pool.string(field.getMapped()),
+ pool.string(field.getOriginal())
+ ); + );
+ } + }
+ +
+ final ClassMapping map = new ClassMapping( + final ClassMapping map = new ClassMapping(
+ Objects.requireNonNull(cls.getName(SPIGOT_NAMESPACE)).replace('/', '.'), + Objects.requireNonNull(cls.getMapped()).replace('/', '.'),
+ Objects.requireNonNull(cls.getName(MOJANG_PLUS_YARN_NAMESPACE)).replace('/', '.'), + Objects.requireNonNull(cls.getOriginal()).replace('/', '.'),
+ Map.copyOf(methods) + Map.copyOf(methods),
+ Map.copyOf(fields),
+ Map.copyOf(strippedMethods)
+ ); + );
+ classes.add(map); + classes.add(map);
+ } + }
+ +
+ return Set.copyOf(classes); + 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.");
+ ex.printStackTrace(); + ex.printStackTrace();
+ return null; + return null;
+ } + }
+ } + }
+ +
+ public static String methodKey(final String obfName, final String obfDescriptor) { + public static String strippedMethodKey(final String methodName, final String methodDescriptor) {
+ return obfName + obfDescriptor; + final String methodKey = methodKey(methodName, methodDescriptor);
+ final int returnDescriptorEnd = methodKey.indexOf(')');
+ return methodKey.substring(0, returnDescriptorEnd + 1);
+ } + }
+ +
+ private static final class StringPool { + public static String methodKey(final String methodName, final String methodDescriptor) {
+ private final Map<String, String> pool = new HashMap<>(); + return methodName + methodDescriptor;
+
+ 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<String, String> methodsByObf + Map<String, String> methodsByObf,
+ Map<String, String> fieldsByObf,
+ // obf name with mapped desc to mapped name. return value is excluded from desc as reflection doesn't use it
+ Map<String, String> strippedMethods
+ ) {} + ) {}
+} +}
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
@ -251,12 +260,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+package io.papermc.paper.util; +package io.papermc.paper.util;
+ +
+import io.papermc.paper.configuration.GlobalConfiguration; +import io.papermc.paper.configuration.GlobalConfiguration;
+import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
+import java.io.IOException; +import java.io.IOException;
+import java.io.InputStream; +import java.io.InputStream;
+import java.util.Collections; +import java.util.Collections;
+import java.util.HashMap;
+import java.util.LinkedHashMap; +import java.util.LinkedHashMap;
+import java.util.Map; +import java.util.Map;
+import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.NonNull;
@ -272,9 +280,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+public enum StacktraceDeobfuscator { +public enum StacktraceDeobfuscator {
+ INSTANCE; + INSTANCE;
+ +
+ private final Map<Class<?>, Map<String, IntList>> lineMapCache = Collections.synchronizedMap(new LinkedHashMap<>(128, 0.75f, true) { + private final Map<Class<?>, Int2ObjectMap<String>> lineMapCache = Collections.synchronizedMap(new LinkedHashMap<>(128, 0.75f, true) {
+ @Override + @Override
+ protected boolean removeEldestEntry(final Map.Entry<Class<?>, Map<String, IntList>> eldest) { + protected boolean removeEldestEntry(final Map.Entry<Class<?>, Int2ObjectMap<String>> eldest) {
+ return this.size() > 127; + return this.size() > 127;
+ } + }
+ }); + });
@ -339,18 +347,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ +
+ private @Nullable String determineMethodForLine(final Class<?> clazz, final int lineNumber) { + private @Nullable String determineMethodForLine(final Class<?> clazz, final int lineNumber) {
+ final Map<String, IntList> lineMap = this.lineMapCache.computeIfAbsent(clazz, StacktraceDeobfuscator::buildLineMap); + return this.lineMapCache.computeIfAbsent(clazz, StacktraceDeobfuscator::buildLineMap).get(lineNumber);
+ for (final var entry : lineMap.entrySet()) {
+ final String methodKey = entry.getKey();
+ final IntList lines = entry.getValue();
+ for (int i = 0, linesSize = lines.size(); i < linesSize; i++) {
+ final int num = lines.getInt(i);
+ if (num == lineNumber) {
+ return methodKey;
+ }
+ }
+ }
+ return null;
+ } + }
+ +
+ private static String sourceFileName(final String fullClassName) { + private static String sourceFileName(final String fullClassName) {
@ -362,34 +359,27 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return rootClassName + ".java"; + return rootClassName + ".java";
+ } + }
+ +
+ private static Map<String, IntList> buildLineMap(final Class<?> key) { + private static Int2ObjectMap<String> buildLineMap(final Class<?> key) {
+ final Map<String, IntList> lineMap = new HashMap<>(); + final StringPool pool = new StringPool();
+ final Int2ObjectMap<String> lineMap = new Int2ObjectOpenHashMap<>();
+ final class LineCollectingMethodVisitor extends MethodVisitor { + final class LineCollectingMethodVisitor extends MethodVisitor {
+ private final IntList lines = new IntArrayList();
+ private final String name; + private final String name;
+ private final String descriptor; + private final String descriptor;
+ +
+ LineCollectingMethodVisitor(String name, String descriptor) { + LineCollectingMethodVisitor(final String name, final String descriptor) {
+ super(Opcodes.ASM9); + super(Opcodes.ASM9);
+ this.name = name; + this.name = name;
+ this.descriptor = descriptor; + this.descriptor = descriptor;
+ } + }
+ +
+ @Override + @Override
+ public void visitLineNumber(int line, Label start) { + public void visitLineNumber(final int line, final Label start) {
+ super.visitLineNumber(line, start); + lineMap.put(line, pool.string(ObfHelper.methodKey(this.name, this.descriptor)));
+ this.lines.add(line);
+ }
+
+ @Override
+ public void visitEnd() {
+ super.visitEnd();
+ lineMap.put(ObfHelper.methodKey(this.name, this.descriptor), this.lines);
+ } + }
+ } + }
+ final ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM9) { + final ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM9) {
+ @Override + @Override
+ public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) { + public MethodVisitor visitMethod(final int access, final String name, final String descriptor, final String signature, final String[] exceptions) {
+ return new LineCollectingMethodVisitor(name, descriptor); + return new LineCollectingMethodVisitor(name, descriptor);
+ } + }
+ }; + };
@ -411,6 +401,46 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return lineMap; + return lineMap;
+ } + }
+} +}
diff --git a/src/main/java/io/papermc/paper/util/StringPool.java b/src/main/java/io/papermc/paper/util/StringPool.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/StringPool.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+/**
+ * De-duplicates {@link String} instances without using {@link String#intern()}.
+ *
+ * <p>Interning may not be desired as we may want to use the heap for our pool,
+ * so it can be garbage collected as normal, etc.</p>
+ *
+ * <p>Additionally, interning can be slow due to the potentially large size of the
+ * pool (as it is shared for the entire JVM), and because most JVMs implement
+ * it using JNI.</p>
+ */
+@DefaultQualifier(NonNull.class)
+public final class StringPool {
+ private final Map<String, String> pool;
+
+ public StringPool() {
+ this(new HashMap<>());
+ }
+
+ public StringPool(final Map<String, String> map) {
+ this.pool = map;
+ }
+
+ public String string(final String string) {
+ return this.pool.computeIfAbsent(string, Function.identity());
+ }
+}
diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java diff --git a/src/main/java/net/minecraft/CrashReport.java b/src/main/java/net/minecraft/CrashReport.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/CrashReport.java --- a/src/main/java/net/minecraft/CrashReport.java

View File

@ -10,11 +10,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
--- a/build.gradle.kts --- a/build.gradle.kts
+++ b/build.gradle.kts +++ b/build.gradle.kts
@@ -0,0 +0,0 @@ dependencies { @@ -0,0 +0,0 @@ dependencies {
testImplementation("org.mockito:mockito-core:5.11.0")
testImplementation("org.ow2.asm:asm-tree:9.7") testImplementation("org.ow2.asm:asm-tree:9.7")
testImplementation("org.junit-pioneer:junit-pioneer:2.2.0") // Paper - CartesianTest testImplementation("org.junit-pioneer:junit-pioneer:2.2.0") // Paper - CartesianTest
implementation("net.neoforged:srgutils:1.0.9") // Paper - mappings handling
+ implementation("net.neoforged:AutoRenamingTool:2.0.3") // Paper - remap plugins + implementation("net.neoforged:AutoRenamingTool:2.0.3") // Paper - remap plugins
+ implementation("net.neoforged:srgutils:1.0.9") // Paper - remap plugins - bump transitive of ART
+} +}
+ +
+paperweight { +paperweight {
@ -38,9 +37,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
runtime.filterNot { it.asFile.absolutePath == vanilla } runtime.filterNot { it.asFile.absolutePath == vanilla }
} }
-tasks.registerRunTask("runShadow") { -tasks.registerRunTask("runServerJar") {
- description = "Spin up a test server from the shadowJar archiveFile" - description = "Spin up a test server from the serverJar archiveFile"
- classpath(tasks.shadowJar.flatMap { it.archiveFile }) - classpath(tasks.serverJar.flatMap { it.archiveFile })
+tasks.registerRunTask("runServer") { +tasks.registerRunTask("runServer") {
+ description = "Spin up a test server from the Mojang mapped server jar" + description = "Spin up a test server from the Mojang mapped server jar"
+ classpath(tasks.includeMappings.flatMap { it.outputJar }) + classpath(tasks.includeMappings.flatMap { it.outputJar })
@ -1377,9 +1376,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return null; + return null;
+ } + }
+ try (final InputStream mappingsInputStream = MappingEnvironment.mappingsStream()) { + try (final InputStream mappingsInputStream = MappingEnvironment.mappingsStream()) {
final MemoryMappingTree tree = new MemoryMappingTree(); final IMappingFile mappings = IMappingFile.load(mappingsInputStream); // Mappings are mojang->spigot
MappingReader.read(new InputStreamReader(mappingsInputStream, StandardCharsets.UTF_8), MappingFormat.TINY_2_FILE, tree);
final Set<ClassMapping> classes = new HashSet<>(); final Set<ClassMapping> classes = new HashSet<>();
diff --git a/src/main/java/io/papermc/paper/util/concurrent/ScalingThreadPool.java b/src/main/java/io/papermc/paper/util/concurrent/ScalingThreadPool.java diff --git a/src/main/java/io/papermc/paper/util/concurrent/ScalingThreadPool.java b/src/main/java/io/papermc/paper/util/concurrent/ScalingThreadPool.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000

View File

@ -9,18 +9,10 @@ diff --git a/build.gradle.kts b/build.gradle.kts
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/build.gradle.kts --- a/build.gradle.kts
+++ b/build.gradle.kts +++ b/build.gradle.kts
@@ -0,0 +0,0 @@ dependencies {
implementation("org.ow2.asm:asm-commons:9.7")
implementation("org.spongepowered:configurate-yaml:4.2.0-SNAPSHOT") // Paper - config files
implementation("commons-lang:commons-lang:2.6")
- implementation("net.fabricmc:mapping-io:0.5.0") // Paper - needed to read mappings for stacktrace deobfuscation
runtimeOnly("com.lmax:disruptor:3.4.4") // Paper
runtimeOnly("org.apache.maven:maven-resolver-provider:3.9.6")
@@ -0,0 +0,0 @@ dependencies { @@ -0,0 +0,0 @@ dependencies {
testImplementation("org.junit-pioneer:junit-pioneer:2.2.0") // Paper - CartesianTest testImplementation("org.junit-pioneer:junit-pioneer:2.2.0") // Paper - CartesianTest
implementation("net.neoforged:srgutils:1.0.9") // Paper - mappings handling
implementation("net.neoforged:AutoRenamingTool:2.0.3") // Paper - remap plugins implementation("net.neoforged:AutoRenamingTool:2.0.3") // Paper - remap plugins
implementation("net.neoforged:srgutils:1.0.9") // Paper - remap plugins - bump transitive of ART
+ // Paper start - Remap reflection + // Paper start - Remap reflection
+ val reflectionRewriterVersion = "0.0.1" + val reflectionRewriterVersion = "0.0.1"
+ implementation("io.papermc:reflection-rewriter:$reflectionRewriterVersion") + implementation("io.papermc:reflection-rewriter:$reflectionRewriterVersion")
@ -364,165 +356,11 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
private static final @Nullable String MAPPINGS_HASH = readMappingsHash(); private static final @Nullable String MAPPINGS_HASH = readMappingsHash();
private static final boolean REOBF = checkReobf(); private static final boolean REOBF = checkReobf();
diff --git a/src/main/java/io/papermc/paper/util/ObfHelper.java b/src/main/java/io/papermc/paper/util/ObfHelper.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/io/papermc/paper/util/ObfHelper.java
+++ b/src/main/java/io/papermc/paper/util/ObfHelper.java
@@ -0,0 +0,0 @@ package io.papermc.paper.util;
import java.io.IOException;
import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
-import java.util.function.Function;
import java.util.stream.Collectors;
-import net.fabricmc.mappingio.MappingReader;
-import net.fabricmc.mappingio.format.MappingFormat;
-import net.fabricmc.mappingio.tree.MappingTree;
-import net.fabricmc.mappingio.tree.MemoryMappingTree;
+import net.neoforged.srgutils.IMappingFile;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.checkerframework.framework.qual.DefaultQualifier;
@@ -0,0 +0,0 @@ import org.checkerframework.framework.qual.DefaultQualifier;
public enum ObfHelper {
INSTANCE;
- public static final String MOJANG_PLUS_YARN_NAMESPACE = "mojang+yarn";
- public static final String SPIGOT_NAMESPACE = "spigot";
-
private final @Nullable Map<String, ClassMapping> mappingsByObfName;
private final @Nullable Map<String, ClassMapping> mappingsByMojangName;
@@ -0,0 +0,0 @@ public enum ObfHelper {
return null;
}
try (final InputStream mappingsInputStream = MappingEnvironment.mappingsStream()) {
- final MemoryMappingTree tree = new MemoryMappingTree();
- MappingReader.read(new InputStreamReader(mappingsInputStream, StandardCharsets.UTF_8), MappingFormat.TINY_2_FILE, tree);
+ final IMappingFile mappings = IMappingFile.load(mappingsInputStream); // Mappings are mojang->spigot
final Set<ClassMapping> classes = new HashSet<>();
final StringPool pool = new StringPool();
- for (final MappingTree.ClassMapping cls : tree.getClasses()) {
+ for (final IMappingFile.IClass cls : mappings.getClasses()) {
final Map<String, String> methods = new HashMap<>();
+ final Map<String, String> fields = new HashMap<>();
+ final Map<String, String> strippedMethods = new HashMap<>();
- for (final MappingTree.MethodMapping methodMapping : cls.getMethods()) {
+ for (final IMappingFile.IMethod methodMapping : cls.getMethods()) {
methods.put(
pool.string(methodKey(
- Objects.requireNonNull(methodMapping.getName(SPIGOT_NAMESPACE)),
- Objects.requireNonNull(methodMapping.getDesc(SPIGOT_NAMESPACE))
+ Objects.requireNonNull(methodMapping.getMapped()),
+ Objects.requireNonNull(methodMapping.getMappedDescriptor())
)),
- pool.string(Objects.requireNonNull(methodMapping.getName(MOJANG_PLUS_YARN_NAMESPACE)))
+ pool.string(Objects.requireNonNull(methodMapping.getOriginal()))
+ );
+
+ strippedMethods.put(
+ pool.string(pool.string(strippedMethodKey(
+ methodMapping.getMapped(),
+ methodMapping.getDescriptor()
+ ))),
+ pool.string(methodMapping.getOriginal())
+ );
+ }
+ for (final IMappingFile.IField field : cls.getFields()) {
+ fields.put(
+ pool.string(field.getMapped()),
+ pool.string(field.getOriginal())
);
}
final ClassMapping map = new ClassMapping(
- Objects.requireNonNull(cls.getName(SPIGOT_NAMESPACE)).replace('/', '.'),
- Objects.requireNonNull(cls.getName(MOJANG_PLUS_YARN_NAMESPACE)).replace('/', '.'),
- Map.copyOf(methods)
+ Objects.requireNonNull(cls.getMapped()).replace('/', '.'),
+ Objects.requireNonNull(cls.getOriginal()).replace('/', '.'),
+ Map.copyOf(methods),
+ Map.copyOf(fields),
+ Map.copyOf(strippedMethods)
);
classes.add(map);
}
return Set.copyOf(classes);
} catch (final IOException ex) {
- System.err.println("Failed to load mappings for stacktrace deobfuscation.");
+ System.err.println("Failed to load mappings.");
ex.printStackTrace();
return null;
}
}
- public static String methodKey(final String obfName, final String obfDescriptor) {
- return obfName + obfDescriptor;
+ public static String strippedMethodKey(final String methodName, final String methodDescriptor) {
+ final String methodKey = methodKey(methodName, methodDescriptor);
+ final int returnDescriptorEnd = methodKey.indexOf(')');
+ return methodKey.substring(0, returnDescriptorEnd + 1);
}
- 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 static String methodKey(final String methodName, final String methodDescriptor) {
+ return methodName + methodDescriptor;
}
public record ClassMapping(
String obfName,
String mojangName,
- Map<String, String> methodsByObf
+ Map<String, String> methodsByObf,
+ Map<String, String> fieldsByObf,
+ // obf name with mapped desc to mapped name. return value is excluded from desc as reflection doesn't use it
+ Map<String, String> strippedMethods
) {}
}
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
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java --- a/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java
+++ b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java +++ b/src/main/java/io/papermc/paper/util/StacktraceDeobfuscator.java
@@ -0,0 +0,0 @@ @@ -0,0 +0,0 @@ public enum StacktraceDeobfuscator {
package io.papermc.paper.util;
import io.papermc.paper.configuration.GlobalConfiguration;
-import it.unimi.dsi.fastutil.ints.IntArrayList;
-import it.unimi.dsi.fastutil.ints.IntList;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import java.io.IOException;
import java.io.InputStream;
import java.util.Collections;
-import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import org.checkerframework.checker.nullness.qual.NonNull;
@@ -0,0 +0,0 @@ import org.objectweb.asm.Opcodes;
public enum StacktraceDeobfuscator {
INSTANCE;
- private final Map<Class<?>, Map<String, IntList>> lineMapCache = Collections.synchronizedMap(new LinkedHashMap<>(128, 0.75f, true) {
+ private final Map<Class<?>, Int2ObjectMap<String>> lineMapCache = Collections.synchronizedMap(new LinkedHashMap<>(128, 0.75f, true) {
@Override
- protected boolean removeEldestEntry(final Map.Entry<Class<?>, Map<String, IntList>> eldest) {
+ protected boolean removeEldestEntry(final Map.Entry<Class<?>, Int2ObjectMap<String>> eldest) {
return this.size() > 127;
}
}); });
public void deobfuscateThrowable(final Throwable throwable) { public void deobfuscateThrowable(final Throwable throwable) {
@ -542,108 +380,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
if (GlobalConfiguration.get() != null && !GlobalConfiguration.get().logging.deobfuscateStacktraces) { // handle null as true if (GlobalConfiguration.get() != null && !GlobalConfiguration.get().logging.deobfuscateStacktraces) { // handle null as true
return traceElements; return traceElements;
} }
@@ -0,0 +0,0 @@ public enum StacktraceDeobfuscator {
}
private @Nullable String determineMethodForLine(final Class<?> clazz, final int lineNumber) {
- final Map<String, IntList> lineMap = this.lineMapCache.computeIfAbsent(clazz, StacktraceDeobfuscator::buildLineMap);
- for (final var entry : lineMap.entrySet()) {
- final String methodKey = entry.getKey();
- final IntList lines = entry.getValue();
- for (int i = 0, linesSize = lines.size(); i < linesSize; i++) {
- final int num = lines.getInt(i);
- if (num == lineNumber) {
- return methodKey;
- }
- }
- }
- return null;
+ return this.lineMapCache.computeIfAbsent(clazz, StacktraceDeobfuscator::buildLineMap).get(lineNumber);
}
private static String sourceFileName(final String fullClassName) {
@@ -0,0 +0,0 @@ public enum StacktraceDeobfuscator {
return rootClassName + ".java";
}
- private static Map<String, IntList> buildLineMap(final Class<?> key) {
- final Map<String, IntList> lineMap = new HashMap<>();
+ private static Int2ObjectMap<String> buildLineMap(final Class<?> key) {
+ final StringPool pool = new StringPool();
+ final Int2ObjectMap<String> lineMap = new Int2ObjectOpenHashMap<>();
final class LineCollectingMethodVisitor extends MethodVisitor {
- private final IntList lines = new IntArrayList();
private final String name;
private final String descriptor;
- LineCollectingMethodVisitor(String name, String descriptor) {
+ LineCollectingMethodVisitor(final String name, final String descriptor) {
super(Opcodes.ASM9);
this.name = name;
this.descriptor = descriptor;
}
@Override
- public void visitLineNumber(int line, Label start) {
- super.visitLineNumber(line, start);
- this.lines.add(line);
- }
-
- @Override
- public void visitEnd() {
- super.visitEnd();
- lineMap.put(ObfHelper.methodKey(this.name, this.descriptor), this.lines);
+ public void visitLineNumber(final int line, final Label start) {
+ lineMap.put(line, pool.string(ObfHelper.methodKey(this.name, this.descriptor)));
}
}
final ClassVisitor classVisitor = new ClassVisitor(Opcodes.ASM9) {
@Override
- public MethodVisitor visitMethod(int access, String name, String descriptor, String signature, String[] exceptions) {
+ public MethodVisitor visitMethod(final int access, final String name, final String descriptor, final String signature, final String[] exceptions) {
return new LineCollectingMethodVisitor(name, descriptor);
}
};
diff --git a/src/main/java/io/papermc/paper/util/StringPool.java b/src/main/java/io/papermc/paper/util/StringPool.java
new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
--- /dev/null
+++ b/src/main/java/io/papermc/paper/util/StringPool.java
@@ -0,0 +0,0 @@
+package io.papermc.paper.util;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.Function;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.framework.qual.DefaultQualifier;
+
+/**
+ * De-duplicates {@link String} instances without using {@link String#intern()}.
+ *
+ * <p>Interning may not be desired as we may want to use the heap for our pool,
+ * so it can be garbage collected as normal, etc.</p>
+ *
+ * <p>Additionally, interning can be slow due to the potentially large size of the
+ * pool (as it is shared for the entire JVM), and because most JVMs implement
+ * it using JNI.</p>
+ */
+@DefaultQualifier(NonNull.class)
+public final class StringPool {
+ private final Map<String, String> pool;
+
+ public StringPool() {
+ this(new HashMap<>());
+ }
+
+ public StringPool(final Map<String, String> map) {
+ this.pool = map;
+ }
+
+ public String string(final String string) {
+ return this.pool.computeIfAbsent(string, Function.identity());
+ }
+}
diff --git a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java diff --git a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java b/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java --- a/src/main/java/net/minecraft/world/level/redstone/CollectingNeighborUpdater.java

View File

@ -135,9 +135,9 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ runtime.filterNot { it.asFile.absolutePath == vanilla } + runtime.filterNot { it.asFile.absolutePath == vanilla }
+ } + }
+ +
+tasks.registerRunTask("runShadow") { +tasks.registerRunTask("runServerJar") {
+ description = "Spin up a test server from the shadowJar archiveFile" + description = "Spin up a test server from the serverJar archiveFile"
+ classpath(tasks.shadowJar.flatMap { it.archiveFile }) + classpath(tasks.serverJar.flatMap { it.archiveFile })
+ classpath(runtimeClasspathWithoutVanillaServer) + classpath(runtimeClasspathWithoutVanillaServer)
+} +}
+ +