莊周夢蝶

          生活、程序、未來
             :: 首頁 ::  ::  :: 聚合  :: 管理

          Clojure Hacking Guide

          Posted on 2010-07-11 12:07 dennis 閱讀(3613) 評論(1)  編輯  收藏 所屬分類: 動態(tài)語言javaClojure
              這題目起的嘩眾取寵,其實只是想介紹下怎么查看Clojure動態(tài)生成的字節(jié)碼,這對分析Clojure的內(nèi)部實現(xiàn)很重要。

              第一步,下載最新的Clojure 1.1.0源碼并解壓,并導(dǎo)入到你喜歡的IDE。

              其次,下載asm 3.0的源碼并解壓。

              第三,刪除Clojure 1.1.0源碼中的clojure.asm包。clojure并不是引用asm的jar包,而是將asm的源碼合并到clojure中,并且刪除一些只會在調(diào)試階段用到的package和class,保留使用asm的最小源碼集合,這可能是處于防止asm不同版本的jar包沖突以及縮小clojure大小的考慮。

              第四,將asm 3.0源碼拷入clojure的源碼中,并將包org.objectweb.asm包括子包整體重名名為clojure.asm。

              第五步,修改Clojure源碼,加入TraceClassVisitor的適配器,用于跟蹤字節(jié)碼生成,這需要修改clojure.lang.Compiler類中的兩個compile方法,找到類似
          ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
          // ClassWriter cw = new ClassWriter(0);
          ClassVisitor cv = cw;

          這樣的代碼,將cv修改為TraceClassVisitor:
           ClassVisitor cv = new TraceClassVisitor(new CheckClassAdapter(cw), new PrintWriter(System.out));

              TraceClassVisitor的第二個參數(shù)指定將跟蹤到的字節(jié)碼輸出到哪里,這里簡單地輸出到標(biāo)準(zhǔn)輸出方便查看。

              第六步,接下來可以嘗試下我們修改過的clojure怎么動態(tài)生成字節(jié)碼,啟動REPL,
          java clojure.main

          啟動階段就會輸出一些字節(jié)碼信息,主要預(yù)先加載的一些標(biāo)準(zhǔn)庫函數(shù),如clojure.core中的函數(shù)等,REPL啟動完畢,隨便輸入一個表達(dá)式都將看到生成的字節(jié)碼
          user=> (+ 1 2)

          輸出類似

          compile 1
          // class version 49.0 (49)
          // access flags 33
          public class user$eval__4346 extends clojure/lang/AFunction  {

            
          // compiled from: NO_SOURCE_FILE
            
          // debug info: SMAP
          eval__4346.java
          Clojure
          *S Clojure
          *F
          + 1 NO_SOURCE_FILE
          NO_SOURCE_PATH
          *L
          0#1,1:0
          *E

            
          // access flags 25
            public final static Lclojure/lang/Var; const__0

            
          // access flags 25
            public final static Ljava/lang/Object; const__1

            
          // access flags 25
            public final static Ljava/lang/Object; const__2

            
          // access flags 9
            public static <clinit>()V
             L0
              LINENUMBER 
          2 L0
              LDC 
          "clojure.core"
              LDC 
          "+"
              INVOKESTATIC clojure
          /lang/RT.var (Ljava/lang/String;Ljava/lang/String;)Lclojure/lang/Var;
              CHECKCAST clojure
          /lang/Var
              PUTSTATIC user$eval__4346.const__0 : Lclojure
          /lang/Var;
              ICONST_1
              INVOKESTATIC java
          /lang/Integer.valueOf (I)Ljava/lang/Integer;
              PUTSTATIC user$eval__4346.const__1 : Ljava
          /lang/Object;
              ICONST_2
              INVOKESTATIC java
          /lang/Integer.valueOf (I)Ljava/lang/Integer;
              PUTSTATIC user$eval__4346.const__2 : Ljava
          /lang/Object;
              RETURN
              MAXSTACK 
          = 0
              MAXLOCALS 
          = 0

            
          // access flags 1
            public <init>()V
             L0
              LINENUMBER 
          2 L0
             L1
              ALOAD 
          0
              INVOKESPECIAL clojure
          /lang/AFunction.<init> ()V
             L2
              RETURN
              MAXSTACK 
          = 0
              MAXLOCALS 
          = 0

            
          // access flags 1
            public invoke()Ljava/lang/Object; throws java/lang/Exception 
             L0
              LINENUMBER 
          2 L0
             L1
              LINENUMBER 
          2 L1
              GETSTATIC user$eval__4346.const__1 : Ljava/lang/Object;
              GETSTATIC user$eval__4346.const__2 : Ljava
          /lang/Object;
              INVOKESTATIC clojure
          /lang/Numbers.add (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Number;

             L2
              LOCALVARIABLE 
          this Ljava/lang/Object; L0 L2 0
              ARETURN
              MAXSTACK 
          = 0
              MAXLOCALS 
          = 0
          }
          3

          3就是表達(dá)式的結(jié)果??梢钥吹?,一個表達(dá)式生成了一個class。其中<clinit>是靜態(tài)初始化塊,主要是初始化表達(dá)式中的字面常量;<init>不用說,默認(rèn)的構(gòu)造函數(shù);invoke是核心方法,表達(dá)式生成的class,new一個實例后調(diào)用的就是invoke方法,執(zhí)行實際的代碼,高亮部分加載了兩個常量,并執(zhí)行Number.add方法。

          最后,請Happy hacking!。




          評論

          # re: Clojure Hacking Guide  回復(fù)  更多評論   

          2010-07-12 11:46 by dasdas
          dasdsadas http://www.51pkwg.com DNF免費外掛 http://www.1ploan.com 一點貸 http://www.tatayouyue.com http://www.1ploan.com/forum.do/list/qryFirsort_7.html dasdasdasda
          主站蜘蛛池模板: 屏山县| 嘉兴市| 虞城县| 新乡市| 临泉县| 延庆县| 浙江省| 安陆市| 都匀市| 泸州市| 东丽区| 宁安市| 乡宁县| 全椒县| 望谟县| 东兰县| 西峡县| 福安市| 翁牛特旗| 宜春市| 阳原县| 哈密市| 水城县| 克山县| 云林县| 柘城县| 三都| 田东县| 马边| 界首市| 聂荣县| 巴林左旗| 鹤山市| 库车县| 阜平县| 杨浦区| 高青县| 连城县| 都昌县| 建平县| 寿阳县|