簡體   English   中英

編輯Java ASM字節碼中try-catch的finally塊

[英]Editing the finally block of try-catch in Java ASM bytecode

我有一個 java class,我想在每個 finally 塊中添加一些自定義指令。 我試過使用 Java ASM 庫。 我嘗試迭代每個方法,然后迭代每個 TryCatchBlockNode 並獲取句柄 label 並在其中插入指令。

List<MethodNode> methods = (List<MethodNode>) classNode.methods;
    for (MethodNode method : methods) {
        List<TryCatchBlockNode> tryCatchBlocks = method.tryCatchBlocks;

        for (int i = 0; i < tryCatchBlocks.size(); i++) {
                TryCatchBlockNode tryCatchBlockNode = (TryCatchBlockNode) method.tryCatchBlocks.get(i);
                if (tryCatchBlockNode.type == null) {
                    InsnList tmpInsn = new InsnList();
                    tmpInsn.add(new FieldInsnNode(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"));
                    tmpInsn.add(new LdcInsnNode("AAAA"));
                    tmpInsn.add(new MethodInsnNode(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"));
                    method.instructions.insert(tryCatchBlockNode.handler, tmpInsn);
                }
        }
     }

如何在每個 finally 塊中插入一些自定義代碼?

編輯:上面的代碼有效,但重構不符合預期:

輸入代碼是:

    try {
        lr.abort();
    } finally {
        System.out.println("throwable");
    }

使用 IntelliJ 的反編譯代碼 Output:

try {
    lr.abort();
} catch (Throwable var3) {
    System.out.println("AAAA");
    System.out.println("throwable");
    throw var3;
}

System.out.println("throwable");
System.out.println("Goodbye!");

您在 label 節點之后重復插入一個指令節點,而您實際上想要在剛剛插入的節點之后插入指令節點。

一般模式是

  • 在 X 之后插入 A
    導致 [X, A]
  • 在 X 之后插入 B
    導致 [X, B, A]
  • 在 X 后插入 C
    結果 [X, C, B, A]

以與插入說明相反的順序結束。

有不同的方法可以解決這個問題

  1. 只需使用相反的順序

    TryCatchBlockNode tryCatchBlockNode = method.tryCatchBlocks.get(i); if(tryCatchBlockNode.type == null) { LabelNode h = tryCatchBlockNode.handler; method.instructions.insert(h, new MethodInsnNode(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V")); method.instructions.insert(h, new LdcInsnNode("AAAA")); method.instructions.insert(h, new FieldInsnNode(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;")); }

    這很簡單,但隨着您必須插入的說明越多,閱讀起來就越困難。

  2. 不要使用固定點,而是使用先前插入的節點

    TryCatchBlockNode tryCatchBlockNode = method.tryCatchBlocks.get(i); if(tryCatchBlockNode.type == null) { AbstractInsnNode after = tryCatchBlockNode.handler; method.instructions.insert(after, after = new FieldInsnNode(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;")); method.instructions.insert(after, after = new LdcInsnNode("AAAA")); method.instructions.insert(after, after = new MethodInsnNode(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V")); }

    這允許以預期的結果順序指定指令,但需要一個變化的變量。

  3. 獲取 label 之后的下一個節點並改用insertBefore

     TryCatchBlockNode tryCatchBlockNode = method.tryCatchBlocks.get(i); if(tryCatchBlockNode.type == null) { AbstractInsnNode before = tryCatchBlockNode.handler.getNext(); method.instructions.insertBefore(before, new FieldInsnNode(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;")); method.instructions.insertBefore(before, new LdcInsnNode("AAAA")); method.instructions.insertBefore(before, new MethodInsnNode(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V")); }

    在這里工作順利,因為異常處理程序不能為空。 所以必須有一個后續節點,我們可以參考。 但它可能不適用於其他場景。


您還可以使用指令列表並將它們作為單個實體插入。

static InsnList printStatement() {
    InsnList print = new InsnList();
    print.add(new FieldInsnNode(GETSTATIC,
            "java/lang/System", "out", "Ljava/io/PrintStream;"));
    print.add(new LdcInsnNode("AAAA"));
    print.add(new MethodInsnNode(INVOKEVIRTUAL,
            "java/io/PrintStream", "println", "(Ljava/lang/String;)V"));
    return print;
}
TryCatchBlockNode tryCatchBlockNode = method.tryCatchBlocks.get(i);
if(tryCatchBlockNode.type == null) {
    method.instructions.insert(tryCatchBlockNode.handler, printStatement());
}

這樣的構建塊更容易維護。 請務必記住,這會將節點從一個列表轉移到另一個列表,因此每次需要插入序列時都必須再次調用工廠方法,而不是重復使用InsnList object。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM