在无限深度上访问JVM方法堆栈

在无限深度上访问JVM方法堆栈,jvm,java-bytecode-asm,Jvm,Java Bytecode Asm,我想使用ASM MethodVisitor进行字节码转换。 我的目标是替换所有调用特定方法的INVOKEINTERFACE指令,这些方法用注释标记,顺序如下: // instructions that put instance object on stack INVOKESTATIC package/name/Wrapper wrap (Ljava/lang/Object;)Lpackage/name/Wrapper; LDC <method_name> // instruction

我想使用ASM MethodVisitor进行字节码转换。 我的目标是替换所有调用特定方法的INVOKEINTERFACE指令,这些方法用注释标记,顺序如下:

// instructions that put instance object on stack
INVOKESTATIC package/name/Wrapper wrap (Ljava/lang/Object;)Lpackage/name/Wrapper;
LDC <method_name>
// instructions that put first parameter on stack
INVOKESTATIC package/name/Wrapper wrap (Ljava/lang/Object;)Lpackage/name/Wrapper;
// and so forth for all parameters
INVOKESTATIC package/name/Wrapper invoke (Lpackage/name/Wrapper;<repeat n times>)Lpackage/name/Wrapper;
INVOKESTATIC package/name/Wrapper unwrap (Lpackage/name/Wrapper)Ljava/lang/Object;
使用单参数方法,这是一项非常简单的任务。然而,由于无法在任何深度上检索堆栈,所以随着参数的增加,事情变得越来越重要。可能的解决办法是什么?首先是用局部变量备份最后N个堆栈值,但在这种情况下,transformer必须知道使用的局部变量的数量,因此需要进行第二次传递。此外,我不喜欢这种方法如何破坏所有这些堆栈备份的字节码

第二种解决方案是构建def use链,并在堆栈上出现堆栈值后立即使用此信息包装堆栈值。这种方法不会破坏字节码,但存在以下几个缺点:

首先,它很难实施。 第二,它需要额外的通行证。 第三,def使用链的查找和保存范围很广。 第四,有时在包装后很难处理DUP指令,因为丢弃的值也不需要包装。
有人会注意到,我可以在我的案例中使用代理。不幸的是,我不能,因为转换后的字节码将由另一个依赖包装信息的转换器/分析器处理。

我建议您使用ASM的树API。此API允许您在操作数堆栈中来回导航。这样,您的实现将保持相当简单,因为您可以在发现要替换的方法之前简单地添加指令

否则,在本地变量数组中存储值时,可以使用ASM。同时,您不再需要担心覆盖以后的插槽。此实现将执行得更快,因为它将节省树API的开销

我不会太担心性能。JVM的JIT编译器足够聪明,可以在代码变热时对其进行优化。两种解决方案都可以