深刻字節碼 -- 玩轉 ASM-Bytecode

    本文是《深刻字節碼 -- 使用 ASM 實現 AOP》的後續博文。在上一篇文章中介紹瞭如何使用 ASM 動態安插代碼到類中,從而簡單實現 Aop。文章獲得了廣大朋友好評,我也但願能夠不負衆望繼續寫出能夠獲得你們承認的更多相關文章。廢話很少進入正題。 java

    古語有云「工欲善其事,必先利其器」。因爲 JVM 對字節碼十分敏感修改過程當中稍微有一絲錯誤都會致使虛擬機錯誤,而想要排查錯誤倒是一件比較困難的事情。再加上後面的博文將會很大程度上依賴 「ASM-Bytecode」 工具。所以我以爲有必要在深刻制定字節碼以前介紹一下如何使用 「ASM-Bytecode」 。 eclipse

    首先安裝Eclipse插件,插件的地址爲:「http://andrei.gmxhome.de/eclipse/」 個人 Eclipse 版本爲 3.7。
編輯器

安裝完成以後重啓 Eclipse ,打開菜單 Window -> Show View -> Other... 在分類中選擇 Bytecode 視圖
工具

    爲了測試其功能隨便建立一個工程並新建一個 HalloWord 程序,在 Eclipse 中打開 「HalloWord.java」 程序查看 Bytecode 視圖,你會獲得下面這樣的代碼。
    (注意:因爲Bytecode會自動感知 Eclipse 編輯器中光標位置從而肯定生成的代碼範圍所以初學者建議將光標放到 「main」 方法中) 測試

// access flags 0x9
  public static main(String[]) : void
   L0
    LINENUMBER 22 L0
    GETSTATIC System.out : PrintStream
    LDC "Hallo Word"
    INVOKEVIRTUAL PrintStream.println(String) : void
   L1
    LINENUMBER 23 L1
    RETURN
   L2
    LOCALVARIABLE args String[] L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1
    這是 ASM 爲咱們生成的 「main」 方法字節碼指令。點擊 「Bytecode」  視圖右上角紅色的 「ASM」 按鈕。ASM便會爲咱們生成想要的 ASM 代碼。
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitLineNumber(22, l0);
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("Hallo Word");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitLineNumber(23, l1);
mv.visitInsn(RETURN);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitLocalVariable("args", "[Ljava/lang/String;", null, l0, l2, 0);
mv.visitMaxs(2, 1);
mv.visitEnd();
}
    「Bytecode 」 程序總會爲咱們生成不少沒必要要的代碼,爲此打開 Window -> Preferences 找到 Bytecode Outline 選項關閉 「Show line info」、 「Show variables」 兩個選項。這兩個選項分別是用來生成行號代碼和本地變量表代碼。這樣作能夠大大減小所要分析的內容,不過即使如此 「Bytecode Outline」 的生成代碼中依然保留了不少沒必要要的 「垃圾」 。

    最後獲得以下精簡的 ASM 生成內容:4,5,9,10,12,13 行代碼仍然是垃圾。很惋惜 「 Bytecode Outline 」 只幫咱們去掉了 「visitLineNumber」 這樣的代碼,其餘兩行並未給予處理。只要記得這個是目前是用來表示行號便可。
{
mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
mv.visitCode();
Label l0 = new Label();
mv.visitLabel(l0);
mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
mv.visitLdcInsn("Hallo Word");
mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
Label l1 = new Label();
mv.visitLabel(l1);
mv.visitInsn(RETURN);
Label l2 = new Label();
mv.visitLabel(l2);
mv.visitMaxs(2, 1);
mv.visitEnd();
}

    要注意的是雖然藉助 「Bytecode Outline」 咱們只須要提供一份代碼模板便可生成各類 ASM 代碼,可是,切莫生成過於複雜的代碼 spa

    到這裏使用 「Bytecode Outline」 生成 ASM 代碼部分就介紹這麼多,在下一篇文章中將重點介紹 ASM 核心接口方法。 .net

相關文章
相關標籤/搜索