From 168911821d8812e25fac7ae9fb6bc040288b60b4 Mon Sep 17 00:00:00 2001 From: JoJoDeveloping Date: Mon, 26 Aug 2019 15:12:19 +0200 Subject: [PATCH] Add general parameter naming --- .../oceanlabs/mcp/mcinjector/MCInjector.java | 31 +++- .../mcp/mcinjector/MCInjectorImpl.java | 13 +- .../mcp/mcinjector/adaptors/ApplyMap.java | 27 +++- .../mcp/mcinjector/data/Constructors.java | 91 ------------ .../mcp/mcinjector/data/Parameters.java | 136 ++++++++++++++++++ 5 files changed, 191 insertions(+), 107 deletions(-) delete mode 100644 src/main/java/de/oceanlabs/mcp/mcinjector/data/Constructors.java create mode 100644 src/main/java/de/oceanlabs/mcp/mcinjector/data/Parameters.java diff --git a/src/main/java/de/oceanlabs/mcp/mcinjector/MCInjector.java b/src/main/java/de/oceanlabs/mcp/mcinjector/MCInjector.java index f98c16a..67a4c4c 100644 --- a/src/main/java/de/oceanlabs/mcp/mcinjector/MCInjector.java +++ b/src/main/java/de/oceanlabs/mcp/mcinjector/MCInjector.java @@ -30,7 +30,8 @@ public class MCInjector private Path fileIn, fileOut; private Path excIn, excOut; private Path accIn, accOut; - private Path ctrIn, ctrOut; + private Path ctrIn; + private Path prmIn, prmOut; private LVTNaming lvt; public MCInjector(Path fileIn, Path fileOut) @@ -104,9 +105,15 @@ public MCInjector constructors(Path ctrs) return this; } - public MCInjector constructorsOut(Path out) + public MCInjector parameters(Path ctrs) { - this.ctrOut = out; + this.prmIn = ctrs; + return this; + } + + public MCInjector parametersOut(Path out) + { + this.prmOut = out; return this; } @@ -121,8 +128,9 @@ public void process() throws IOException { MCInjectorImpl.process(fileIn, fileOut, accIn, accOut, - ctrIn, ctrOut, + ctrIn, excIn, excOut, + prmIn, prmOut, lvt); } @@ -174,7 +182,9 @@ public static void main(String[] args) throws Exception OptionSpec acc = parser.accepts("acc") .withRequiredArg().withValuesConvertedBy(PATH_ARG); OptionSpec accOut = parser.accepts("accOut").withRequiredArg().withValuesConvertedBy(PATH_ARG); OptionSpec ctr = parser.accepts("ctr") .withRequiredArg().withValuesConvertedBy(PATH_ARG); - OptionSpec ctrOut = parser.accepts("ctrOut").withRequiredArg().withValuesConvertedBy(PATH_ARG); + OptionSpec ctrOut = parser.accepts("ctrOut").withRequiredArg().withValuesConvertedBy(PATH_ARG).describedAs("legacy, can't be used anymore"); + OptionSpec prm = parser.accepts("prm") .withRequiredArg().withValuesConvertedBy(PATH_ARG); + OptionSpec prmOut = parser.accepts("prmOut").withRequiredArg().withValuesConvertedBy(PATH_ARG); OptionSpec logLvl = parser.accepts("level") .withRequiredArg().withValuesConvertedBy(LEVEL_ARG).defaultsTo(Level.INFO); OptionSpec lvt = parser.accepts("lvt").withRequiredArg().ofType(LVTNaming.class).defaultsTo(LVTNaming.STRIP); @@ -192,6 +202,11 @@ else if (o.has(ver)) System.out.println(VERSION); return; } + else if (o.has(ctrOut)) + { + System.out.println("ctrOut is using the legacy format and is no longer supported!"); + return; + } MCInjector.LOG.setUseParentHandlers(false); MCInjector.LOG.setLevel(o.valueOf(logLvl)); @@ -205,7 +220,8 @@ else if (o.has(ver)) LOG.info("Access: " + o.valueOf(acc)); LOG.info(" " + o.valueOf(accOut)); LOG.info("Constructors: " + o.valueOf(ctr)); - LOG.info(" " + o.valueOf(ctrOut)); + LOG.info("Extra Params: " + o.valueOf(prm)); + LOG.info(" " + o.valueOf(prmOut)); LOG.info("LVT: " + o.valueOf(lvt)); try @@ -219,7 +235,8 @@ else if (o.has(ver)) .access(o.valueOf(acc)) .accessOut(o.valueOf(accOut)) .constructors(o.valueOf(ctr)) - .constructorsOut(o.valueOf(ctrOut)) + .parameters(o.valueOf(prm)) + .parametersOut(o.valueOf(prmOut)) .process(); } catch (Exception e) diff --git a/src/main/java/de/oceanlabs/mcp/mcinjector/MCInjectorImpl.java b/src/main/java/de/oceanlabs/mcp/mcinjector/MCInjectorImpl.java index c415ca5..ee1edb8 100644 --- a/src/main/java/de/oceanlabs/mcp/mcinjector/MCInjectorImpl.java +++ b/src/main/java/de/oceanlabs/mcp/mcinjector/MCInjectorImpl.java @@ -32,7 +32,7 @@ import de.oceanlabs.mcp.mcinjector.adaptors.InnerClassInitAdder; import de.oceanlabs.mcp.mcinjector.adaptors.ParameterAnnotationFixer; import de.oceanlabs.mcp.mcinjector.data.Access; -import de.oceanlabs.mcp.mcinjector.data.Constructors; +import de.oceanlabs.mcp.mcinjector.data.Parameters; import de.oceanlabs.mcp.mcinjector.data.Exceptions; import de.oceanlabs.mcp.mcinjector.lvt.LVTFernflower; import de.oceanlabs.mcp.mcinjector.lvt.LVTLvt; @@ -47,15 +47,18 @@ public class MCInjectorImpl static void process( Path in, Path out, Path accIn, Path accOut, - Path ctrIn, Path ctrOut, + Path ctrIn, Path excIn, Path excOut, + Path prmIn, Path prmOut, LVTNaming naming) throws IOException { if (accIn != null) Access.INSTANCE.load(accIn); + if (prmIn != null) + Parameters.INSTANCE.load(prmIn); if (ctrIn != null) - Constructors.INSTANCE.load(ctrIn); + Parameters.INSTANCE.loadLegacy(ctrIn); if (excIn != null) Exceptions.INSTANCE.load(excIn); @@ -69,8 +72,8 @@ static void process( if (accOut != null) Access.INSTANCE.dump(accOut); - if (ctrOut != null) - Constructors.INSTANCE.dump(ctrOut); + if (prmOut != null) + Parameters.INSTANCE.dump(prmOut); if (excOut != null) Exceptions.INSTANCE.dump(excOut); diff --git a/src/main/java/de/oceanlabs/mcp/mcinjector/adaptors/ApplyMap.java b/src/main/java/de/oceanlabs/mcp/mcinjector/adaptors/ApplyMap.java index 7e166ec..c369549 100644 --- a/src/main/java/de/oceanlabs/mcp/mcinjector/adaptors/ApplyMap.java +++ b/src/main/java/de/oceanlabs/mcp/mcinjector/adaptors/ApplyMap.java @@ -10,6 +10,7 @@ import java.util.Set; import java.util.logging.Level; +import de.oceanlabs.mcp.mcinjector.data.Parameters; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.MethodVisitor; import org.objectweb.asm.Opcodes; @@ -21,12 +22,12 @@ import de.oceanlabs.mcp.mcinjector.MCInjector; import de.oceanlabs.mcp.mcinjector.MCInjectorImpl; -import de.oceanlabs.mcp.mcinjector.data.Constructors; import de.oceanlabs.mcp.mcinjector.data.Exceptions; public class ApplyMap extends ClassVisitor { String className; + boolean isEnum; MCInjectorImpl injector; public ApplyMap(MCInjectorImpl injector, ClassVisitor cn) @@ -39,6 +40,7 @@ public ApplyMap(MCInjectorImpl injector, ClassVisitor cn) public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) { this.className = name; + isEnum = (access & Opcodes.ACC_ENUM) != 0; super.visit(version, access, name, signature, superName, interfaces); } @@ -95,9 +97,11 @@ private void processLVT(String cls, String name, String desc, MethodNode mn) { List params = new ArrayList<>(); List types = new ArrayList<>(); + boolean isStatic = true; if ((mn.access & Opcodes.ACC_STATIC) == 0) { + isStatic = false; types.add(Type.getType("L" + cls + ";")); params.add(0, "this"); } @@ -109,11 +113,12 @@ private void processLVT(String cls, String name, String desc, MethodNode mn) return; MCInjector.LOG.fine(" Generating map:"); - String nameFormat = "p_" + name + "_%d_"; + String nameFormat = null; if (name.matches("func_\\d+_.+")) // A srg name method params are just p_MethodID_ParamIndex_ nameFormat = "p_" + name.substring(5, name.indexOf('_', 5)) + "_%s_"; - else if (name.equals("")) // Every constructor is given a unique ID, try to load the ID from the map, if none is found assign a new one - nameFormat = "p_i" + Constructors.INSTANCE.getID(className, desc, types.size() > 1) + "_%s_"; + else if(!isSynthetic(mn)) + nameFormat = "p_" + Parameters.INSTANCE.getName(className, name, desc, types.size() > params.size(), isStatic) + "_%s_"; //assign new name only if there are names remaining + else nameFormat = "p_%s_"; //don't really care about synthetics for (int x = params.size(), y = x; x < types.size(); x++) { @@ -190,4 +195,18 @@ else if (tmp.getType() != AbstractInsnNode.LABEL) Collections.sort(mn.localVariables, (o1, o2) -> o1.index < o2.index ? -1 : (o1.index == o2.index ? 0 : 1)); } + + private boolean isSynthetic(MethodNode mn){ + if ((mn.access & Opcodes.ACC_SYNTHETIC) != 0) return true; + + //check for special case pursuant to JLS 13.1.7 + //which specifies that are the one and only proper methods that may be generated and not be marked synthetic + if (isEnum && (mn.access & Opcodes.ACC_STATIC) != 0) { + if ("valueOf".equals(mn.name) && mn.desc.equals("(Ljava/lang/String;)L" + className + ";")) + return true; + if("values".equals(mn.name) && mn.desc.equals("()[L" + className + ";")) + return true; + } + return false; + } } diff --git a/src/main/java/de/oceanlabs/mcp/mcinjector/data/Constructors.java b/src/main/java/de/oceanlabs/mcp/mcinjector/data/Constructors.java deleted file mode 100644 index 2ea2901..0000000 --- a/src/main/java/de/oceanlabs/mcp/mcinjector/data/Constructors.java +++ /dev/null @@ -1,91 +0,0 @@ -package de.oceanlabs.mcp.mcinjector.data; - -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.StandardOpenOption; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import de.oceanlabs.mcp.mcinjector.MCInjector; - -public enum Constructors -{ - INSTANCE; - - private Map fromDesc = new HashMap<>(); - private Map fromID = new HashMap<>(); - private int maxID = 0; - - public boolean load(Path file) - { - this.fromDesc.clear(); - this.fromID.clear(); - try - { - MCInjector.LOG.fine("Loading Constructors from: " + file); - Files.readAllLines(file).forEach(line -> - { - line = line.trim(); - if (line.isEmpty() || line.startsWith("#")) - return; - - String[] parts = line.split(" " ); - int id = Integer.parseInt(parts[0]); - MCInjector.LOG.fine(" Constructor ID loaded " + id + " " + parts[0] + " " + parts[1]); - this.setID(parts[1], parts[2], id); - }); - } - catch (IOException e) - { - e.printStackTrace(); - MCInjector.LOG.warning("Could not load Constructors list: " + e.toString()); - return false; - } - return true; - } - - public boolean dump(Path file) - { - try - { - List ret = this.fromID.entrySet().stream() - .sorted((e1, e2) -> e1.getKey().compareTo(e2.getKey())) - .map(e -> e.getKey() + " " + e.getValue()) - .collect(Collectors.toList()); - Files.write(file, String.join("\n", ret).getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE_NEW); - } - catch (IOException e) - { - e.printStackTrace(); - MCInjector.LOG.warning("Could not dump Constructors list: " + e.toString()); - return false; - } - return true; - } - - public void setID(String cls, String desc, int id) - { - if (id < 0) - throw new IllegalArgumentException("ID must be positive: " + id); - this.maxID = Math.max(this.maxID, id); - this.fromDesc.put(cls + " " + desc, id); - this.fromID .put(id, cls + " " + desc); - } - - public int getID(String cls, String desc, boolean generate) - { - Integer id = this.fromDesc.get(cls + " " + desc); - if (id == null) - { - if (!generate) - return -1; - id = ++maxID; - this.setID(cls, desc, id); - } - return id; - } -} diff --git a/src/main/java/de/oceanlabs/mcp/mcinjector/data/Parameters.java b/src/main/java/de/oceanlabs/mcp/mcinjector/data/Parameters.java new file mode 100644 index 0000000..0ed1c7e --- /dev/null +++ b/src/main/java/de/oceanlabs/mcp/mcinjector/data/Parameters.java @@ -0,0 +1,136 @@ +package de.oceanlabs.mcp.mcinjector.data; + +import de.oceanlabs.mcp.mcinjector.MCInjector; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public enum Parameters +{ + INSTANCE; + + private Map fromDesc = new HashMap<>(); + private Map fromID = new HashMap<>(); + private int maxID = 0; + + public boolean load(Path file) + { + this.fromDesc.clear(); + this.fromID.clear(); + try + { + MCInjector.LOG.fine("Loading Parameters from: " + file); + Files.readAllLines(file).forEach(line -> + { + line = line.trim(); + if (line.isEmpty() || line.startsWith("#")) + return; + + String[] parts = line.split(" " ); + int id = Integer.parseInt(parts[0].substring(1)); + char prefix = parts[0].charAt(0); + MCInjector.LOG.fine(" Method parameter ID loaded " + prefix + id + " " + parts[0] + " " + parts[1] + " " + parts[3]); + this.setName(parts[1], parts[2], parts[3], id, prefix); + }); + } + catch (IOException e) + { + e.printStackTrace(); + MCInjector.LOG.warning("Could not load Parameters list: " + e.toString()); + return false; + } + return true; + } + + public boolean loadLegacy(Path file) + { + try { + MCInjector.LOG.fine("Loading Constructors from: " + file); + Files.readAllLines(file).forEach(line -> + { + line = line.trim(); + if (line.isEmpty() || line.startsWith("#")) + return; + + String[] parts = line.split(" " ); + int id = Integer.parseInt(parts[0]); + MCInjector.LOG.fine(" Constructor ID loaded " + id + " " + parts[0] + " " + parts[1]); + this.setName(parts[1], "", parts[2], id, 'i'); + }); + return true; + } + catch (IOException e) + { + e.printStackTrace(); + MCInjector.LOG.warning("Could not import Constructors list: " + e.toString()); + return false; + } + } + + public boolean dump(Path file) + { + try + { + List ret = this.fromID.entrySet().stream() + .sorted((e1, e2) -> e1.getKey().compareTo(e2.getKey())) + .map(e -> e.getKey() + " " + e.getValue()) + .collect(Collectors.toList()); + Files.write(file, String.join("\n", ret).getBytes(StandardCharsets.UTF_8), StandardOpenOption.CREATE_NEW); + } + catch (IOException e) + { + e.printStackTrace(); + MCInjector.LOG.warning("Could not dump Parameters list: " + e.toString()); + return false; + } + return true; + } + + public void setName(String cls, String method, String desc, int id, char prefix) + { + if (id < 0) + throw new IllegalArgumentException("ID must be positive: " + id); + this.maxID = Math.max(this.maxID, id); + this.fromDesc.put(cls + " " + method + " " + desc, prefix + "" + id); + this.fromID .put(prefix + "" + id, cls + " " + method + " " + desc); + } + + public String getName(String cls, String method, String desc, boolean generate, boolean isStatic) + { + String id = this.fromDesc.get(cls + " " + method + " " + desc); + if (id == null) + { + if (!generate) + return method; //if we are not generating new names we will return the old parameter format, _p_funcname_x_ + char prefix = getPrefix(method, isStatic); + int newId = ++maxID; + this.setName(cls, method, desc, newId, prefix); + return prefix + "" + newId; + } + if(id.charAt(0) != getPrefix(method, isStatic)) + { + String num = id.substring(1); + char prefix = getPrefix(method, isStatic); + this.setName(cls, method, desc, Integer.parseInt(num), prefix); + String newID = prefix + "" + num; + MCInjector.LOG.info("Method " + cls + "." + method + desc + " has wrong name attribute, updating: " + id + " -> " + newID); + return newID; + } + return id; + } + + public char getPrefix(String name, boolean isStatic){ + if(name.equals("")) //this ensures constructors will still have the _p_i12345_x_ format + return 'i'; + if(isStatic) //since the static map does not cover these methods we encode it in the param prefix (s=static) + return 's'; + return 'e'; //while new methods named will use the _p_e12345_x_ format + } +}