Clojure Hacking Guide

  这题目起的哗众取宠,其实只是想介绍下怎么查看Clojure动态生成的字节码,这对分析Clojure的内部实现很重要。

    第一步,下载最新的Clojure 1.1.0源码并解压,并导入到你喜欢的IDE。

    其次,下载asm 3.0的源码并解压。

    第三,删除Clojure 1.1.0源码中的clojure.asm包。clojure并不是引用asm的jar包,而是将asm的源码合并到clojure中,并且删除一些只会在调试阶段用到的package和class,保留使用asm的最小源码集合,这可能是处于防止asm不同版本的jar包冲突以及缩小clojure大小的考虑。

    第四,将asm 3.0源码拷入clojure的源码中,并将包org.objectweb.asm包括子包整体重名名为clojure.asm。

    第五步,修改Clojure源码,加入TraceClassVisitor的适配器,用于跟踪字节码生成,这需要修改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的第二个参数指定将跟踪到的字节码输出到哪里,这里简单地输出到标准输出方便查看。

    第六步,接下来可以尝试下我们修改过的clojure怎么动态生成字节码,启动REPL,

java clojure.main

启动阶段就会输出一些字节码信息,主要预先加载的一些标准库函数,如clojure.core中的函数等,REPL启动完毕,随便输入一个表达式都将看到生成的字节码

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就是表达式的结果。可以看到,一个表达式生成了一个class。其中<clinit>是静态初始化块,主要是初始化表达式中的字面常量;<init>不用说,默认的构造函数;invoke是核心方法,表达式生成的class,new一个实例后调用的就是invoke方法,执行实际的代码,高亮部分加载了两个常量,并执行Number.add方法。

文章转自庄周梦蝶  ,原文发布时间2010-07-11

时间: 2024-09-14 23:39:16

Clojure Hacking Guide的相关文章

Clojure世界:利用HouseMD诊断clojure

  HouseMD是淘宝的聚石写的一个非常优秀的Java进程运行时诊断和调试工具,如果你接触过btrace,那么HouseMD也许你应该尝试下,它比btrace更易用,不需要写脚本,类似strace的方式attach到jvm进程做跟踪调试.     基本的安装和使用请看这篇文档<UserGuide>,恕不重复.以下内容都假设你正确安装了housemd.     本文主要介绍下怎么用housemd诊断跟踪clojure进程.Clojure的java实现也是跑在JVM里,当然也可以用housemd

免费编程书

Index Meta-Lists Graphics user interfaces Graphics Programming Language Agnostic Ada Android Autotools ASP.NET MVC Assembly Language Bash C C++ Clojure CoffeeScript ColdFusion D DTrace DB2 Delphi / Pascal Django Elasticsearch Emacs Erlang Flask Flex

介绍下XRuby项目

XRuby是什么?它是一个编译器.与其它编译器一样,它完成的工作是将一种格式的语言转换成另一种.与大多数编译器不同的是,它是将Ruby的代码(.rb)转换成Java的bytecode(.class). Xruby是一群中国开发者维护的项目,它的目的如上所述.它的主页是http://code.google.com/p/xruby/.与JRuby不同,JRuby一开始是想使用java写ruby解析器,性能上是个大问题,当然现在也走上了编译这条路.而XRuby是第一个实现这种想法的人. 我翻译下了<X

模仿st_table写的StTable类

  update1:添加了remove,removeAll()方法以及getSize()方法     update2:添加了keySet()方法用于迭代       update3:经过测试,StTable类在存储Integer类型key时,put的速度比HashMap快了接近3倍,而remove.get却比HashMap慢:而在存储String类型的key时,put比Hashmap慢,但是get.remove却快不少.     读ruby hacking guide,其中专门辟了一个章节介绍了

判断栈的增长方向

  dreamhead老大曾经讨论过这个问题,寻找一种可移植的方式来判断栈的增长方向,见<栈的增长方向>.今天在读Ruby hacking guide第5章,介绍alloca函数的部分,提到ruby实现的C语言版本的alloca.c,读了下代码,发现这里倒是实现了一个很漂亮的函数用于实现判断栈的增长方向,利用了局部static变量,与dreamhead老大的想法其实是一致的. #include<stdio.h>static void find_stack_direction(voi

我深入学习C语言的三个目的

   学习和使用java有四年多了,现在却回头搞起了C,理由有三: 1.为了考试啊,我也知道高程证书含金量不怎么样,可为了督促自己再次深入学习下基础知识,考个证没坏处. 2.我想读<ruby hacking guide>,ruby是用C写的,自从看了dreamhead老大的<管窥ruby>之后,我一直有股强烈的冲动去读ruby的源码.想把冲动转成行动,不深入下C语言是不行的.有牛人将Erlang的源码都看了,尽管我觉的我这辈子还达不到那么牛,不过偶尔去探访一下神秘的代码丛林也能满足

Ruby变量在c ruby中的存储

读完ruby hacking guide第6章,彻底总结下: 1.在Ruby中,类也是一个对象,因此有实例变量.类的实例变量.类变量.常量都是存储在RClass struct的iv_tbl中, struct RClass {     struct RBasic basic;     struct st_table *iv_tbl;     struct st_table *m_tbl;     VALUE super; }; iv_tbl的类型是st_table,我在这里用java实现了一下.

GnuRadio Hacking①:使用GnuRadio+SDR破解固定码无线遥控

0×01 信号捕获 在这篇文章中,我们将使用GnuRadio+SDR硬件对某品牌型号的无线跳蛋进行无线重放攻击的演示. 市面上常见的无线遥控工作的频段,通常工作在315Mhz.433Mhz,也有少数的会采用868Mhz.915Mhz这几个频点. 我们可以用电视棒.HackRF.BladeRF等SDR硬件来确定遥控的工作频率: 打开软件按下遥控器后,能在瀑布图上看到明显的反应: osmocom_fft -F -f 433e6 -s 4e6   gqrx 无线遥控中心频率:433870000 0×0

I.MX6 mfgtool2-android-mx6q-sabresd-emmc.vbs hacking

/******************************************************************** * I.MX6 mfgtool2-android-mx6q-sabresd-emmc.vbs hacking * 说明: * 以前用的mfgtool2是直接执行MfgTool2.exe就行了,现在的NXP将其封 * 装在vbs文件内,这是左栋告诉我的,这里记录一下命令行参数的本质. * * 2016-9-18 深圳 南山平山村 曾剑锋 ***********