我们用Java编写了一个简单的PostScript解释器,并希望通过直接为源代码的特定部分生成字节码来优化它。为此,我们需要从Java字节码上下文的上下文中加载对象。在生成的字节码方法的签名中指定这样的对象是不好的,因为在我们的情况下它们可能是大量的。
在Java Asm中我们有方法
public void visitLdcInsn(Object cst)
它访问LDC指令。参数cst - 要在堆栈上加载的常量。
有没有办法加载非常量对象?
由于
答案 0 :(得分:0)
ldc
可用于加载int
,float
,String
,Class
,MethodType
或{{1}类型的值}; MethodHandle
支持ldc2_w
和long
类型的值。 1
As said,在Oracle的JVM实现中,有一个内部使用的double
API,允许在运行时对象中修补作为常量的替代,但这有几个缺点。首先,它显然不是官方API的一部分,不存在于每个JVM中,甚至可能在未来的Oracle JVM中消失(或更改方法签名)。此外,ASM框架将不会知道您将要做什么,并且难以为后续补丁生成适当的字节码。
毕竟,目前尚不清楚,滥用Unsafe
对项目中的运行时对象有什么好处。生成用于将实例作为方法或构造函数参数传递以及将对象存储在字段中的代码对于ASM来说并不是非常复杂。对于程序逻辑,无论您使用ldc
还是使用{1}}, ldc
,在使用该值之前。
答案 1 :(得分:0)
由于指出使用Unsafe
的错误方式(它实际上不是一个选项,因为它要求您匿名加载类):
我假设您在构建期间创建了一个类,但是您希望将某种运行时上下文注入到运行检测所需的这些类中。您至少可以通过为您的应用程序编写一个专门的ClassLoader
来模拟这一点,该应用程序知道此上下文并通过例如注释显式初始化类。
这意味着您要修改一个类,如:
@Enhanced
class Foo {
static EnhancementDelegate delegate;
void instrumentedMethod() {
// do something with delegate
}
}
在构建时,您在加载时明确初始化:
class EnhancementClassLoader extends ClassLoader {
@Override
protected Class<?> loadClass(String name) {
Class<?> clazz = super.loadClass(name);
if(clazz.isAnnotationPresent(Enhanced.class)) {
// do initialization stuff
}
return clazz;
}
}
这会帮助你吗?这是一种猜测你想要实现的目标,但我认为这可能是一个很好的解决方案。查看我的项目Byte Buddy,它通过引入LoadedTypeInitializer
解决了代理类的类似问题。
答案 2 :(得分:0)
自Java 11起,可以使用LDC
指令加载任意常量。这些可能是任意类型的对象,但意味着具有恒定的语义,因此它们最好是不可变的。
要使其正常工作,引用的常量池条目必须为CONSTANT_Dynamic_info
,其结构与CONSTANT_InvokeDynamic_info
类似,同样描述了引导方法。
一个区别是动态信息结构的name_and_type_index
条目将指向字段描述符。此外,引导程序方法的签名为(MethodHandles.Lookup,String,Class[,static arguments])
,而不是Class
对象,该签名的MethodType
参数表示常量的预期类型。 bootstrap方法必须直接返回常量值,而不是调用站点。
invokedynamic
指令的共同之处在于,第一个引导过程的结果将与LDC
指令相关联,并在所有后续执行中使用(因为它应该是常量)。 / p>
这些动态常量的一个有趣特性是,它们是另一个动态常量或invokedynamic
指令(只要动态常量之间没有循环依赖性)的bootstrap方法的有效静态参数。
请注意,已经有一个convenience class包含一些随时可以使用的动态常量引导程序方法。