Skip to content

Commit 4b60fc7

Browse files
authored
Add ASMAPI methods to assist in working with instruction indexes (#69)
1 parent 27c1b18 commit 4b60fc7

File tree

1 file changed

+191
-3
lines changed
  • src/main/java/net/minecraftforge/coremod/api

1 file changed

+191
-3
lines changed

src/main/java/net/minecraftforge/coremod/api/ASMAPI.java

+191-3
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ public class ASMAPI {
4040
*
4141
* @param nodes The instructions you want to add
4242
* @return A new list with the instructions
43+
*
44+
* @apiNote Due to a bug in Nashorn, invoking this method from your CoreMod with a very large array (or varargs)
45+
* will not work due to it being cast to {@code Object[]}. In that case, you will need to wrap this method
46+
* like this: {@code ASMAPI.listOf(Java.to([...], Java.type('org.objectweb.asm.tree.AbstractInsnNode[]')))}.
4347
*/
4448
public static InsnList listOf(AbstractInsnNode... nodes) {
4549
InsnList list = new InsnList();
@@ -78,6 +82,21 @@ public static boolean insertInsn(MethodNode method, AbstractInsnNode insn, Abstr
7882
return true;
7983
}
8084

85+
/**
86+
* Inserts/replaces an instruction, with respect to the given {@link InsertMode}, on the given index.
87+
*
88+
* @param method The method to insert the instruction into
89+
* @param index The index where the new instruction should be inserted into
90+
* @param toInsert The instruction to be inserted
91+
* @param mode How the instruction should be inserted
92+
* @return {@code true} if the list was inserted, {@code false} otherwise
93+
*/
94+
public static boolean insertInsn(MethodNode method, int index, AbstractInsnNode toInsert, InsertMode mode) {
95+
index = clamp(index, 0, method.instructions.size());
96+
var insn = method.instructions.get(index);
97+
return insertInsn(method, insn, toInsert, mode);
98+
}
99+
81100
/**
82101
* Inserts/replaces an instruction, with respect to the given {@link InsertMode}, on the first
83102
* {@link MethodInsnNode} that matches the parameters of these functions in the method provided. Only the first
@@ -108,6 +127,7 @@ public static boolean insertInsn(MethodNode method, MethodType type, String owne
108127
* Inserts/replaces an instruction list, with respect to the given {@link InsertMode}, on the given instruction.
109128
*
110129
* @param method The method to insert the list into
130+
* @param insn The instruction where the list should be inserted into
111131
* @param list The list to be inserted
112132
* @param mode How the list should be inserted
113133
* @return {@code true} if the list was inserted, {@code false} otherwise
@@ -126,6 +146,19 @@ public static boolean insertInsnList(MethodNode method, AbstractInsnNode insn, I
126146
return true;
127147
}
128148

149+
/**
150+
* Inserts/replaces an instruction list, with respect to the given {@link InsertMode}, on the given index.
151+
*
152+
* @param method The method to insert the list into
153+
* @param index The index where the list should be inserted into
154+
* @param list The list to be inserted
155+
* @param mode How the list should be inserted
156+
* @return {@code true} if the list was inserted, {@code false} otherwise
157+
*/
158+
public static boolean insertInsnList(MethodNode method, int index, InsnList list, InsertMode mode) {
159+
return insertInsnList(method, method.instructions.get(clamp(index, 0, method.instructions.size())), list, mode);
160+
}
161+
129162
/**
130163
* Inserts/replaces an instruction list, with respect to the given {@link InsertMode}, on the first
131164
* {@link MethodInsnNode} that matches the parameters of these functions in the method provided. Only the first
@@ -159,7 +192,7 @@ public static boolean insertInsnList(MethodNode method, MethodType type, String
159192
* @param insn The method call to inject
160193
*/
161194
public static void injectMethodCall(MethodNode method, MethodInsnNode insn) {
162-
method.instructions.insertBefore(method.instructions.getFirst(), insn);
195+
ASMAPI.insertInsn(method, method.instructions.getFirst(), insn, InsertMode.INSERT_BEFORE);
163196
}
164197

165198
/**
@@ -263,6 +296,18 @@ public int get() {
263296
return findFirstInstructionAfter(method, opcode, null, startIndex);
264297
}
265298

299+
/**
300+
* Finds the first instruction with matching opcode after the given start instruction.
301+
*
302+
* @param method the method to search in
303+
* @param opcode the opcode to search for
304+
* @param startInsn the instruction to start search after (inclusive)
305+
* @return the found instruction node or {@code null} if none matched after the given index
306+
*/
307+
public static @Nullable AbstractInsnNode findFirstInstructionAfter(MethodNode method, int opcode, AbstractInsnNode startInsn) {
308+
return findFirstInstructionAfter(method, opcode, method.instructions.indexOf(startInsn));
309+
}
310+
266311
/**
267312
* Finds the first instruction with matching instruction type after the given start index.
268313
*
@@ -275,6 +320,18 @@ public int get() {
275320
return findFirstInstructionAfter(method, -2, type, startIndex);
276321
}
277322

323+
/**
324+
* Finds the first instruction with matching instruction type after the given start instruction.
325+
*
326+
* @param method the method to search in
327+
* @param type the instruction type to search for
328+
* @param startInsn the instruction to start search after (inclusive)
329+
* @return the found instruction node or {@code null} if none matched after the given index
330+
*/
331+
public static @Nullable AbstractInsnNode findFirstInstructionAfter(MethodNode method, InsnType type, AbstractInsnNode startInsn) {
332+
return findFirstInstructionAfter(method, type, method.instructions.indexOf(startInsn));
333+
}
334+
278335
/**
279336
* Finds the first instruction with matching opcode and instruction type after the given start index.
280337
*
@@ -296,6 +353,19 @@ public int get() {
296353
return null;
297354
}
298355

356+
/**
357+
* Finds the first instruction with matching opcode and instruction type after the given start instruction.
358+
*
359+
* @param method the method to search in
360+
* @param opcode the opcode to search for
361+
* @param type the instruction type to search for
362+
* @param startInsn the instruction to start search after (inclusive)
363+
* @return the found instruction node or {@code null} if none matched after the given index
364+
*/
365+
public static @Nullable AbstractInsnNode findFirstInstructionAfter(MethodNode method, int opcode, @Nullable InsnType type, AbstractInsnNode startInsn) {
366+
return findFirstInstructionAfter(method, opcode, type, method.instructions.indexOf(startInsn));
367+
}
368+
299369
/**
300370
* Finds the first instruction with matching opcode before the given index in reverse search.
301371
*
@@ -313,6 +383,21 @@ public int get() {
313383
return findFirstInstructionBefore(method, opcode, null, startIndex);
314384
}
315385

386+
/**
387+
* Finds the first instruction with matching opcode before the given instruction in reverse search.
388+
*
389+
* @param method the method to search in
390+
* @param opcode the opcode to search for
391+
* @param startInsn the instruction at which to start searching (inclusive)
392+
* @return the found instruction node or {@code null} if none matched before the given startIndex
393+
*
394+
* @apiNote Since this method is new, it will automatically apply the fixed logic in
395+
* {@link #findFirstInstructionBefore(MethodNode, int, InsnType, int, boolean)}.
396+
*/
397+
public static @Nullable AbstractInsnNode findFirstInstructionBefore(MethodNode method, int opcode, AbstractInsnNode startInsn) {
398+
return findFirstInstructionBefore(method, opcode, null, startInsn);
399+
}
400+
316401
/**
317402
* Finds the first instruction with matching instruction type before the given index in reverse search.
318403
*
@@ -330,6 +415,21 @@ public int get() {
330415
return findFirstInstructionBefore(method, -2, type, startIndex);
331416
}
332417

418+
/**
419+
* Finds the first instruction with matching instruction type before the given instruction in reverse search.
420+
*
421+
* @param method the method to search in
422+
* @param type the instruction type to search for
423+
* @param startInsn the index at which to start searching (inclusive)
424+
* @return the found instruction node or {@code null} if none matched before the given startIndex
425+
*
426+
* @apiNote Since this method is new, it will automatically apply the fixed logic in
427+
* {@link #findFirstInstructionBefore(MethodNode, int, InsnType, int, boolean)}.
428+
*/
429+
public static @Nullable AbstractInsnNode findFirstInstructionBefore(MethodNode method, InsnType type, AbstractInsnNode startInsn) {
430+
return findFirstInstructionBefore(method, -2, type, startInsn);
431+
}
432+
333433
/**
334434
* Finds the first instruction with matching opcode before the given index in reverse search.
335435
*
@@ -376,6 +476,22 @@ public int get() {
376476
return findFirstInstructionBefore(method, opCode, type, startIndex, !CoreModEngine.DO_NOT_FIX_INSNBEFORE);
377477
}
378478

479+
/**
480+
* Finds the first instruction with matching opcode and instruction type before the given instruction in reverse
481+
* search.
482+
*
483+
* @param method the method to search in
484+
* @param opCode the opcode to search for
485+
* @param startInsn the instruction at which to start searching (inclusive)
486+
* @return the found instruction node or {@code null} if none matched before the given startIndex
487+
*
488+
* @apiNote Since this method is new, it will automatically apply the fixed logic in
489+
* {@link #findFirstInstructionBefore(MethodNode, int, InsnType, int, boolean)}.
490+
*/
491+
public static @Nullable AbstractInsnNode findFirstInstructionBefore(MethodNode method, int opCode, @Nullable InsnType type, AbstractInsnNode startInsn) {
492+
return findFirstInstructionBefore(method, opCode, type, method.instructions.indexOf(startInsn), true);
493+
}
494+
379495
/**
380496
* Finds the first instruction with matching opcode and instruction type before the given index in reverse search.
381497
*
@@ -414,7 +530,7 @@ public int get() {
414530

415531
/**
416532
* Finds the first method call in the given method matching the given type, owner, name and descriptor after the
417-
* instruction given index.
533+
* given index.
418534
*
419535
* @param method the method to search in
420536
* @param type the type of method call to search for
@@ -438,6 +554,22 @@ public int get() {
438554
return null;
439555
}
440556

557+
/**
558+
* Finds the first method call in the given method matching the given type, owner, name and descriptor after the
559+
* given instruction.
560+
*
561+
* @param method the method to search in
562+
* @param type the type of method call to search for
563+
* @param owner the method call's owner to search for
564+
* @param name the method call's name
565+
* @param descriptor the method call's descriptor
566+
* @param insn the instruction after which to start searching (inclusive)
567+
* @return the found method call node, {@code null} if none matched after the given index
568+
*/
569+
public static @Nullable MethodInsnNode findFirstMethodCallAfter(MethodNode method, MethodType type, String owner, String name, String descriptor, AbstractInsnNode insn) {
570+
return findFirstMethodCallAfter(method, type, owner, name, descriptor, method.instructions.indexOf(insn));
571+
}
572+
441573
/**
442574
* Finds the first method call in the given method matching the given type, owner, name and descriptor before the
443575
* given index in reverse search.
@@ -464,6 +596,22 @@ public int get() {
464596
return null;
465597
}
466598

599+
/**
600+
* Finds the first method call in the given method matching the given type, owner, name and descriptor before the
601+
* given instruction in reverse search.
602+
*
603+
* @param method the method to search in
604+
* @param type the type of method call to search for
605+
* @param owner the method call's owner to search for
606+
* @param name the method call's name
607+
* @param descriptor the method call's descriptor
608+
* @param insn the instruction at which to start searching (inclusive)
609+
* @return the found method call node or {@code null} if none matched before the given startIndex
610+
*/
611+
public static @Nullable MethodInsnNode findFirstMethodCallBefore(MethodNode method, MethodType type, String owner, String name, String descriptor, AbstractInsnNode insn) {
612+
return findFirstMethodCallBefore(method, type, owner, name, descriptor, method.instructions.indexOf(insn));
613+
}
614+
467615
/**
468616
* Finds the first field call in the given method matching the given opcode, owner, name and descriptor.
469617
*
@@ -480,7 +628,7 @@ public int get() {
480628

481629
/**
482630
* Finds the first field call in the given method matching the given opcode, owner, name and descriptor after the
483-
* instruction given index.
631+
* given index.
484632
*
485633
* @param method the method to search in
486634
* @param opcode the opcode of field call to search for
@@ -503,6 +651,22 @@ public int get() {
503651
return null;
504652
}
505653

654+
/**
655+
* Finds the first field call in the given method matching the given opcode, owner, name and descriptor after the
656+
* given instruction.
657+
*
658+
* @param method the method to search in
659+
* @param opcode the opcode of field call to search for
660+
* @param owner the method call's owner to search for
661+
* @param name the method call's name
662+
* @param descriptor the method call's descriptor
663+
* @param startInsn the instruction after which to start searching (inclusive)
664+
* @return the found method call node, {@code null} if none matched after the given index
665+
*/
666+
public static @Nullable FieldInsnNode findFirstFieldCallAfter(MethodNode method, int opcode, String owner, String name, String descriptor, AbstractInsnNode startInsn) {
667+
return findFirstFieldCallAfter(method, opcode, owner, name, descriptor, method.instructions.indexOf(startInsn));
668+
}
669+
506670
/**
507671
* Finds the first field call in the given method matching the given opcode, owner, name and descriptor before the
508672
* given index in reverse search.
@@ -528,6 +692,22 @@ public int get() {
528692
return null;
529693
}
530694

695+
/**
696+
* Finds the first field call in the given method matching the given opcode, owner, name and descriptor before the
697+
* given instruction in reverse search.
698+
*
699+
* @param method the method to search in
700+
* @param opcode the opcode of field call to search for
701+
* @param owner the method call's owner to search for
702+
* @param name the method call's name
703+
* @param descriptor the method call's descriptor
704+
* @param startInsn the instruction at which to start searching (inclusive)
705+
* @return the found method call node or {@code null} if none matched before the given startIndex
706+
*/
707+
public static @Nullable FieldInsnNode findFirstFieldCallBefore(MethodNode method, int opcode, String owner, String name, String descriptor, AbstractInsnNode startInsn) {
708+
return findFirstFieldCallBefore(method, opcode, owner, name, descriptor, method.instructions.indexOf(startInsn));
709+
}
710+
531711

532712
/* CREATING AND FINDING METHODS */
533713

@@ -1105,4 +1285,12 @@ private static String toString(Textifier text) {
11051285
pw.flush();
11061286
return sw.toString();
11071287
}
1288+
1289+
1290+
/* MISCELLANEOUS */
1291+
1292+
// private because this is really only used to clamp indexes
1293+
private static int clamp(int value, int min, int max) {
1294+
return Math.max(min, Math.min(max, value));
1295+
}
11081296
}

0 commit comments

Comments
 (0)