From 056817d9676a557d55052eaaa0933f8eaae23ed5 Mon Sep 17 00:00:00 2001 From: Jonathing Date: Sun, 22 Dec 2024 23:18:27 -0500 Subject: [PATCH 1/3] Mention workaround to #68 in apiNote of listOf() --- src/main/java/net/minecraftforge/coremod/api/ASMAPI.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java b/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java index e310141..06965ac 100644 --- a/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java +++ b/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java @@ -40,6 +40,10 @@ public class ASMAPI { * * @param nodes The instructions you want to add * @return A new list with the instructions + * + * @apiNote Due to a bug in Nashorn, invoking this method from your CoreMod with a very large array (or varargs) + * will not work due to it being cast to {@code Object[]}. In that case, you will need to wrap this method + * like this: {@code ASMAPI.listOf(Java.to([...], Java.type('org.objectweb.asm.tree.AbstractInsnNode[]')))}. */ public static InsnList listOf(AbstractInsnNode... nodes) { InsnList list = new InsnList(); From 72ab24c7d695b56c74fc94be401fc2162df2d6a2 Mon Sep 17 00:00:00 2001 From: Jonathing Date: Sun, 22 Dec 2024 23:44:00 -0500 Subject: [PATCH 2/3] stray javadoc cleanup + injectMethodCall change --- src/main/java/net/minecraftforge/coremod/api/ASMAPI.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java b/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java index 06965ac..bb0156f 100644 --- a/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java +++ b/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java @@ -112,6 +112,7 @@ public static boolean insertInsn(MethodNode method, MethodType type, String owne * Inserts/replaces an instruction list, with respect to the given {@link InsertMode}, on the given instruction. * * @param method The method to insert the list into + * @param insn The instruction where the list should be inserted into * @param list The list to be inserted * @param mode How the list should be inserted * @return {@code true} if the list was inserted, {@code false} otherwise @@ -163,7 +164,7 @@ public static boolean insertInsnList(MethodNode method, MethodType type, String * @param insn The method call to inject */ public static void injectMethodCall(MethodNode method, MethodInsnNode insn) { - method.instructions.insertBefore(method.instructions.getFirst(), insn); + ASMAPI.insertInsn(method, method.instructions.getFirst(), insn, InsertMode.INSERT_BEFORE); } /** @@ -418,7 +419,7 @@ public int get() { /** * Finds the first method call in the given method matching the given type, owner, name and descriptor after the - * instruction given index. + * given index. * * @param method the method to search in * @param type the type of method call to search for @@ -484,7 +485,7 @@ public int get() { /** * Finds the first field call in the given method matching the given opcode, owner, name and descriptor after the - * instruction given index. + * given index. * * @param method the method to search in * @param opcode the opcode of field call to search for From 6da95484a7e4a0838aadc7e705362f75c5194fc4 Mon Sep 17 00:00:00 2001 From: Jonathing Date: Sun, 22 Dec 2024 23:44:18 -0500 Subject: [PATCH 3/3] add methods that use insn instead of index, or vice versa --- .../minecraftforge/coremod/api/ASMAPI.java | 183 ++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java b/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java index bb0156f..4899cfe 100644 --- a/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java +++ b/src/main/java/net/minecraftforge/coremod/api/ASMAPI.java @@ -82,6 +82,21 @@ public static boolean insertInsn(MethodNode method, AbstractInsnNode insn, Abstr return true; } + /** + * Inserts/replaces an instruction, with respect to the given {@link InsertMode}, on the given index. + * + * @param method The method to insert the instruction into + * @param index The index where the new instruction should be inserted into + * @param toInsert The instruction to be inserted + * @param mode How the instruction should be inserted + * @return {@code true} if the list was inserted, {@code false} otherwise + */ + public static boolean insertInsn(MethodNode method, int index, AbstractInsnNode toInsert, InsertMode mode) { + index = clamp(index, 0, method.instructions.size()); + var insn = method.instructions.get(index); + return insertInsn(method, insn, toInsert, mode); + } + /** * Inserts/replaces an instruction, with respect to the given {@link InsertMode}, on the first * {@link MethodInsnNode} that matches the parameters of these functions in the method provided. Only the first @@ -131,6 +146,19 @@ public static boolean insertInsnList(MethodNode method, AbstractInsnNode insn, I return true; } + /** + * Inserts/replaces an instruction list, with respect to the given {@link InsertMode}, on the given index. + * + * @param method The method to insert the list into + * @param index The index where the list should be inserted into + * @param list The list to be inserted + * @param mode How the list should be inserted + * @return {@code true} if the list was inserted, {@code false} otherwise + */ + public static boolean insertInsnList(MethodNode method, int index, InsnList list, InsertMode mode) { + return insertInsnList(method, method.instructions.get(clamp(index, 0, method.instructions.size())), list, mode); + } + /** * Inserts/replaces an instruction list, with respect to the given {@link InsertMode}, on the first * {@link MethodInsnNode} that matches the parameters of these functions in the method provided. Only the first @@ -268,6 +296,18 @@ public int get() { return findFirstInstructionAfter(method, opcode, null, startIndex); } + /** + * Finds the first instruction with matching opcode after the given start instruction. + * + * @param method the method to search in + * @param opcode the opcode to search for + * @param startInsn the instruction to start search after (inclusive) + * @return the found instruction node or {@code null} if none matched after the given index + */ + public static @Nullable AbstractInsnNode findFirstInstructionAfter(MethodNode method, int opcode, AbstractInsnNode startInsn) { + return findFirstInstructionAfter(method, opcode, method.instructions.indexOf(startInsn)); + } + /** * Finds the first instruction with matching instruction type after the given start index. * @@ -280,6 +320,18 @@ public int get() { return findFirstInstructionAfter(method, -2, type, startIndex); } + /** + * Finds the first instruction with matching instruction type after the given start instruction. + * + * @param method the method to search in + * @param type the instruction type to search for + * @param startInsn the instruction to start search after (inclusive) + * @return the found instruction node or {@code null} if none matched after the given index + */ + public static @Nullable AbstractInsnNode findFirstInstructionAfter(MethodNode method, InsnType type, AbstractInsnNode startInsn) { + return findFirstInstructionAfter(method, type, method.instructions.indexOf(startInsn)); + } + /** * Finds the first instruction with matching opcode and instruction type after the given start index. * @@ -301,6 +353,19 @@ public int get() { return null; } + /** + * Finds the first instruction with matching opcode and instruction type after the given start instruction. + * + * @param method the method to search in + * @param opcode the opcode to search for + * @param type the instruction type to search for + * @param startInsn the instruction to start search after (inclusive) + * @return the found instruction node or {@code null} if none matched after the given index + */ + public static @Nullable AbstractInsnNode findFirstInstructionAfter(MethodNode method, int opcode, @Nullable InsnType type, AbstractInsnNode startInsn) { + return findFirstInstructionAfter(method, opcode, type, method.instructions.indexOf(startInsn)); + } + /** * Finds the first instruction with matching opcode before the given index in reverse search. * @@ -318,6 +383,21 @@ public int get() { return findFirstInstructionBefore(method, opcode, null, startIndex); } + /** + * Finds the first instruction with matching opcode before the given instruction in reverse search. + * + * @param method the method to search in + * @param opcode the opcode to search for + * @param startInsn the instruction at which to start searching (inclusive) + * @return the found instruction node or {@code null} if none matched before the given startIndex + * + * @apiNote Since this method is new, it will automatically apply the fixed logic in + * {@link #findFirstInstructionBefore(MethodNode, int, InsnType, int, boolean)}. + */ + public static @Nullable AbstractInsnNode findFirstInstructionBefore(MethodNode method, int opcode, AbstractInsnNode startInsn) { + return findFirstInstructionBefore(method, opcode, null, startInsn); + } + /** * Finds the first instruction with matching instruction type before the given index in reverse search. * @@ -335,6 +415,21 @@ public int get() { return findFirstInstructionBefore(method, -2, type, startIndex); } + /** + * Finds the first instruction with matching instruction type before the given instruction in reverse search. + * + * @param method the method to search in + * @param type the instruction type to search for + * @param startInsn the index at which to start searching (inclusive) + * @return the found instruction node or {@code null} if none matched before the given startIndex + * + * @apiNote Since this method is new, it will automatically apply the fixed logic in + * {@link #findFirstInstructionBefore(MethodNode, int, InsnType, int, boolean)}. + */ + public static @Nullable AbstractInsnNode findFirstInstructionBefore(MethodNode method, InsnType type, AbstractInsnNode startInsn) { + return findFirstInstructionBefore(method, -2, type, startInsn); + } + /** * Finds the first instruction with matching opcode before the given index in reverse search. * @@ -381,6 +476,22 @@ public int get() { return findFirstInstructionBefore(method, opCode, type, startIndex, !CoreModEngine.DO_NOT_FIX_INSNBEFORE); } + /** + * Finds the first instruction with matching opcode and instruction type before the given instruction in reverse + * search. + * + * @param method the method to search in + * @param opCode the opcode to search for + * @param startInsn the instruction at which to start searching (inclusive) + * @return the found instruction node or {@code null} if none matched before the given startIndex + * + * @apiNote Since this method is new, it will automatically apply the fixed logic in + * {@link #findFirstInstructionBefore(MethodNode, int, InsnType, int, boolean)}. + */ + public static @Nullable AbstractInsnNode findFirstInstructionBefore(MethodNode method, int opCode, @Nullable InsnType type, AbstractInsnNode startInsn) { + return findFirstInstructionBefore(method, opCode, type, method.instructions.indexOf(startInsn), true); + } + /** * Finds the first instruction with matching opcode and instruction type before the given index in reverse search. * @@ -443,6 +554,22 @@ public int get() { return null; } + /** + * Finds the first method call in the given method matching the given type, owner, name and descriptor after the + * given instruction. + * + * @param method the method to search in + * @param type the type of method call to search for + * @param owner the method call's owner to search for + * @param name the method call's name + * @param descriptor the method call's descriptor + * @param insn the instruction after which to start searching (inclusive) + * @return the found method call node, {@code null} if none matched after the given index + */ + public static @Nullable MethodInsnNode findFirstMethodCallAfter(MethodNode method, MethodType type, String owner, String name, String descriptor, AbstractInsnNode insn) { + return findFirstMethodCallAfter(method, type, owner, name, descriptor, method.instructions.indexOf(insn)); + } + /** * Finds the first method call in the given method matching the given type, owner, name and descriptor before the * given index in reverse search. @@ -469,6 +596,22 @@ public int get() { return null; } + /** + * Finds the first method call in the given method matching the given type, owner, name and descriptor before the + * given instruction in reverse search. + * + * @param method the method to search in + * @param type the type of method call to search for + * @param owner the method call's owner to search for + * @param name the method call's name + * @param descriptor the method call's descriptor + * @param insn the instruction at which to start searching (inclusive) + * @return the found method call node or {@code null} if none matched before the given startIndex + */ + public static @Nullable MethodInsnNode findFirstMethodCallBefore(MethodNode method, MethodType type, String owner, String name, String descriptor, AbstractInsnNode insn) { + return findFirstMethodCallBefore(method, type, owner, name, descriptor, method.instructions.indexOf(insn)); + } + /** * Finds the first field call in the given method matching the given opcode, owner, name and descriptor. * @@ -508,6 +651,22 @@ public int get() { return null; } + /** + * Finds the first field call in the given method matching the given opcode, owner, name and descriptor after the + * given instruction. + * + * @param method the method to search in + * @param opcode the opcode of field call to search for + * @param owner the method call's owner to search for + * @param name the method call's name + * @param descriptor the method call's descriptor + * @param startInsn the instruction after which to start searching (inclusive) + * @return the found method call node, {@code null} if none matched after the given index + */ + public static @Nullable FieldInsnNode findFirstFieldCallAfter(MethodNode method, int opcode, String owner, String name, String descriptor, AbstractInsnNode startInsn) { + return findFirstFieldCallAfter(method, opcode, owner, name, descriptor, method.instructions.indexOf(startInsn)); + } + /** * Finds the first field call in the given method matching the given opcode, owner, name and descriptor before the * given index in reverse search. @@ -533,6 +692,22 @@ public int get() { return null; } + /** + * Finds the first field call in the given method matching the given opcode, owner, name and descriptor before the + * given instruction in reverse search. + * + * @param method the method to search in + * @param opcode the opcode of field call to search for + * @param owner the method call's owner to search for + * @param name the method call's name + * @param descriptor the method call's descriptor + * @param startInsn the instruction at which to start searching (inclusive) + * @return the found method call node or {@code null} if none matched before the given startIndex + */ + public static @Nullable FieldInsnNode findFirstFieldCallBefore(MethodNode method, int opcode, String owner, String name, String descriptor, AbstractInsnNode startInsn) { + return findFirstFieldCallBefore(method, opcode, owner, name, descriptor, method.instructions.indexOf(startInsn)); + } + /* CREATING AND FINDING METHODS */ @@ -1110,4 +1285,12 @@ private static String toString(Textifier text) { pw.flush(); return sw.toString(); } + + + /* MISCELLANEOUS */ + + // private because this is really only used to clamp indexes + private static int clamp(int value, int min, int max) { + return Math.max(min, Math.min(max, value)); + } }