@@ -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