我们的项目执行一些Java字节码检测.我们偶然发现了一些奇怪的行为.假设以下代码段:
public void a() {
new Integer(2);
}
Run Code Online (Sandbox Code Playgroud)
Oracle的javac将上面的代码编译成以下字节码:
0: new #2; //class java/lang/Integer
3: dup
4: iconst_2
5: invokespecial #3; //Method java/lang/Integer."<init>":(I)V
8: pop
9: return
Run Code Online (Sandbox Code Playgroud)
和Eclipse的编译器进入:
0: new #15; //class java/lang/Integer
3: iconst_2
4: invokespecial #17; //Method java/lang/Integer."<init>":(I)V
7: return
Run Code Online (Sandbox Code Playgroud)
如您所见,Oracle编译器在"new"之后生成"dup",而Eclipse则不然.在这个用例中完全正确,因为根本不使用新创建的Integer实例,因此不需要"dup".
我的问题是:
我正在开发一个字节码分析项目,我正在使用ASM.一切都很顺利,我能够成功解析,获得类和方法信息.
但我坚持理解泛型的字节码表示.下面是一个例子java.util.list,当我使用visitMethod从ClassVisitor打印的信息,这是我得到的方法的签名之一:
(ILjava/util/Collection<+TE;>;)Z
Run Code Online (Sandbox Code Playgroud)
在这里,我试图逐个反汇编并理解方法的参数:
I 代表intLjava/util/Collection 代表它是一种类型的论证 Collection但我被困在仿制药类型<+TE>等等.任何人都可以指导我吗?我试图搜索但没有得到足够的信息.如果有人有字节码名称列表,请分享一下吗?
我需要从现有类生成新类(通过生成java字节代码).我将分析类的方法的主体(表达式).表达式将决定我将生成什么代码.
对我来说,它是import和设置新类的源文件(与基本java文件相同)以及控制行号(当抛出异常时,stacktrace应该包含基本java文件的行号).
示例:我有文件BaseClass.java.编译器从中生成BaseClass.class.我想分析这个类文件并生成GeneratedClass.class的字节代码.当在c处抛出异常时,stacktrace应包含"BaseClass.java第3行".
BaseClass.java
1: class BaseClass {
2: void method() {
3: call();
4: }
5:}
GeneratesClaas.class
a: class GeneratedClass {
b: void generatedMethod() {
c: generatedCall();
d: }
e:}
Run Code Online (Sandbox Code Playgroud)
我的问题:是否有支持此要求的库?Javassist,ASM还是BCEL?用于此目的的是什么?提示如何做或示例代码将特别有用.
编辑: 提示哪些库不使用,因为要求不能满足也是有帮助的:).
我正在使用ASM并希望重写类似的东西:
someMethod().targetMethod(args...)
Run Code Online (Sandbox Code Playgroud)
至:
someMethod().injectedMethod(arg).targetMethod(args...)
Run Code Online (Sandbox Code Playgroud)
问题是我不知道之前的方法是什么,我只知道目标方法(因此找不到someMethod()并注入之后不是一个选项).
我还有许多版本的目标方法,我想要使用不同的参数集.
使用ASM我可以很容易地找到目标方法调用,但不幸的是,那时的操作数堆栈是:
[ argN, ..., arg1, instance, ... ]
Run Code Online (Sandbox Code Playgroud)
虽然我可以计算出实例的距离,但是我没有可以注入的字节码会读取它.我知道你可以使用带有dup命令的技巧最多4个参数,但我需要一个通用的解决方案.
我可以添加一堆局部变量并将所有内容复制到堆栈中,复制指向的实例并重新打开所有内容,但这是我真正不想要的运行时效率低下.
我认为可行的是,如果我可以跟踪哪个指令负责将实例指针放在堆栈上,然后我可以在那里注入我的方法调用而不是在目标方法调用.但是,我没有找到任何帮助我做这件事的运气.
我知道像AspectJ这样的东西允许这样做,但是必须在很多类中执行此操作,因为它们加载并且AspectJ太慢了.
任何人都可以指出我在ASM之上构建的分析工具可能让我这样做,或者任何人都可以想到一个更好的方法来在另一个之前注入一个方法调用?
我得到像这样的堆栈跟踪:
java.lang.NoClassDefFoundError: sun/reflect/GeneratedMethodAccessor1
at sun.reflect.GeneratedMethodAccessor1.<clinit>(Unknown Source)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:355)
at java.lang.Class.newInstance(Class.java:308)
at sun.reflect.MethodAccessorGenerator$1.run(MethodAccessorGenerator.java:381)
at java.security.AccessController.doPrivileged(Native Method)
at sun.reflect.MethodAccessorGenerator.generate(MethodAccessorGenerator.java:377)
at sun.reflect.MethodAccessorGenerator.generateMethod(MethodAccessorGenerator.java:59)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:28)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at edu.tufts.cs.testsim.LogicalProcess.dispatchMessage(LogicalProcess.java:214)
at edu.tufts.cs.testsim.LogicalProcess.processForward(LogicalProcess.java:287)
at edu.tufts.cs.testsim.LogicalProcess.doOperation(LogicalProcess.java:423)
at edu.tufts.cs.testsim.LogicalProcess.run(LogicalProcess.java:434)
at java.lang.Thread.run(Thread.java:637)
Caused by: java.lang.ClassNotFoundException: sun.reflect.GeneratedMethodAccessor1
at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:316)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:288)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)
... 19 more
Run Code Online (Sandbox Code Playgroud)
什么是GeneratedMethodAccessor1,GeneratedMethodAccessor2,GeneratedMethodAccessorN以及可能导致它们无法找到的原因?我在运行时进行一些字节码重写,但只在加载类之前,前几次通过反射调用工作正常.我想知道在JIT编译器获取我的代码之后是否会发生这种情况,但我甚至不知道如何开始调试它.
我正在创建一个应用程序服务器,在其中我需要使用一些字节码操作(例如,将自定义equals和hashCode方法插入到带注释的类中@Entity).现在我给JVM一个Java代理(-javaagent选项),它使用ASM进行字节码转换.
我一直在考虑使用OSGi,但我不知道它是否允许我进行必要的字节码操作.
@Entity注释的API包的人都必须被操纵.我试图获取Java程序的方法参数的值.我正在使用ASM来检测字节码并获取这些值.但是,我遇到了一些麻烦.
这是用于检测代码的visitCode()方法.它正在做的是:
.
@Override
public void visitCode() {
int paramLength = paramTypes.length;
// Create array with length equal to number of parameters
mv.visitIntInsn(Opcodes.BIPUSH, paramLength);
mv.visitTypeInsn(Opcodes.ANEWARRAY, "java/lang/Object");
mv.visitVarInsn(Opcodes.ASTORE, paramLength);
// Fill the created array with method parameters
int i = 0;
for (Type tp : paramTypes) {
mv.visitVarInsn(Opcodes.ALOAD, paramLength);
mv.visitIntInsn(Opcodes.BIPUSH, i);
if (tp.equals(Type.BOOLEAN_TYPE) || tp.equals(Type.BYTE_TYPE) || tp.equals(Type.CHAR_TYPE) || tp.equals(Type.SHORT_TYPE) || tp.equals(Type.INT_TYPE))
mv.visitVarInsn(Opcodes.ILOAD, i);
else if (tp.equals(Type.LONG_TYPE)) {
mv.visitVarInsn(Opcodes.LLOAD, i);
i++;
}
else if (tp.equals(Type.FLOAT_TYPE))
mv.visitVarInsn(Opcodes.FLOAD, i);
else if …Run Code Online (Sandbox Code Playgroud) 这里是龙.你被警告过了.
我正在考虑创建一个新的库,试图帮助编写一个更好的测试套件.
为了做到这一点,其中一个功能是一个功能,它验证正在使用的任何不是测试运行器和被测系统的对象都有一个测试对象(模拟对象,存根,伪造或虚拟对象) ).如果测试人员想要活动对象并因此减少测试隔离,则必须明确指定.
我看到这样做的唯一方法是覆盖内置type()函数,它是默认的元类.
新的默认元类将检查测试双重注册表字典,以查看它是否已被测试双重替换或是否指定了活动对象.
当然,这不可能通过Python本身实现:
>>> TypeError: can't set attributes of built-in/extension type 'type'
Run Code Online (Sandbox Code Playgroud)
有没有办法在测试套件运行之前干预Python的元类查找(可能还有Python)?
也许使用字节码操作?但到底怎么样?
我最近一直在使用Java库'ASM',它用于在运行时修改字节码,以防人们不知道,而且我无法在ASM 4上找到一个教程.除了官方手册之外ASM 4,它引用了甚至不存在的ASM类.
我想知道是否有人知道该库的任何教程,其中包括基本到中间事物,例如将一些代码插入到方法中.
我是格拉巴酒的维护者.此包通过使用ASM生成一个扩展解析器类的类,从Java代码在运行时生成解析器.
我已经从ASM 4迁移到ASM 5,从生成JVM 1.5字节码到生成JVM 1.6字节码,现在我已经成功生成了JVM 1.7字节码而不是......除了我不知道为什么这样做.
基本上,我做了以下事情:
new ClassWriter(ClassWriter.COMPUTE_MAXS)现在是new ClassWriter(ClassWriter.COMPUTE_FRAMES).visit()方法的第一个参数更改Opcodes.V1_6为Opcodes.V1_7.现在,为什么我不明白为什么它有效有两个原因:
我有几个电话给MethodVisitors:
mv.visitMaxs(0, 0); // trigger automatic computing
Run Code Online (Sandbox Code Playgroud)
这是否意味着可以删除这些说明?
起初我只是尝试和添加的COMPUTE_FRAMES参数的ClassWriter构造函数,但它没有在一个点为我的测试中,我宣布一个:
static class TestJoinParser
extends EventBusParser<Object>
{
protected final JoinMatcherBuilder builder
= join('a').using('b');
}
Run Code Online (Sandbox Code Playgroud)
错误是:
java.lang.ClassFormatError: Arguments can't fit into locals
Run Code Online (Sandbox Code Playgroud)
鉴于它是一个实例字段,我想它与在构造函数中初始化的特定参数有关吗?
无论如何,我所有的测试现在都有效,我正在尝试更重的测试......但是我的目标是更进一步,我想至少了解为什么我的修改工作了... .