Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add additional instruction searching to ASMAPI #59

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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