Java 不安全的defineAnonymousClass和ClassLoader之间的不同行为
我使用classloader和Unsafe::definedanymous()加载生成的字节码[]。classLoader.loadClass()返回的类的使用成功,而使用Java 不安全的defineAnonymousClass和ClassLoader之间的不同行为,java,classloader,java-bytecode-asm,bytecode-manipulation,dynamic-class-loaders,Java,Classloader,Java Bytecode Asm,Bytecode Manipulation,Dynamic Class Loaders,我使用classloader和Unsafe::definedanymous()加载生成的字节码[]。classLoader.loadClass()返回的类的使用成功,而使用c.getMethod()返回的类失败,其中c=Unsafe.defineAnonymousClass()API。那么生成的字节码是错误的吗 我的代码: MainInliner loader = new MainInliner(); Class<?> c =null;
c.getMethod()
返回的类失败,其中c=Unsafe.defineAnonymousClass()
API。那么生成的字节码是错误的吗
我的代码:
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 });
生成的字节码是:
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 ]
}
此字节码对应于内联的被调用方方法
我检查了这个字节码序列,似乎没有错误。错误消息中的变量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);
}
}
loader.loadClass(字节)
是什么意思?没有这样的ClassLoader.loadClass(byte[])
方法。您是如何生成字节码的?您是否从现有方法开始并对其进行了修改?是的。字节码是基于调用者和被调用者的类生成的,使用ASM库loader.loadClass(名称、字节、0、字节、长度)
?没有这样的ClassLoader.loadClass(字符串,字节[],int,int)
方法。这里输入错误。loadClass(字符串)将最终调用defineClass(名称、字节、0、长度)。我自己的问题已经有了答案。变量索引错误,因为55:istore_3
出于性能原因,我没有建议使用它。问题是,由于反射不兼容的自优化,一些实现存在问题。Read,在一些成功的调用之后,方法
将尝试通过编译访问器类来优化自身,但由于其他类无法访问匿名类,因此在调用调用
时,您会突然收到错误
s。这可能发生在20次左右的调用之后。如前所述,这取决于实现,因此是jre版本。这就是为什么我说俄罗斯轮盘赌。
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;
}}