我正试图通过使用ASM 4.0重新编写类的字节码,以用非native
存根替换所有native
方法。
到目前为止,我有以下内容:
class ClassAdapter extends ClassVisitor {
public ClassAdapter(ClassVisitor cv) {
super(Opcodes.ASM4, cv);
}
@Override
public MethodVisitor visitMethod(int access, String base, String desc, String signature, String[] exceptions) {
return cv.visitMethod(access & ~Opcodes.ACC_NATIVE, base, desc, signature, exceptions);
}
}
由...执行
private static byte[] instrument(byte[] originalBytes, ClassLoader loader) {
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
ClassAdapter adapter = new ClassAdapter(cw);
ClassReader cr = new ClassReader(originalBytes);
cr.accept(adapter, ClassReader.SKIP_FRAMES);
return cw.toByteArray();
}
这似乎很简单:我从 visitMethod()
方法中删除 ACC_NATIVE
,并保留其他所有内容。然而,当我对 java.lang.Object
进行此操作时,它会出错。
Exception in thread "main"
Exception: java.lang.StackOverflowError thrown from the UncaughtExceptionHandler in thread "main"
StackOverflow问题发生在instrumentation时间而不是runtime,我认为这相当不寻常。但是,如果我删除& ~Opcodes.ACC_NATIVE
修饰符,java.lang.Object
就会被重写(在这种情况下没有更改)并正常执行。
显然我做错了什么,用非native
方法替换native
方法并不像简单地去掉方法上的native
修饰符那样简单,但我不知道从哪里开始。 ASM文档根本不讨论如何使用native
方法。有没有使用ASM经验的人知道我需要做什么才能使native
方法重写起作用?
编辑
抱歉,那个简短、无用的消息是e.printStackTrace()
给我的,但是使用e.getStackTrace()
我成功地得到了一些有用的信息:
java.util.concurrent.ConcurrentHashMap.hash(ConcurrentHashMap.java:332)
java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1124)
java.util.Collections$SetFromMap.add(Collections.java:3903)
sandbox.classloader.MyClassLoader.instrument(Unknown Source)
sandbox.classloader.MyClassLoader.loadClass(Unknown Source)
java.lang.ClassLoader.defineClass1(Native Method)
java.lang.ClassLoader.defineClass(ClassLoader.java:791)
java.lang.ClassLoader.defineClass(ClassLoader.java:634)
sandbox.classloader.MyClassLoader.findClass(Unknown Source)
sandbox.classloader.MyClassLoader.loadClass(Unknown Source)
sandbox.Tester.main(Unknown Source)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:601)
com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
据我看来,错误实际上是在执行时发生的(例如,我错误地认为它是在插装时发生的),并且是调用hashCode()
方法的结果。恰好,hashCode()
是我(可能不正确地)去掉了其native
修饰符的原生方法之一。因此,显然是调用被去除native
修饰符的方法导致了问题。
真正奇怪的是,堆栈跟踪仅深入了16层;考虑到它是一个StackOverflowError
,我本来期待有更多的层。
Code
属性?如果没有,我会怀疑 ASM 会感到困惑,因为它没有足够的信息来编写文件。 - kdgregory