随笔-204  评论-149  文章-0  trackbacks-0
查到一篇使用BCEL了,Java 编程的动态性,第 7 部分: 用 BCEL 设计字节码,网址是http://www-128.ibm.com/developerworks/cn/java/j-dyn0414/

字节码处理的工具也挺多,什么时候再看看asm
import java.io.FileOutputStream;

import org.apache.bcel.Constants;
import org.apache.bcel.classfile.ClassParser;
import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;
import org.apache.bcel.generic.ClassGen;
import org.apache.bcel.generic.ConstantPoolGen;
import org.apache.bcel.generic.GETSTATIC;
import org.apache.bcel.generic.INVOKEVIRTUAL;
import org.apache.bcel.generic.InstructionConstants;
import org.apache.bcel.generic.InstructionFactory;
import org.apache.bcel.generic.InstructionList;
import org.apache.bcel.generic.MethodGen;
import org.apache.bcel.generic.ObjectType;
import org.apache.bcel.generic.PUSH;
import org.apache.bcel.generic.Type;



public class BCELTiming {
    
    
    
private static void addWrapper(ClassGen cgen,Method method){
        
//set up the construction tools
        InstructionFactory ifact = new InstructionFactory(cgen);
        InstructionList ilist 
= new InstructionList();
        ConstantPoolGen pgen 
= cgen.getConstantPool();
        String cname 
= cgen.getClassName();
        MethodGen wrapgen 
= new MethodGen(method,cname,pgen);
        wrapgen.setInstructionList(ilist);
        
        
//rename a copy of the original method
        MethodGen methgen = new MethodGen(method,cname,pgen);
        cgen.removeMethod(method);
        String iname 
= methgen.getName()+"$impl";
        methgen.setName(iname);
        cgen.addMethod(methgen.getMethod());
        Type returnType 
= methgen.getReturnType();
        
//        methgen.addLocalVariable(name, type, slot, start, end)
        
        Type[] types 
= methgen.getArgumentTypes();
        
int slot = methgen.isStatic()?0:1;//非静态方法slot 0处应该存储的是this
        //// 这种方式与Java如何处理方法调用有关。对于非静态的方法,每次调用的第一个(隐藏的)参数是目标对象的this引用(就是位置0储存的内容)。
        for(int i = 0;i<types.length;i++){
            slot 
+= types[i].getSize();//long,double的size为2
        }

        
        
//save time prior to invocation
        
//createInvoke在常量池增加了 addMethodref,并且addMethodref方法会先在常量池中查找是否有这个方法存在,没有则创建一系列的与此方法相关的常量池内容
        
//看看这个方法是怎么实现的,为什么此方法中INVOKEINTERFACE的要有nargs
        
//InstructionFactory的实例方法一般要用到cp在常量池中添加引用,其静态的方法一般只是创建一些指令,而这些指令不需要在常量池添加内容
        
//INVOKEXXXXX指令包括一个index指示此方法在常量池中的索引
        //// 调用静态的long java.lang.System.currentTimeMillis()方法,调用结束后函数的返回的long类型的值会压入operand stack操作数堆栈
        ilist.append(ifact.createInvoke("java.lang.System""currentTimeMillis"
                Type.LONG, Type.NO_ARGS, Constants.INVOKESTATIC));
//currentTimemillis()的方法结果在operand stack栈顶
        
        
//createStore方法生成了XSTORE指令,弹出operand stack栈顶的元素写入到某个局部变量中,
        
//参照之前打印出的局部变量的信息可以知道若是实例方法则 index=0处保留的this,之后是用到的方法参数的index,然后是方法内定义的局部变量
        
//slot标记在局部变量中的位置,
        
//这个局部变量没有设置名称????????
        ilist.append(InstructionFactory.createStore(Type.LONG, slot));
        
        
//call the wrapped method
        int offset =0;
        
short invoke = Constants.INVOKESTATIC;
        
//如果是实例方法则load this到栈中
        if(!methgen.isStatic()){
            
//// 如果不是调用静态函数,将调用的第一个(隐藏的)参数(目标对象的this引用)压入operand stack
            ilist.append(InstructionFactory.createLoad(Type.OBJECT, 0));
            offset 
=1;
            invoke 
= Constants.INVOKESPECIAL;
        }

        
//load 参数到栈中
        for(int i=0;i<types.length;i++){
            Type type 
= types[i];
            ilist.append(InstructionFactory.createLoad(type, offset));
// 按参数类型把参数一个个从本地变量堆栈取出,压入operand stack
            
//Long Double的size为2,void为0,其他的为1
            offset += type.getSize();
        }

        
        
//执行方法buildString$impl()
        ilist.append(ifact.createInvoke(cname, iname, 
                returnType, types, invoke));
//消耗oprand stack的this参数和length参数
                                            
//并将结果保存在操作数的栈顶
        
        
//stor result for return later
        if(returnType != Type.VOID){
            
//+2是因为之前加的的long局部变量占两个2个字,这个字是虚拟机定义的,一般为32位
            //// 将名为iname的函数返回值复制到本地变量堆栈的slot+2的位置上
            ilist.append(InstructionFactory.createStore(returnType,slot+2));
        }

        
        
//print time required for method call
        
//createFieldAccess中的 addFieldref方法先在ConstantFieldref常量池中根据type的描述符创建引用
        
//然后根据kind来创建是GETFIELD,PUTFIELD,GETSTATIC,PUTSTATIC哪个指令
        //// 获取静态对象java.lang.System.out的引用,返回值压入operand stack
        ilist.append(ifact.createFieldAccess("java.lang.System"
                , 
"out"new ObjectType("java.io.PrintStream"), 
                Constants.GETSTATIC));
//out会在栈顶
        
        
//ilist.append(InstructionFactory.createDup(1));
        ilist.append(InstructionConstants.DUP);//复制栈顶元素out
        ilist.append(InstructionConstants.DUP);//在复制,当前栈顶前三元素都为out引用,供下面的三次print使用out引用
        
        String text 
= "Call to method "+methgen.getName()+" took ";
        
//实际还是调的new LDC
        ilist.append(new PUSH(pgen,text));
        
        ilist.append(ifact.createInvoke(
"java.io.PrintStream"
                
"print", Type.VOID, new Type[]{Type.STRING}
                Constants.INVOKEVIRTUAL));
//消耗调一个out和栈顶的一个元素
                                         
// 调用结束,operand stack弹出一个String的引用和一个out的引用(还剩2个out),函数没有返回值
        
        ilist.append(ifact.createInvoke(
"java.lang.System"
                
"currentTimeMillis", Type.LONG, Type.NO_ARGS, 
                Constants.INVOKESTATIC));
//operand stack栈顶保留此方法的结果,即结束时间
                                         
//调用java.lang.System.currentTimeMillis()方法,调用结束后函数的返回的long类型的值会压入堆栈operand 
        
        
//load 局部变量到栈顶
        
//从本地变量堆栈的slot位置载入先前储存的long值,压入operand stack
        ilist.append(InstructionFactory.createLoad(Type.LONG, slot));
        
        
//栈顶两个元素进行减法操作,结果保存在栈顶
        
// 调用long的减法指令,弹出2个long值,并把结果压入operand stack,现在operand stack的top第一个是long,第二个是out的引用
        ilist.append(InstructionConstants.LSUB);
        
        ilist.append(ifact.createInvoke(
"java.io.PrintStream"
                
"print", Type.VOID, new Type[]{Type.LONG}
                Constants.INVOKEVIRTUAL));
//消耗一个out,和减法的结果
        
        
// 将String对象" ms."放入pgen,并把其在pgen的引用(这个引用其实是字符串在常量池中的索引下标)压入operand stack(供out.print(Sting)调用的参数)
        ilist.append(new PUSH(pgen," ms."));//常量入栈,首先会判断常量池中是否有此字符串
        ilist.append(ifact.createInvoke("java.io.PrintStream"
                
"println", Type.VOID, new Type[]{Type.STRING}
                Constants.INVOKEVIRTUAL));
//消耗调最后一个out和刚入栈的" ms."
        
        
//如果返回类型不为void,则将返回结果入栈并返回
        if(returnType != Type.VOID){
            
//处理返回值,如果不为空,从本地局部对象堆栈的slot+2位置读取指定类型的返回值压入operand stack
            ilist.append(InstructionFactory.createLoad(returnType, slot+2));
        }

        
        ilist.append(InstructionFactory.createReturn(returnType));
//根据相应的返回类型创建相应的返回指令
        
        
        
//finalize the construted method
        wrapgen.stripAttributes(true);
        wrapgen.setMaxStack();
        wrapgen.setMaxLocals();
        cgen.addMethod(wrapgen.getMethod());
        ilist.dispose();
        
        
        
        
        
/*
         * ifact.createPrintln(s)
         * 
         *     public InstructionList createPrintln( String s ) {
        InstructionList il = new InstructionList();
        int out = cp.addFieldref("java.lang.System", "out", "Ljava/io/PrintStream;");
        int println = cp.addMethodref("java.io.PrintStream", "println", "(Ljava/lang/String;)V");
        il.append(new GETSTATIC(out));
        il.append(new PUSH(cp, s));
        il.append(new INVOKEVIRTUAL(println));
        return il;
    }
         
*/

        
        
    }


    
/**
     * 
@param args
     
*/

    
public static void main(String[] args) {
        
        args[
0]="D:\\java to eclipse\\javaeclipsestudy\\workspace\\BCELTest\\bin\\StringBuilder.class";
        args[
1]="buildString";
        String targetClassfile 
= "StringBuilder.class";
        
if(args.length==2 && args[0].endsWith(".class")){
            
try{
                JavaClass jclas 
= new ClassParser(args[0]).parse();
                
                ClassGen cgen 
= new ClassGen(jclas);
                Method[] methods 
= jclas.getMethods();
                
                
int index;
                
for(index =0;index<methods.length;index++){
                    
if(methods[index].getName().equals(args[1])){
                        
break;
                    }

                }

                
if(index<methods.length){
                    addWrapper(cgen,methods[index]);
                    FileOutputStream fos 
= new FileOutputStream(targetClassfile);
                    cgen.getJavaClass().dump(fos);
                    fos.close();
                }
else{
                    System.err.println(
"Method " + args[1]+"not found in"+ args[0]);
                }

            }
catch(Exception e){
                e.printStackTrace();
            }

        }
else{
            System.out.println(
"usage: class-file method-name");
        }


    }


}




