Skip to content

Commit

Permalink
Add ASMAPI methods to assist in working with instruction indexes (#69)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathing authored Dec 23, 2024
1 parent 27c1b18 commit 4b60fc7
Showing 1 changed file with 191 additions and 3 deletions.
194 changes: 191 additions & 3 deletions src/main/java/net/minecraftforge/coremod/api/ASMAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -78,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
Expand Down Expand Up @@ -108,6 +127,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
Expand All @@ -126,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
Expand Down Expand Up @@ -159,7 +192,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);
}

/**
Expand Down Expand Up @@ -263,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.
*
Expand All @@ -275,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.
*
Expand All @@ -296,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.
*
Expand All @@ -313,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.
*
Expand All @@ -330,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.
*
Expand Down Expand Up @@ -376,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.
*
Expand Down Expand Up @@ -414,7 +530,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
Expand All @@ -438,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.
Expand All @@ -464,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.
*
Expand All @@ -480,7 +628,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
Expand All @@ -503,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.
Expand All @@ -528,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 */

Expand Down Expand Up @@ -1105,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));
}
}

0 comments on commit 4b60fc7

Please sign in to comment.