`
aswang
  • 浏览: 848254 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

ASM指南翻译-12 无状态转换

 
阅读更多

 

3.2.4无状态转换

假定,我们想要测量一个程序中花费在每个类上的时间,那么我们需要在每个类上添加一个静态的计时字段,并且我们需要将每个方法的执行之间加到这个字段上。也就是说我们想转换类似于C这样的一个类:

public class C {

         public void m() throws Exception {

                  Thread.sleep(100);

         }

}

转换之后:

public class C {

         public static long timer;

         public void m() throws Exception {

                   timer -= System.currentTimeMillis();

                   Thread.sleep(100);

                   timer += System.currentTimeMillis();

         }

}

 

为了弄清楚ASM是如何实现的,我们将编译这两个类,然后对比它们的TraceClassVisitor或者ASMifierClassVisitor的输出。通过TraceClassVisitor我们可以发现以下不同(粗体表示):

GETSTATIC C.timer : J

INVOKESTATIC java/lang/System.currentTimeMillis()J

LSUB

PUTSTATIC C.timer : J

LDC 100

INVOKESTATIC java/lang/Thread.sleep(J)V

GETSTATIC C.timer : J

INVOKESTATIC java/lang/System.currentTimeMillis()J

LADD

PUTSTATIC C.timer : J

RETURN

MAXSTACK = 4

MAXLOCALS = 1

 

通过上面我们看到了,我们必须在这个方法的最开始添加四条指令,以及在这个方法返回之前添加另外四条指令。最后 我们需要更新操作数栈的大小。因此,我们可以在方法适配器中重写这个方法以增加最开始的四条指令:

public void visitCode() {

         mv.visitCode();

         mv.visitFieldInsn(GETSTATIC, owner, "timer", "J");

         mv.visitMethodInsn(INVOKESTATIC, "java/lang/System",

                   "currentTimeMillis", "()J");

         mv.visitInsn(LSUB);

         mv.visitFieldInsn(PUTSTATIC, owner, "timer", "J");

}

 

在这里owner必须设置为即将转换的类的名字。现在我们需要添加另外四条位于RETURN之前的指令,同时这四条指令也必须位于xRETURN或者ATHROW之前,因为这些指令都会结束方法的执行。这些指令没有任何参数,并且都是通过visitInsn方法来访问。因此,我们可以重写这个方法来添加这四条指令:

public void visitInsn(int opcode) {

         if ((opcode >= IRETURN && opcode <= RETURN) || opcode == ATHROW) {

                   mv.visitFieldInsn(GETSTATIC, owner, "timer", "J");

                   mv.visitMethodInsn(INVOKESTATIC, "java/lang/System",

                   "currentTimeMillis", "()J");

                   mv.visitInsn(LADD);

                   mv.visitFieldInsn(PUTSTATIC, owner, "timer", "J");

         }

         mv.visitInsn(opcode);

}

 

最后,我们仍然需要更新操作数栈的大小。这些指令中,我们往操作数栈中放置了两个long行数据,因此需要四个方框。在这个方法开始的时候,这个操作数栈是被初始化为空的,因此我们知道最开始的四条指令需要的栈大小为4.我们也知道,我们插入的代码对这个栈大小没有改变(因为从栈中弹出的数据与入栈的数据一样多)。结果是,如果最初的代码需要的栈大小为s,那么转换方法之后栈的大小的最大值为max(4,s)。不幸地是,我们还需要在RETURN指令之前添加四条指令,在这里我们不知道这个操作数栈的大小。我们只知道它的大小应该小于等于s。最后,我们可以认为在RETURN指令之前添加的代码需要的操作数栈的大小最大为s+4。这种最坏的情形在实际中很少发生:就一般的编译器而言,RETURN指令之前,操作数栈中一般只包含方法的返回值,那么它的大小就可能是0,1或者最大为2.但是,如果我们希望处理所有可能的情况,那么我们应该使用最坏的这种情况。所以,我们需要重写visitMaxs方法:

public void visitMaxs(int maxStack, int maxLocals) {

         mv.visitMaxs(maxStack + 4, maxLocals);

}

 

当然了,我们也不必为操作数栈的大小而烦恼,我们可以依赖于COMPUTE_MAXS选项,它会为我们计算最优的值而不是最坏的值。同时,就这么一个简单的转换,也没必须花费这么经理来手动更新maxStack

 

现在,一个有趣的问题是:如何处理栈映射帧?原始的代码不包含任何帧,转换后的代码页不包含,难道这是因为我们使用的例子很特殊吗?这里是否有一些情形帧必须被更新吗?答案是否定的,因为,第一,插入的代码没有改变操作数栈,第二,插入的代码没有包含跳转指令,第三,这些跳转指令,或者更正式的,程序的控制流没有修改。这意味着原始的帧没有改变,既然新插入的代码没有增加帧,那么原始帧压缩后也没有改变。

 

现在,我们可以将这些元素和ClassAdapter以及MethodAdapter结合起来:

public class AddTimerAdapter extends ClassAdapter {

         private String owner;

         private boolean isInterface;

         public AddTimerAdapter(ClassVisitor cv) {

                   super(cv);

         }

         @Override public void visit(int version, int access, String name,

                   String signature, String superName, String[] interfaces) {

                   cv.visit(version, access, name, signature, superName, interfaces);

                   owner = name;

                   isInterface = (access & ACC_INTERFACE) != 0;

         }

         @Override public MethodVisitor visitMethod(int access, String name,

                   String desc, String signature, String[] exceptions) {

                   MethodVisitor mv = cv.visitMethod(access, name, desc, signature,

                   exceptions);

                   if (!isInterface && mv != null && !name.equals("<init>")) {

                            mv = new AddTimerMethodAdapter(mv);

                   }

         return mv;

         }

         @Override public void visitEnd() {

                   if (!isInterface) {

                            FieldVisitor fv = cv.visitField(ACC_PUBLIC + ACC_STATIC, "timer",

                            "J", null, null);

                            if (fv != null) {

                                     fv.visitEnd();

                            }

                   }

         cv.visitEnd();

}

 

class AddTimerMethodAdapter extends MethodAdapter {

         public AddTimerMethodAdapter(MethodVisitor mv) {

                   super(mv);

         }

         @Override public void visitCode() {

                   mv.visitCode();

                   mv.visitFieldInsn(GETSTATIC, owner, "timer", "J");

                   mv.visitMethodInsn(INVOKESTATIC, "java/lang/System",

                   "currentTimeMillis", "()J");

                   mv.visitInsn(LSUB);

                   mv.visitFieldInsn(PUTSTATIC, owner, "timer", "J");

         }

         @Override public void visitInsn(int opcode) {

                   if ((opcode >= IRETURN && opcode <= RETURN) || opcode == ATHROW) {

                            mv.visitFieldInsn(GETSTATIC, owner, "timer", "J");

                            mv.visitMethodInsn(INVOKESTATIC, "java/lang/System",

                            "currentTimeMillis", "()J");

                            mv.visitInsn(LADD);

                            mv.visitFieldInsn(PUTSTATIC, owner, "timer", "J");

                   }

                   mv.visitInsn(opcode);

         }

         @Override public void visitMaxs(int maxStack, int maxLocals) {

                   mv.visitMaxs(maxStack + 4, maxLocals);

         }

         }

}

 

这里的类适配器是用来实例化方法适配器(除了构造方法),同时也用来添加计时字段和保存将被转换的类名到一个字段中,这样在方法适配器中可以访问到这个类名。

2
1
分享到:
评论

相关推荐

    C32Asm纯正无毒

    - `C32ASM.chm`:这通常是一个CHM(Compiled Help Manual)文件,即编译后的帮助文档,包含C32Asm的使用指南和参考信息。 - `C32asm.dll`:动态链接库文件,可能包含了C32Asm运行时需要的一些函数或服务。 - `C32...

    ASM1153E_固件刷写.zip

    ASM1153E是一款广泛应用在电子设备中的串行ATA(SATA)桥接芯片,它主要用于将SATA接口转换为其他类型的接口,如PCI-E,USB等,以便于数据传输和存储。固件刷写是更新该芯片内嵌软件的过程,以改善性能、修复错误或...

    绿联ASM1153E芯片硬盘盒关闭休眠工具+教程

    总结来说,这个主题涵盖了硬件组件(ASM1153E芯片)、外设优化(关闭休眠)、以及用户操作指南,是关于提升硬盘盒性能和效率的一个实践性教程。如果你需要关闭硬盘盒的休眠功能,这个工具和教程将非常有用。在操作前...

    C32Asm.exe

    1. C32ASM.chm:这是帮助文档,通常包含软件的使用指南、功能介绍和常见问题解答。用户可以通过这个文件快速学习如何使用C32Asm.exe。 2. C32asm.dll:这是一个动态链接库文件,包含了C32Asm.exe运行所需的部分功能...

    asm.rar_asm电机是什么_步进电机_步进电机调速

    这些文档可能包括技术手册、代码示例、电路图和调试指南,帮助用户更好地理解和应用ASM步进电机。 总之,步进电机调速是通过改变脉冲频率、采用细分驱动和精确的正反转控制来实现的。ASM电机作为一个特定的电机类型...

    C32Asm编辑器

    2. **调试功能**:C32Asm编辑器内置了调试工具,允许用户设置断点、单步执行、查看寄存器状态和内存内容,这对于理解程序运行过程和查找错误至关重要。 3. **反汇编和二进制查看**:编辑器可能包含反汇编器功能,...

    训练asm 英文文档

    ### 训练ASM英文文档知识点概述 #### 一、引言 - **Stasm**:一个C++软件包,主要用于定位面部图像中的特征点(即面部标志)。用户提供一张人脸图像,该软件能够返回这些特征点的位置。 - **适用场景**:Stasm主要...

    ASM汇编语言全集,很经典的,希望大家能喜欢

    ASM汇编语言全集是一份宝贵的资源,涵盖了汇编语言的各个方面,对于学习和深入理解计算机底层原理极其有用。汇编语言是计算机编程的一种低级语言,它与机器语言紧密相关,每一行汇编指令几乎都能直接转换为特定的...

    Moving your SAP database to Oracle 11gR2 ASM

    ### 将SAP数据库迁移至Oracle 11g R2 ASM的最佳实践指南 #### 概述 本指南旨在提供一个全面的技术文档,介绍如何将现有的SAP数据库迁移至Oracle 11g R2 ASM(自动存储管理)环境,并强调最佳实践以确保数据完整性和...

    反汇编工具 win32asm

    描述中提到的“汉化了的,好用”,意味着这个win32asm工具已经被翻译成了中文,这对于中文用户来说是一个极大的便利,因为它消除了语言障碍,使得不懂英文的开发者也能轻松使用。通常,反汇编器的界面和文档都是英文...

    MCS51_ASM_IDE_2812

    《MCS51_ASM_IDE_2812:全面解析单片机开发的强大工具》 在电子工程和嵌入式系统的世界里,MCS51系列单片机以其高效能和广泛应用而闻名。为了更好地支持这些单片机的开发工作,出现了"MCS51_ASM_IDE_2812"这样的...

    OTIS-电梯系统文件

    - 2004-12-14: M. Müller, P. Walden 和 G. Blechschmidt 发布版本 - 2005-02-02: G. Blechschmidt 进行了小幅度修正 - 2005-04-08: G. Blechschmidt 适应新版本 GAA30785AAC,并增加了 ASM 机器类型 (MCS220 ...

    杭电微机原理AD转换DA转换实验实验报告.pdf

    2. 在PC机和实验系统联机状态下,新建实验程序,编辑完成后进行保存(保存后缀为.asm 文件)。 3. 编译下载。 4. 全速运行,运行程序。 5. 按 RST 键退出。 七、实验程序 实验程序主要包括两个部分:数据段和代码...

    HairOracle数据库运维手册.docx

    - **视图V$ASM_DISK**:列出ASM实例中的所有磁盘及其状态。 - **常用方法** - **如何确定ASM实例的编号**:解释如何查找ASM实例的标识符。 - **查询DG-RAW-磁盘的对应关系**:查询diskgroup与磁盘之间的关联。 ...

    ARM编译器参考指南

    ### ARM编译器参考指南知识点总结 #### 一、ARM RealView 编译工具 (RVCT) 概述 **1.1 关于ARM编译器** - **RealView 编译工具 (RVCT)**:这是一套由ARM公司开发的专业编译工具,主要用于ARM架构下的软件开发。 -...

    ds18.rar_DS18B20 ASM_ds18

    标题中的“ds18.rar_DS18B20 ASM_ds18”暗示了这个压缩包主要涉及DS18B20数字温度传感器的程序代码,其中可能包含了使用汇编语言(ASM)编写的代码。DS18B20是一款单线数字温度传感器,由达拉斯半导体(现为Maxim ...

    MCS51_ASM_IDE

    【MCS51_ASM_IDE】是一款专为51系列微控制器设计的汇编语言集成开发环境(IDE),它提供了全面的功能,使开发者能够高效地编写、编译和调试51汇编代码。51汇编器是这个IDE的核心部分,它支持8051、8052等51家族的微...

    Intel® 64 and IA-32 Architectures Software Developer’s Manual

    《Intel® 64 and IA-32 Architectures Software Developer’s Manual》是Intel公司为开发者提供的权威指南,详细阐述了Intel 64(也称为x86-64)和IA-32架构的硬件特性、指令集以及编程模型。这份手册对于深入理解...

Global site tag (gtag.js) - Google Analytics