不安全的defineAnonymousClass和ClassLoader之间的不同行为

时间:2015-05-27 19:18:06

标签: java classloader java-bytecode-asm bytecode-manipulation dynamic-class-loaders

我使用classloader和Unsafe :: definedAnonymous()来加载生成的字节码byte []。 classLoader.loadClass()返回的Class的使用成功,而c.getMethod() API中的c=Unsafe.defineAnonymousClass()失败。那么生成的字节码是错的吗?

我的代码:

        MainInliner loader = new MainInliner();
        Class<?> c =null;
        byte[] bytes = ...
        if(args[0].equals("0")){
            c = loader.loadClass(name, bytes, 0, bytes.length);  // Classloader.loadClass.
        }else{
            c = Unsafe.defineAnonymousClass(Hoster, bytes, null);
        }

        Method m = c.getMethod("main", new Class<?>[] { String[].class    });

错误是:

Exception Details:
  Location:
    code/sxu/asm/example/Caller.test(II)V @98: lload_3
  Reason:
    Type integer (current frame, locals[3]) is not assignable to long
  Current Frame:
    bci: @98
    flags: { }
    locals: { 'code/sxu/asm/example/Caller', integer, integer, integer, integer, integer, integer, integer, integer, integer }
    stack: { 'java/io/PrintStream' }
  Bytecode:
    0000000: 1b85 2ab4 000e 1b1c 3e36 043a 0537 0619
    0000010: 05b4 002a b600 3019 05b4 0033 b600 3060
    0000020: 3608 1508 3609 1606 1509 a700 0385 6542
    0000030: 1b2a b400 0e1c 033e 3604 3a05 3606 1905
    0000040: b400 2ab6 0030 1905 b400 33b6 0030 6036
    0000050: 0715 0736 0815 0615 08a7 0003 6036 05b2
    0000060: 003d 21b6 0043 b1                      
  Stackmap Table:
    full_frame(@45,{Object[#2],Integer,Integer,Integer,Integer,Object[#21],Long,Integer,Integer},{Long,Integer})
    full_frame(@92,{Object[#2],Integer,Integer,Integer,Integer,Object[#21],Integer,Integer,Integer,Integer},{Integer,Integer})

,生成的字节码为:

 public void test(int, int);
    flags: ACC_PUBLIC
    Code:
      stack=5, locals=10, args_size=3
         0: iload_1       
         1: i2l   

         2: aload_0       
         3: getfield      #14                 // Field _callee:Lcode/sxu/asm/example/Callee;
         6: iload_1       
         7: iload_2       
         8: istore_3      
         9: istore        4
        11: astore        5
        13: lstore        6

        15: aload         5
        17: getfield      #42                 // Field code/sxu/asm/example/Callee._a:Ljava/lang/String;
        20: invokevirtual #48                 // Method java/lang/String.length:()I
        23: aload         5
        25: getfield      #51                 // Field code/sxu/asm/example/Callee._b:Ljava/lang/String;
        28: invokevirtual #48                 // Method java/lang/String.length:()I
        31: iadd          
        32: istore        8
        34: iload         8
        36: istore        9
        38: lload         6
        40: iload         9
        42: goto          45


        45: i2l           
        46: lsub          
        47: lstore_3        //r..

        48: iload_1       

        49: aload_0       
        50: getfield      #14                 // Field _callee:Lcode/sxu/asm/example/Callee;
        53: iload_2       
        54: iconst_0      
        55: istore_3      
        56: istore        4
        58: astore        5
        60: istore        6   //The backup stack bottom variable.

        62: aload         5
        64: getfield      #42                 // Field code/sxu/asm/example/Callee._a:Ljava/lang/String;
        67: invokevirtual #48                 // Method java/lang/String.length:()I
        70: aload         5
        72: getfield      #51                 // Field code/sxu/asm/example/Callee._b:Ljava/lang/String;
        75: invokevirtual #48                 // Method java/lang/String.length:()I
        78: iadd          
        79: istore        7
        81: iload         7
        83: istore        8
        85: iload         6     //Push back 6
        87: iload         8     //Repush 8
        89: goto          92
                                //return calculate()
        92: iadd          
        93: istore        5
        95: getstatic     #61                 // Field java/lang/System.out:Ljava/io/PrintStream;
        98: lload_3       
        99: invokevirtual #67                 // Method java/io/PrintStream.println:(J)V
       102: return        
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
              15      30     5  this   Lcode/sxu/asm/example/Callee;
              15      30     4     t   I
              15      30     3     p   I
              34      11     8   tmp   I
              62      30     5  this   Lcode/sxu/asm/example/Callee;
              62      30     4     t   I
              62      30     3     p   I
              81      11     7   tmp   I
               0     103     0  this   Lcode/sxu/asm/example/Caller;
               0     103     1     a   I
               0     103     2     b   I
              48      55     3     r   J
              95       8     5     c   I
      LineNumberTable:
        line 19: 0
        line 16: 15
        line 23: 34
        line 21: 48
        line 16: 62
        line 23: 81
        line 23: 95
        line 30: 102
      StackMapTable: number_of_entries = 2
           frame_type = 255 /* full_frame */
          offset_delta = 45
          locals = [ class code/sxu/asm/example/Caller, int, int, int, int, class code/sxu/asm/example/Callee, long, int, int ]
          stack = [ long, int ]
           frame_type = 255 /* full_frame */
          offset_delta = 46
          locals = [ class code/sxu/asm/example/Caller, int, int, int, int, class code/sxu/asm/example/Callee, int, int, int, int ]
          stack = [ int, int ]

}

此字节码对应于内联Callee方法。

我检查了这个字节码序列,似乎没有错误。错误消息中的变量3出现4次,其中:

8: istore_3        //Popo up existing parameters for inlining. 
47: lstore_3        //r. The local variable in the Caller method
55: istore_3        // Similiar to the label 8, pops stack paras to local variable. 
98: lload_3         //Println parameter

相应的方法是:

public class Caller{
public void test(int a, int b){
    long r = (long)a- _callee.calculate(a, b);
    int c = a +_callee.calculate(b, 0);
    System.out.println(r);
}

}

  public class Callee{
    public int calculate(int t, int p){
        int tmp=_a.length()+_b.length();
        return tmp;
    }}

0 个答案:

没有答案