读书人

ASM指南通译-13 有状态转换

发布时间: 2012-12-21 12:03:49 作者: rapoo

ASM指南翻译-13 有状态转换

3.2.5有状态转换



?

每个转换都会以一个条件作为标签(就是当前的指令)以及一个动作(一个必须被执行的指令序列,以粗体表示)。例如从S1到S0的转换,只有当前的指令不是ALOAD 0时才进行。在这种情形下,ALOAD 0会被访问然到达初始状态。来看看S2到自身的转换:如果找到3个或者更多的连续的ALOAD 0指令,那么将进行S2到自身的转换。在这种情形下,我们会停留在这样的状态:两条ALOAD 0指令已经被访问,同时我们将再执行一个ALOAD 0指令。一旦这个状态机模型被找到,那么编写对应的方法适配器就很直接了(下面的8个switch case就对应着上面的8个转换):

class RemoveGetFieldPutFieldAdapter extendsPatternMethodAdapter {

???????? privatefinal static int SEEN_ALOAD_0 = 1;

???????? privatefinal static int SEEN_ALOAD_0ALOAD_0 = 2;

???????? privatefinal static int SEEN_ALOAD_0ALOAD_0GETFIELD = 3;

???????? privateString fieldOwner;

???????? privateString fieldName;

???????? privateString fieldDesc;

????????

???????? publicRemoveGetFieldPutFieldAdapter(MethodVisitor mv) {

?????????????????? super(mv);

???????? }

???????? @Override

???????? publicvoid visitVarInsn(int opcode, int var) {

?????????????????? switch(state) {

?????????????????? caseSEEN_NOTHING: // S0 -> S1

??????????????????????????? if(opcode == ALOAD && var == 0) {

??????????????????????????? state= SEEN_ALOAD_0;

??????????????????????????? return;

??????????????????????????? }

??????????????????????????? break;

?????????????????? caseSEEN_ALOAD_0: // S1 -> S2

??????????????????????????? if(opcode == ALOAD && var == 0) {

??????????????????????????? state= SEEN_ALOAD_0ALOAD_0;

??????????????????????????? return;

??????????????????????????? }

??????????????????????????? break;

?????????????????? caseSEEN_ALOAD_0ALOAD_0: // S2 -> S2

??????????????????????????? if(opcode == ALOAD && var == 0) {

??????????????????????????? mv.visitVarInsn(ALOAD,0);

??????????????????????????? return;

??????????????????????????? }

??????????????????????????? break;

?????????????????? }

?????????????????? visitInsn();

?????????????????? mv.visitVarInsn(opcode,var);

???????? }

???????? @Override

???????? publicvoid visitFieldInsn(int opcode, String owner, String name,

?????????????????? Stringdesc) {

?????????????????? switch(state) {

?????????????????? caseSEEN_ALOAD_0ALOAD_0: // S2 -> S3

??????????????????????????? if(opcode == GETFIELD) {

??????????????????????????? state= SEEN_ALOAD_0ALOAD_0GETFIELD;

??????????????????????????? fieldOwner= owner;

??????????????????????????? fieldName= name;

??????????????????????????? fieldDesc= desc;

??????????????????????????? return;

??????????????????????????? }

??????????????????????????? break;

?????????????????? caseSEEN_ALOAD_0ALOAD_0GETFIELD: // S3 -> S0

??????????????????????????? if(opcode == PUTFIELD && name.equals(fieldName)) {

??????????????????????????? state= SEEN_NOTHING;

??????????????????????????? return;

??????????????????????????? }

??????????????????????????? break;

?????????????????? }

?????????????????? visitInsn();

?????????????????? mv.visitFieldInsn(opcode,owner, name, desc);

???????? }

???????? @Overrideprotected void visitInsn() {

?????????????????? switch(state) {

?????????????????? caseSEEN_ALOAD_0: // S1 -> S0

??????????????????????????? mv.visitVarInsn(ALOAD,0);

??????????????????????????? break;

?????????????????? caseSEEN_ALOAD_0ALOAD_0: // S2 -> S0

??????????????????????????? mv.visitVarInsn(ALOAD,0);

??????????????????????????? mv.visitVarInsn(ALOAD,0);

??????????????????????????? break;

?????????????????? caseSEEN_ALOAD_0ALOAD_0GETFIELD: // S3 -> S0

??????????????????????????? mv.visitVarInsn(ALOAD,0);

??????????????????????????? mv.visitVarInsn(ALOAD,0);

??????????????????????????? mv.visitFieldInsn(GETFIELD,fieldOwner, fieldName, fieldDesc);

??????????????????????????? break;

?????????????????? }

?????????????????? state= SEEN_NOTHING;

???????? }

}

?

注意,因为和3.2.4节中AddTimerAdapter相似的原因,本节中出现的有状态转换不需要转换栈映射帧:原始的帧仍在转换之后然有效。也不需要转换局部变量和操作数栈的大小。最后,注意有状态转换不局限于检测和转换指令序列,还有很多其它类型的转换也是状态转换。下一节出现的有关方法适配器就是这样的例子。

读书人网 >编程

热点推荐