如何在另一个生成字节码类中使用匿名类实例 [英] How to use an anonymous class instance in another generate bytecode class

查看:98
本文介绍了如何在另一个生成字节码类中使用匿名类实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难使用由 Unsafe.defineAnonymousClass() 加载的生成的字节码类.我想知道如何使用匿名类的对象来初始化另一个类(或匿名类).

以下面的示例类 Callee 为例,其构造函数接受 Callee2 作为参数.

类被调用者{Callee2 _call2;公共被调用者(Callee2 callee2){...}}

在运行时,我为 Callee2 和 Callee 生成了新类,并且这两个新类都由 Unsafe.defineAnonymousClass() 加载.对于new Callee,构造函数也改为:

 public test.code.jit.asm.simple.Callee(test.code.jit.asm.simple.Callee2.1506553666);标志:ACC_PUBLIC代码:堆栈=2,本地人=3,args_size=20:aload_01: invokespecial #65//方法 java/lang/Object."<init>":()V....8:返回

而Callee2生成的类名是:

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

我创建了一个 `Callee2/1506553666' 的实例,并想用它创建新的 Callee 的实例,但失败了:

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

哪里args = [class test.code.jit.asm.simple.Callee2/1506553666]objs= [test.code.jit.asm.simple.Callee2/1506553666@39b0a038]

args[0] 没有意义,因为这个类是由匿名加载器加载的(匿名类不被任何类加载器引用).所以我真的很困惑如何将 objs 数组中的对象传递给方法调用..

使用消息调用 getConstructor (args) 时发生异常:

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

这个例外对我来说很明显,因为匿名类对于任何类加载器都是瞬态的.但就我而言,我确实需要通过新的 Callee2 实例初始化新的 Callee(也是匿名类)(Callee 的构造函数中的字节码将读取 Callee2 的字段成员),那么是否有任何解决方法可以为新的被调用方的构造函数传递新的 callee2 实例?

解决方案

看看 签名和文档注释,在标准 API 文档中不可用,因为它不是官方 API 的一部分:><块引用>

定义一个类,但不要让类加载器或系统字典知道它.对于每个 CP 条目,相应的 CP 补丁必须为空或具有与其标签匹配的格式:

  • Integer、Long、Float、Double:java.lang 中对应的包装对象类型
  • Utf8:一个字符串(如果用作签名或名称,必须有合适的语法)类:任何 java.lang.Class 对象
  • String:任何对象(不仅仅是 java.lang.String)
  • InterfaceMethodRef:(NYI) 调用该调用站点参数的方法句柄

…(参数:)

cpPatches 存在非空条目时,它们替换数据中相应的 CP 条目

公共原生类定义匿名类(类主机类,字节 [] 数据,对象 [] cpPatches);

换句话说,您可以提供一个与您要定义的类的常量池大小相同的数组.将 null 保留在您不想修改它的地方.在常量池具有表示匿名类的 CONSTANT_Class_info 的地方,您只需在数组中传递关联的 Class 对象.因此不需要查找类,您甚至不必在类字节中提供正确的类名.

有一些明显的限制:

  • 如果您有循环依赖,就会出现问题,因为您需要一个已经存在的 Class 对象来修补另一个类的池.好吧,对于已知可以延迟解析的类使用,它可能会起作用
  • 您只能将 CONSTANT_Class_info 修补到足以用于例如的 Class访问该类的成员或创建它的新实例.但是,当匿名类是签名的一部分时,它无济于事,即您想声明该类型的字段或使用将其作为参数或返回类型的方法.但是您可以使用通过 MethodHandle 修补 CONSTANT_InterfaceMethodref_info 条目的选项来访问这些方法(嗯,一旦实现,我猜NYI"意味着尚未实现")......

I have difficulty in using a generated bytecode class which is loaded by 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.

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(). For new Callee, the constructor is also changed to be:

 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:

      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:

        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]

The args[0] is meanless as this class is loaded by anonymous loader (Anonymous classes are not referenced by any class loaders). So it really puzzles me how to pass objects in objs array to a method invocation..

The exception occurs on the invocation of getConstructor (args) with message:

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?

解决方案

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:

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:

  • Integer, Long, Float, Double: the corresponding wrapper object type from java.lang
  • Utf8: a string (must have suitable syntax if used as signature or name) Class: any java.lang.Class object
  • String: any object (not just a java.lang.String)
  • InterfaceMethodRef: (NYI) a method handle to invoke on that call site's arguments

… (params:)

cpPatches where non-null entries exist, they replace corresponding CP entries in data

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 nulls where you don’t want to modify it. 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. 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. 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, e.g. accessing members of that class or creating new instances of it. But it doesn’t help when an anonymous class is part of a signature, i.e. 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")…

这篇关于如何在另一个生成字节码类中使用匿名类实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