public class StringBuilder
{
    
private String buildString$impl(int length) {
        String result 
= "";
        
for (int i = 0; i < length; i++{
            result 
+= (char)(i%26 + 'a');
        }

        
return result;
    }

    
    
private String buildString(int length) {
        
long start = System.currentTimeMillis();
        String result 
= buildString$impl(length);
        System.out.println(
"Call to buildString$impl took " +
            (System.currentTimeMillis()
-start) + " ms.");
        
return result;
    }

    
    
public static void main(String[] argv) {
        StringBuilder inst 
= new StringBuilder();
        
for (int i = 0; i < argv.length; i++{
            String result 
= inst.buildString(Integer.parseInt(argv[i]));
            System.out.println(
"Constructed string of length " +
                result.length());
        }

    }

}



字节码
--------------------------------33
--------------------------------33
0
2
CONSTANT_Utf8[
1]("SourceFile")
true
CONSTANT_Utf8[
1]("StringBuilder.java")
1
StringBuilder.java
StringBuilder.java
---------------------------------------------------------------------------
1:CONSTANT_Class[7](name_index = 2)
2:CONSTANT_Utf8[1]("StringBuilder")
3:CONSTANT_Class[7](name_index = 4)
4:CONSTANT_Utf8[1]("java/lang/Object")
5:CONSTANT_Utf8[1]("<init>")
6:CONSTANT_Utf8[1]("()V")
7:CONSTANT_Utf8[1]("Code")
8:CONSTANT_Methodref[10](class_index = 3, name_and_type_index = 9)
9:CONSTANT_NameAndType[12](name_index = 5, signature_index = 6)
10:CONSTANT_Utf8[1]("LineNumberTable")
11:CONSTANT_Utf8[1]("LocalVariableTable")
12:CONSTANT_Utf8[1]("this")
13:CONSTANT_Utf8[1]("LStringBuilder;")
14:CONSTANT_Utf8[1]("buildString$impl")
15:CONSTANT_Utf8[1]("(I)Ljava/lang/String;")
16:CONSTANT_String[8](string_index = 17)
17:CONSTANT_Utf8[1]("")
18:CONSTANT_Class[7](name_index = 19)
19:CONSTANT_Utf8[1]("java/lang/StringBuilder")
20:CONSTANT_Methodref[10](class_index = 21, name_and_type_index = 23)
21:CONSTANT_Class[7](name_index = 22)
22:CONSTANT_Utf8[1]("java/lang/String")
23:CONSTANT_NameAndType[12](name_index = 24, signature_index = 25)
24:CONSTANT_Utf8[1]("valueOf")
25:CONSTANT_Utf8[1]("(Ljava/lang/Object;)Ljava/lang/String;")
26:CONSTANT_Methodref[10](class_index = 18, name_and_type_index = 27)
27:CONSTANT_NameAndType[12](name_index = 5, signature_index = 28)
28:CONSTANT_Utf8[1]("(Ljava/lang/String;)V")
29:CONSTANT_Methodref[10](class_index = 18, name_and_type_index = 30)
30:CONSTANT_NameAndType[12](name_index = 31, signature_index = 32)
31:CONSTANT_Utf8[1]("append")
32:CONSTANT_Utf8[1]("(C)Ljava/lang/StringBuilder;")
33:CONSTANT_Methodref[10](class_index = 18, name_and_type_index = 34)
34:CONSTANT_NameAndType[12](name_index = 35, signature_index = 36)
35:CONSTANT_Utf8[1]("toString")
36:CONSTANT_Utf8[1]("()Ljava/lang/String;")
37:CONSTANT_Utf8[1]("length")
38:CONSTANT_Utf8[1]("I")
39:CONSTANT_Utf8[1]("result")
40:CONSTANT_Utf8[1]("Ljava/lang/String;")
41:CONSTANT_Utf8[1]("i")
42:CONSTANT_Utf8[1]("buildString")
43:CONSTANT_Methodref[10](class_index = 44, name_and_type_index = 46)
44:CONSTANT_Class[7](name_index = 45)
45:CONSTANT_Utf8[1]("java/lang/System")
46:CONSTANT_NameAndType[12](name_index = 47, signature_index = 48)
47:CONSTANT_Utf8[1]("currentTimeMillis")
48:CONSTANT_Utf8[1]("()J")
49:CONSTANT_Methodref[10](class_index = 1, name_and_type_index = 50)
50:CONSTANT_NameAndType[12](name_index = 14, signature_index = 15)
51:CONSTANT_Fieldref[9](class_index = 44, name_and_type_index = 52)
**********************************************************************
cc.toString : CONSTANT_Class[
7](name_index = 45)
java
/lang/System
cnat.toString : CONSTANT_NameAndType[
12](name_index = 53, signature_index = 54)
out
Ljava
/io/PrintStream;
**********************************************************************
52:CONSTANT_NameAndType[12](name_index = 53, signature_index = 54)
53:CONSTANT_Utf8[1]("out")
54:CONSTANT_Utf8[1]("Ljava/io/PrintStream;")
55:CONSTANT_String[8](string_index = 56)
56:CONSTANT_Utf8[1]("Call to buildString$impl took ")
57:CONSTANT_Methodref[10](class_index = 18, name_and_type_index = 58)
58:CONSTANT_NameAndType[12](name_index = 31, signature_index = 59)
59:CONSTANT_Utf8[1]("(J)Ljava/lang/StringBuilder;")
60:CONSTANT_String[8](string_index = 61)
61:CONSTANT_Utf8[1](" ms.")
62:CONSTANT_Methodref[10](class_index = 18, name_and_type_index = 63)
63:CONSTANT_NameAndType[12](name_index = 31, signature_index = 64)
64:CONSTANT_Utf8[1]("(Ljava/lang/String;)Ljava/lang/StringBuilder;")
65:CONSTANT_Methodref[10](class_index = 66, name_and_type_index = 68)
66:CONSTANT_Class[7](name_index = 67)
67:CONSTANT_Utf8[1]("java/io/PrintStream")
68:CONSTANT_NameAndType[12](name_index = 69, signature_index = 28)
69:CONSTANT_Utf8[1]("println")
70:CONSTANT_Utf8[1]("start")
71:CONSTANT_Utf8[1]("J")
72:CONSTANT_Utf8[1]("main")
73:CONSTANT_Utf8[1]("([Ljava/lang/String;)V")
74:CONSTANT_Methodref[10](class_index = 1, name_and_type_index = 9)
75:CONSTANT_Methodref[10](class_index = 76, name_and_type_index = 78)
76:CONSTANT_Class[7](name_index = 77)
77:CONSTANT_Utf8[1]("java/lang/Integer")
78:CONSTANT_NameAndType[12](name_index = 79, signature_index = 80)
79:CONSTANT_Utf8[1]("parseInt")
80:CONSTANT_Utf8[1]("(Ljava/lang/String;)I")
81:CONSTANT_Methodref[10](class_index = 1, name_and_type_index = 82)
82:CONSTANT_NameAndType[12](name_index = 42, signature_index = 15)
83:CONSTANT_String[8](string_index = 84)
84:CONSTANT_Utf8[1]("Constructed string of length ")
85:CONSTANT_Methodref[10](class_index = 21, name_and_type_index = 86)
86:CONSTANT_NameAndType[12](name_index = 37, signature_index = 87)
87:CONSTANT_Utf8[1]("()I")
88:CONSTANT_Methodref[10](class_index = 18, name_and_type_index = 89)
89:CONSTANT_NameAndType[12](name_index = 31, signature_index = 90)
90:CONSTANT_Utf8[1]("(I)Ljava/lang/StringBuilder;")
91:CONSTANT_Utf8[1]("argv")
92:CONSTANT_Utf8[1]("[Ljava/lang/String;")
93:CONSTANT_Utf8[1]("inst")
94:CONSTANT_Utf8[1]("SourceFile")
95:CONSTANT_Utf8[1]("StringBuilder.java")
------------------------------------------------------
------------------------------------------------------
start method method method
-----------------------------------
方法访问标志
1
方法访问名称
me[i].getName()  
<init>
CONSTANT_Utf8[
1]("<init>")
方法签名
()V
CONSTANT_Utf8[
1]("()V")
方法的参数类型
[Lorg.apache.bcel.generic.Type;@54172f
方法的返回类型
void
方法的Code
public void <init>()
Code(max_stack 
= 1, max_locals = 1, code_length = 5)
0:    aload_0
1:    invokespecial    java.lang.Object.<init> ()V (8)
4:    return

Attribute(s) 
= 
LineNumber(
02)
LocalVariable(start_pc 
= 0, length = 5, index = 0:StringBuilder this)

end method method method
-----------------------------------
start method method method
-----------------------------------
方法访问标志
2
方法访问名称
me[i].getName()  buildString$impl
CONSTANT_Utf8[
1]("buildString$impl")
方法签名
(I)Ljava
/lang/String;
CONSTANT_Utf8[
1]("(I)Ljava/lang/String;")
方法的参数类型
[Lorg.apache.bcel.generic.Type;@1ed2ae8
方法的返回类型
java.lang.String
方法的Code
private String buildString$impl(int length)
Code(max_stack 
= 3, max_locals = 4, code_length = 44)
0:    ldc        "" (16)
2:    astore_2
3:    iconst_0
4:    istore_3
5:    goto        #37
8:    new        <java.lang.StringBuilder> (18)
11:   dup
12:   aload_2
13:   invokestatic    java.lang.String.valueOf (Ljava/lang/Object;)Ljava/lang/String; (20)
16:   invokespecial    java.lang.StringBuilder.<init> (Ljava/lang/String;)V (26)
19:   iload_3
20:   bipush        26
22:   irem
23:   bipush        97
25:   iadd
26:   i2c
27:   invokevirtual    java.lang.StringBuilder.append (C)Ljava/lang/StringBuilder; (29)
30:   invokevirtual    java.lang.StringBuilder.toString ()Ljava/lang/String; (33)
33:   astore_2
34:   iinc        %3    1
37:   iload_3
38:   iload_1
39:   if_icmplt        #8
42:   aload_2
43:   areturn

Attribute(s) 
= 
LineNumber(
05), LineNumber(36), LineNumber(87), LineNumber(346), 
LineNumber(
429)
LocalVariable(start_pc 
= 0, length = 44, index = 0:StringBuilder this)
LocalVariable(start_pc 
= 0, length = 44, index = 1:int length)
LocalVariable(start_pc 
= 3, length = 41, index = 2:String result)
LocalVariable(start_pc 
= 5, length = 37, index = 3:int i)

end method method method
-----------------------------------
start method method method
-----------------------------------
方法访问标志
2
方法访问名称
me[i].getName()  buildString
CONSTANT_Utf8[
1]("buildString")
方法签名
(I)Ljava
/lang/String;
CONSTANT_Utf8[
1]("(I)Ljava/lang/String;")
方法的参数类型
[Lorg.apache.bcel.generic.Type;@19c26f5
方法的返回类型
java.lang.String
方法的Code
private String buildString(int length)
Code(max_stack 
= 6, max_locals = 5, code_length = 45)
0:    invokestatic    java.lang.System.currentTimeMillis ()J (43)
3:    lstore_2
4:    aload_0
5:    iload_1
6:    invokespecial    StringBuilder.buildString$impl (I)Ljava/lang/String; (49)
9:    astore        %4
11:   getstatic        java.lang.System.out Ljava/io/PrintStream; (51)
14:   new        <java.lang.StringBuilder> (18)
17:   dup
18:   ldc        "Call to buildString$impl took " (55)
20:   invokespecial    java.lang.StringBuilder.<init> (Ljava/lang/String;)V (26)
23:   invokestatic    java.lang.System.currentTimeMillis ()J (43)
26:   lload_2
27:   lsub
28:   invokevirtual    java.lang.StringBuilder.append (J)Ljava/lang/StringBuilder; (57)
31:   ldc        " ms." (60)
33:   invokevirtual    java.lang.StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; (62)
36:   invokevirtual    java.lang.StringBuilder.toString ()Ljava/lang/String; (33)
39:   invokevirtual    java.io.PrintStream.println (Ljava/lang/String;)V (65)
42:   aload        %4
44:   areturn

Attribute(s) 
= 
LineNumber(
013), LineNumber(414), LineNumber(1115), LineNumber(2316), 
LineNumber(
3915), LineNumber(4217)
LocalVariable(start_pc 
= 0, length = 45, index = 0:StringBuilder this)
LocalVariable(start_pc 
= 0, length = 45, index = 1:int length)
LocalVariable(start_pc 
= 4, length = 41, index = 2:long start)
LocalVariable(start_pc 
= 11, length = 34, index = 4:String result)

end method method method
-----------------------------------
start method method method
-----------------------------------
方法访问标志
9
方法访问名称
me[i].getName()  main
CONSTANT_Utf8[
1]("main")
方法签名
([Ljava
/lang/String;)V
CONSTANT_Utf8[
1]("([Ljava/lang/String;)V")
方法的参数类型
[Lorg.apache.bcel.generic.Type;@c1b531
方法的返回类型
void
方法的Code
public static void main(String[] argv)
Code(max_stack 
= 4, max_locals = 4, code_length = 59)
0:    new        <StringBuilder> (1)
3:    dup
4:    invokespecial    StringBuilder.<init> ()V (74)
7:    astore_1
8:    iconst_0
9:    istore_2
10:   goto        #52
13:   aload_1
14:   aload_0
15:   iload_2
16:   aaload
17:   invokestatic    java.lang.Integer.parseInt (Ljava/lang/String;)I (75)
20:   invokespecial    StringBuilder.buildString (I)Ljava/lang/String; (81)
23:   astore_3
24:   getstatic        java.lang.System.out Ljava/io/PrintStream; (51)
27:   new        <java.lang.StringBuilder> (18)
30:   dup
31:   ldc        "Constructed string of length " (83)
33:   invokespecial    java.lang.StringBuilder.<init> (Ljava/lang/String;)V (26)
36:   aload_3
37:   invokevirtual    java.lang.String.length ()I (85)
40:   invokevirtual    java.lang.StringBuilder.append (I)Ljava/lang/StringBuilder; (88)
43:   invokevirtual    java.lang.StringBuilder.toString ()Ljava/lang/String; (33)
46:   invokevirtual    java.io.PrintStream.println (Ljava/lang/String;)V (65)
49:   iinc        %2    1
52:   iload_2
53:   aload_0
54:   arraylength
55:   if_icmplt        #13
58:   return

Attribute(s) 
= 
LineNumber(
021), LineNumber(822), LineNumber(1323), LineNumber(2424), 
LineNumber(
3625), LineNumber(4624), LineNumber(4922), LineNumber(5827)

LocalVariable(start_pc 
= 0, length = 59, index = 0:String[] argv)
LocalVariable(start_pc 
= 8, length = 51, index = 1:StringBuilder inst)
LocalVariable(start_pc 
= 10, length = 48, index = 2:int i)
LocalVariable(start_pc 
= 24, length = 25, index = 3:String result)

end method method method
-----------------------------------

posted on 2009-08-13 15:58 Frank_Fang 阅读(1355) 评论(7)  编辑  收藏 所属分类: bcel javassist

评论:
# re: 用 BCEL 设计字节码 2009-08-13 16:13 | Frank_Fang
Java虚拟机框架(frame)翻译为帧是不是更贴切些
用于存储数据和部分结果,以及进行动态链接,返回方法的值和调度异常
每次Java方法被调用时创建一个新的frame,当frame的方法结束时,不论正常的,还是不正常的结束(通过抛出一个异常)框架从创建该框架的线程的Java栈分配,每个frame有它自己的局部变量集,和自己的操作数栈,这些结构的存储器空间可以同时分配,因为局部变量区和操作数栈的大小是编译期已知的。

总的来说要把方法的局部变量集搞清楚,以及方法的操作数栈的当前状态搞清楚,以及每个jvm指令会对栈产生什么影响搞清楚。
下一步在仔细研究一下修改class文件的其他东西。  回复  更多评论
  
# re: 用 BCEL 设计字节码 2009-08-13 16:15 | Frank_Fang
也可以看出String s = s+"ddd";时采用的是java.lang.StringBuilder来进行操作的
以及对于String s="abc" 与String s = new String("abc")这个字符串常量池就很清楚了  回复  更多评论
  
# re: 用 BCEL 设计字节码 2009-08-13 18:43 | Frank_Fang
public class AASTOREextends ArrayInstructionimplements StackConsumerAASTORE - Store into reference array

Stack: ..., arrayref, index, value -> ...


public class AALOADextends ArrayInstructionimplements StackProducerAALOAD - Load reference from array

<red>Stack: ..., arrayref, index -> value</red>  回复  更多评论
  
# re: 用 BCEL 设计字节码 2009-08-13 19:54 | Frank_Fang
private String buildString(int)

Attributes
Code
Byte
offset Instruction Argument
0 invokestatic System.currentTimeMillis ()J():long
3 lstore_2
4 aload_0
5 iload_1
6 invokespecial StringBuilder.buildString$impl (I)Ljava/lang/String;(int):String
9 astore %4
11 getstatic System.out Ljava/io/PrintStream;
14 dup
15 dup
16 ldc "Call to method buildString$impl took "
18 invokevirtual java.io.PrintStream.print (Ljava/lang/String;)V(String):void
21 invokestatic System.currentTimeMillis ()J():long
24 lload_2
25 lsub
26 invokevirtual java.io.PrintStream.print (J)V(long):void
29 ldc " ms."
31 invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V(String):void
34 aload %4
36 areturn


实际生成的字节码中没有方法的Code属性的LocalVariableTable
LineNumberTable 信息
  回复  更多评论
  
# re: 用 BCEL 设计字节码[未登录] 2009-08-14 23:55 | alex
实际生成的字节码中没有方法的Code属性的LocalVariableTable
LineNumberTable 信息 ???
这个为什么没有这些信息了?不知道你想过没有???
  回复  更多评论
  
# re: 用 BCEL 设计字节码 2009-08-15 00:17 | Frank_Fang
@alex
这个我现在还不太清楚
wrapgen.stripAttributes(true);
这个好像设置成false是生成lineNumber和Localvariabel Attribute的信息
但是我设置成false之后,允许生成的代码就报错误了
Exception in thread "main" java.lang.ClassFormatError: Invalid length 44 in Loca
lVariableTable in class file StringBuilder
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:621)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:12
4)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
at java.net.URLClassLoader.access$000(URLClassLoader.java:56)
at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:307)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:252)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)
Could not find the main class: StringBuilder. Program will exit.


  回复  更多评论
  
# re: 用 BCEL 设计字节码 2009-08-15 19:58 | Frank_Fang
@alex
把stripAtrribute设置成false后,即新的方法生成linenumber和localvariable属性

这是原先的属性信息
private String buildString$impl(int length)
Code(max_stack = 3, max_locals = 4, code_length = 51)
0: ldc "" (16)
2: astore_2
3: iconst_0
4: istore_3
5: goto #37
8: new <java.lang.StringBuilder> (18)
11: dup
12: aload_2
13: invokestatic java.lang.String.valueOf (Ljava/lang/Object;)Ljava/lang/String; (20)
16: invokespecial java.lang.StringBuilder.<init> (Ljava/lang/String;)V (26)
19: iload_3
20: bipush 26
22: irem
23: bipush 97
25: iadd
26: i2c
27: invokevirtual java.lang.StringBuilder.append (C)Ljava/lang/StringBuilder; (29)
30: invokevirtual java.lang.StringBuilder.toString ()Ljava/lang/String; (33)
33: astore_2
34: iinc %3 1
37: iload_3
38: iload_1
39: if_icmplt #8
42: getstatic java.lang.System.out Ljava/io/PrintStream; (37)
45: aload_2
46: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (43)
49: aload_2
50: areturn

Attribute(s) =
LocalVariable(start_pc = 0, length = 51, index = 0:StringBuilder this)
LocalVariable(start_pc = 0, length = 51, index = 1:int length)
LocalVariable(start_pc = 3, length = 48, index = 2:String result)
LocalVariable(start_pc = 5, length = 40, index = 3:int i)
LineNumber(0, 6), LineNumber(3, 7), LineNumber(8, 8), LineNumber(34, 7),
LineNumber(42, 10), LineNumber(49, 12)


--------------------------------------------------------
完整的code.toString的信息
private String buildString(int length)
Code(max_stack = 6, max_locals = 5, code_length = 37)
0: invokestatic java.lang.System.currentTimeMillis ()J (81)
3: lstore_2
4: aload_0
5: iload_1
6: invokespecial StringBuilder.buildString$impl (I)Ljava/lang/String; (83)
9: astore %4
11: getstatic java.lang.System.out Ljava/io/PrintStream; (37)
14: dup
15: dup
16: ldc "Call to method buildString$impl took " (85)
18: invokevirtual java.io.PrintStream.print (Ljava/lang/String;)V (88)
21: invokestatic java.lang.System.currentTimeMillis ()J (81)
24: lload_2
25: lsub
26: invokevirtual java.io.PrintStream.print (J)V (91)
29: ldc " ms." (93)
31: invokevirtual java.io.PrintStream.println (Ljava/lang/String;)V (43)
34: aload %4
36: areturn

Attribute(s) =
LocalVariable(start_pc = 0, length = 51, index = 0:StringBuilder this)
LocalVariable(start_pc = 0, length = 51, index = 1:int length)
LocalVariable(start_pc = 3, length = 48, index = 2:String result)
LocalVariable(start_pc = 5, length = 40, index = 3:int i)
LineNumber(0, 6), LineNumber(3, 7), LineNumber(8, 8), LineNumber(34, 7),
LineNumber(42, 10), LineNumber(49, 12)

end method method method-----------------------------------
这个属性信息使用还是使用的原先方法的,显然length=55超过了指令的长度
36,执行时会检查类的局部变量属性信息发现不正确就报错了

这两个属性的信息应该是用来调试器来使用的,可以自己在字节码文件中自己添加这些信息,不过自己添加比较麻烦.
不过我另外一个程序的方法也自己生成了属性信息,这些属性信息也改变了,但是改变的不正确,但是程序能够执行。。

这中的原因我现在也搞不清楚了。

  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: