Skip to content

Commit

Permalink
Add additional instruction searching to ASMAPI (#59)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathing authored Nov 1, 2024
1 parent 7437c08 commit ba314a1
Showing 1 changed file with 66 additions and 14 deletions.
80 changes: 66 additions & 14 deletions src/main/java/net/minecraftforge/coremod/api/ASMAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public static void injectMethodCall(MethodNode node, MethodInsnNode methodCall)
*
* @deprecated Renamed to {@link #injectMethodCall(MethodNode, MethodInsnNode)}
*/
@Deprecated(forRemoval = true, since = "5.1")
@Deprecated(forRemoval = true, since = "6.0")
public static void appendMethodCall(MethodNode node, MethodInsnNode methodCall) {
injectMethodCall(node, methodCall);
}
Expand Down Expand Up @@ -253,6 +253,17 @@ public static AbstractInsnNode findFirstInstruction(MethodNode method, int opCod
return findFirstInstructionAfter(method, opCode, null, 0);
}

/**
* Finds the first instruction with matching opcode.
*
* @param method the method to search in
* @param type the instruction type to search for
* @return the found instruction node or null if none matched
*/
public static AbstractInsnNode findFirstInstruction(MethodNode method, InsnType type) {
return findFirstInstructionAfter(method, -2, type, 0);
}

/**
* Finds the first instruction with matching opcode.
*
Expand All @@ -277,24 +288,35 @@ public static AbstractInsnNode findFirstInstructionAfter(MethodNode method, int
return findFirstInstructionAfter(method, opCode, null, startIndex);
}

/**
* Finds the first instruction with matching opcode after the given start index.
*
* @param method the method to search in
* @param type the instruction type to search for
* @param startIndex the index to start search after (inclusive)
* @return the found instruction node or null if none matched after the given index
*/
public static AbstractInsnNode findFirstInstructionAfter(MethodNode method, InsnType type, int startIndex) {
return findFirstInstructionAfter(method, -2, type, startIndex);
}

/**
* Finds the first instruction with matching opcode after the given start index
*
* @param method the method to search in
* @param opCode the opcode to search for
* @param type the instruction type to search for
* @param method the method to search in
* @param opCode the opcode to search for
* @param type the instruction type to search for
* @param startIndex the index to start search after (inclusive)
* @return the found instruction node or null if none matched after the given index
*/
public static AbstractInsnNode findFirstInstructionAfter(MethodNode method, int opCode, @Nullable InsnType type, int startIndex) {
boolean checkType = type != null;
for (int i = Math.max(0, startIndex); i < method.instructions.size(); i++) {
AbstractInsnNode ain = method.instructions.get(i);
if (ain.getOpcode() == opCode) {
if (!checkType || type.get() == ain.getType()) {
return ain;
}
}

boolean opcodeMatch = opCode < -1 || ain.getOpcode() == opCode;
boolean typeMatch = !checkType || type.get() == ain.getType();
if (opcodeMatch && typeMatch) return ain;
}
return null;
}
Expand All @@ -316,6 +338,23 @@ public static AbstractInsnNode findFirstInstructionBefore(MethodNode method, int
return findFirstInstructionBefore(method, opCode, null, startIndex);
}

/**
* Finds the first instruction with matching opcode before the given index in reverse search.
*
* @param method the method to search in
* @param type the instruction type to search for
* @param startIndex the index at which to start searching (inclusive)
* @return the found instruction node or null if none matched before the given startIndex
*
* @apiNote In Minecraft 1.21.1 and earlier, this method contains broken logic that ignores the {@code startIndex}
* parameter and searches for the requested instruction at the end of the method. This behavior is preserved to
* not disrupt older coremods. If you are on one of these older versions and need to use the fixed logic, please
* use {@link #findFirstInstructionBefore(MethodNode, int, int, boolean)}.
*/
public static AbstractInsnNode findFirstInstructionBefore(MethodNode method, InsnType type, int startIndex) {
return findFirstInstructionBefore(method, -2, type, startIndex);
}

/**
* Finds the first instruction with matching opcode before the given index in reverse search.
*
Expand All @@ -330,6 +369,20 @@ public static AbstractInsnNode findFirstInstructionBefore(MethodNode method, int
return findFirstInstructionBefore(method, opCode, null, startIndex, fixLogic);
}

/**
* Finds the first instruction with matching opcode before the given index in reverse search.
*
* @param method the method to search in
* @param type the instruction type to search for
* @param startIndex the index at which to start searching (inclusive)
* @param fixLogic whether to use the fixed logic for finding instructions before the given startIndex (true by
* default on versions since 1.21.3, false otherwise)
* @return the found instruction node or null if none matched before the given startIndex
*/
public static AbstractInsnNode findFirstInstructionBefore(MethodNode method, InsnType type, int startIndex, boolean fixLogic) {
return findFirstInstructionBefore(method, -2, type, startIndex, fixLogic);
}

/**
* Finds the first instruction with matching opcode before the given index in reverse search
*
Expand Down Expand Up @@ -361,11 +414,10 @@ public static AbstractInsnNode findFirstInstructionBefore(MethodNode method, int
boolean checkType = type != null;
for (int i = fixLogic ? Math.min(method.instructions.size() - 1, startIndex) : startIndex; i >= 0; i--) {
AbstractInsnNode ain = method.instructions.get(i);
if (ain.getOpcode() == opCode) {
if (!checkType || type.get() == ain.getType()) {
return ain;
}
}

boolean opcodeMatch = opCode < -1 || ain.getOpcode() == opCode;
boolean typeMatch = !checkType || type.get() == ain.getType();
if (opcodeMatch && typeMatch) return ain;
}
return null;
}
Expand Down

0 comments on commit ba314a1

Please # to comment.