简体   繁体   English

如何在另一个生成字节码类中使用匿名类实例

[英]How to use an anonymous class instance in another generate bytecode class

I have difficulty in using a generated bytecode class which is loaded by Unsafe.defineAnonymousClass() . 我在使用由Unsafe.defineAnonymousClass()加载的生成的字节码类时遇到困难。 I am wondering how to use an object of anonymous class to initiliaze another class (or anonymous class). 我想知道如何使用匿名类的对象初始化另一个类(或匿名类)。

Take an example class Callee below for example, its constructor accepts Callee2 as parameter. 以下面的示例类Callee为例,其构造函数接受Callee2作为参数。

Class Callee{
    Callee2 _call2;
    public Callee(Callee2 callee2){
        ...
    }
}

During runtime, I generated new classes for both Callee2 and Callee, and both new classes are loaded by Unsafe.defineAnonymousClass() . 在运行时,我为Callee2和Callee生成了新类,并且这两个新类都由Unsafe.defineAnonymousClass()加载。 For new Callee, the constructor is also changed to be: 对于新的Callee,构造函数也更改为:

 public test.code.jit.asm.simple.Callee(test.code.jit.asm.simple.Callee2.1506553666);
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=2
         0: aload_0       
         1: invokespecial #65                 // Method java/lang/Object."<init>":()V
           ....
         8: return       

while the generated class name of Callee2 is: 而Callee2的生成类名称为:

      class test.code.jit.asm.simple.Callee2/1506553666

I created an instance of `Callee2/1506553666' and want to create instance of new Callee with it, but fail: 我创建了`Callee2 / 1506553666'的实例,并想用它创建新Callee的实例,但是失败了:

        newCls.getConstructor(args).newInstance(objs); 

where args = [class test.code.jit.asm.simple.Callee2/1506553666] and objs= [test.code.jit.asm.simple.Callee2/1506553666@39b0a038] 其中args = [class test.code.jit.asm.simple.Callee2/1506553666]objs= [test.code.jit.asm.simple.Callee2/1506553666@39b0a038]

The args[0] is meanless as this class is loaded by anonymous loader (Anonymous classes are not referenced by any class loaders). args [0]毫无意义,因为此类是由匿名加载器加载的(任何类加载器均未引用匿名类)。 So it really puzzles me how to pass objects in objs array to a method invocation.. 因此,这真的使我感到困惑,如何将objs数组中的对象传递给方法调用。

The exception occurs on the invocation of getConstructor (args) with message: 使用消息调用getConstructor(args)时会发生异常:

java.lang.NoClassDefFoundError: test/code/jit/asm/simple/Callee2/1506553666
    at java.lang.Class.getDeclaredConstructors0(Native Method)
    at java.lang.Class.privateGetDeclaredConstructors(Class.java:2483)
    at java.lang.Class.getConstructor0(Class.java:2793)
    at java.lang.Class.getConstructor(Class.java:1708)
    at code.jit.asm.util.ReflectionUtil.adapt2GeneratedObject(ReflectionUtil.java:36)
    at code.jit.asm.services.BytecodeGenerator.generator(BytecodeGenerator.java:164)

The exception is clearly for me since the anonymous class is transient to any classloader. 对我来说显然是个例外,因为匿名类对于任何类加载器都是临时的。 But in my case, I do need initialize the new Callee (also anonymous class) by new Callee2 instance (The bytecodes in Callee's constructor will reads Callee2's field members), so is there any workaround to pass new callee2 instance for the new callee's constructor? 但就我而言,我确实需要通过新的Callee2实例初始化新的Callee(也是匿名类)(Callee的构造函数中的字节码将读取Callee2的字段成员),因此,是否有任何变通办法将新的Callee2实例传递给新的Callee2的构造函数?

Have a look at the signature and documentation comment , which is not available in the standard API documentation as it's not part of the official API: 看一下签名和文档注释 ,由于它不是官方API的一部分,因此在标准API文档中不可用:

Define a class but do not make it known to the class loader or system dictionary. 定义一个类,但不要让类加载器或系统字典知道它。 For each CP entry, the corresponding CP patch must either be null or have the a format that matches its tag: 对于每个CP条目,相应的CP修补程序必须为null或具有与其标签匹配的格式:

  • Integer, Long, Float, Double: the corresponding wrapper object type from java.lang Integer,Long,Float,Double:java.lang中对应的包装器对象类型
  • Utf8: a string (must have suitable syntax if used as signature or name) Class: any java.lang.Class object utf8:字符串(如果用作签名或名称,则必须具有适当的语法)类:任何java.lang.Class对象
  • String: any object (not just a java.lang.String) 字符串:任何对象(不只是java.lang.String)
  • InterfaceMethodRef: (NYI) a method handle to invoke on that call site's arguments InterfaceMethodRef:(NYI)在该调用站点的参数上调用的方法句柄

… (params:) …(参数:)

cpPatches where non-null entries exist, they replace corresponding CP entries in data 存在非空条目的cpPatches ,它们替换数据中相应的CP条目

 public native Class<?> defineAnonymousClass( Class<?> hostClass, byte[] data, Object[] cpPatches); 

In other words, you may provide an array of the same size as the constant pool of the class you're going to define. 换句话说,您可以提供与要定义的类的常量池相同大小的数组。 Keep null s where you don't want to modify it. null保留在您不想对其进行修改的位置。 Right at the places where your constant pool has a CONSTANT_Class_info representing an anonymous class, you simply pass the associated Class object in the array. 在常量池中具有代表匿名类的CONSTANT_Class_info的位置上,您只需在数组中传递关联的Class对象。 So there's no lookup for the class then, you don't even have to provide the correct class name in the class bytes. 因此,无需查找该类,您甚至不必在类字节中提供正确的类名称。

There are some obvious limitations: 有一些明显的局限性:

  • Problem will arise if you have circular dependencies as you need an already existing Class object to patch the pool of another class. 如果您具有循环依赖关系,则会出现问题,因为您需要一个已经存在的Class对象来修补另一个类的池。 Well, for class uses that are known to be resolved lazily, it might work 好吧,对于已知可以延迟解决的类使用,它可能会起作用
  • You can only patch CONSTANT_Class_info to a Class which is sufficient for, eg accessing members of that class or creating new instances of it. 你只能修补CONSTANT_Class_infoClass是足够的,例如访问该类的成员或创建该包的新实例。 But it doesn't help when an anonymous class is part of a signature , ie you want to declare a field of that type or use a method having it as parameter or return type. 但是,当匿名类是签名的一部分时,即当您要声明该类型的字段或使用将其作为参数或返回类型的方法时,这无济于事。 But you may access such methods using the option of patching a CONSTANT_InterfaceMethodref_info entry via a MethodHandle (ahem, once implemented as I guess “NYI” means “not yet implemented”)… 但是您可以使用通过MethodHandle修补CONSTANT_InterfaceMethodref_info条目的选项来访问此类方法( MethodHandle ,一旦实现,我猜“ NYI”就意味着“尚未实现”)…

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM