理解Java中的单元化对象(Understanding unitialized objects in Java)

系统教程 行业动态 更新时间:2024-06-14 16:57:40
理解Java中的单元化对象(Understanding unitialized objects in Java)

我试图理解如何在Object[]存储引用在Java中工作。 所以我用ASM库生成了一个Class ,如下所示:

public static Class<?> getKlass(){ String className = "TestClass"; ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); classWriter.visit(V1_8, ACC_PUBLIC, className, null, getInternalName(Object.class), null); MethodVisitor mv = classWriter.visitMethod(ACC_PUBLIC + ACC_STATIC, "m", "()[Ljava/lang/Object;",null, null); //ARRAY_SIZE mv.visitInsn(ICONST_1); mv.visitTypeInsn(ANEWARRAY, getInternalName(Object.class)); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitTypeInsn(NEW, getInternalName(Object.class)); mv.visitInsn(AASTORE); // <--- Here is the problem mv.visitInsn(ARETURN); mv.visitMaxs(1, 1); mv.visitEnd(); return new ByteArrayClassLoader().defineClass(classWriter.toByteArray()); }

当我运行此代码JVM信号与java.lang.VerifyError

Type uninitialized 6 (current frame, stack[3]) is not assignable to 'java/lang/Object'

添加构造函数调用按预期工作

mv.visitTypeInsn(NEW, getInternalName(Object.class)); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, getInternalName(Object.class), "<init>", "()V", false); mv.visitInsn(AASTORE);

现在它工作正常。 但行为尚不清楚。 我期望未初始化和初始化的对象具有相同的类型。 如JVMS中所述,我们没有特殊的未初始化类型。 所以我希望JVM允许加载具有未初始化引用的类。

我错过了什么?

I'm trying to understand how storing a reference into Object[] works in Java. So I generated a Class with ASM library as follows:

public static Class<?> getKlass(){ String className = "TestClass"; ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); classWriter.visit(V1_8, ACC_PUBLIC, className, null, getInternalName(Object.class), null); MethodVisitor mv = classWriter.visitMethod(ACC_PUBLIC + ACC_STATIC, "m", "()[Ljava/lang/Object;",null, null); //ARRAY_SIZE mv.visitInsn(ICONST_1); mv.visitTypeInsn(ANEWARRAY, getInternalName(Object.class)); mv.visitInsn(DUP); mv.visitInsn(ICONST_0); mv.visitTypeInsn(NEW, getInternalName(Object.class)); mv.visitInsn(AASTORE); // <--- Here is the problem mv.visitInsn(ARETURN); mv.visitMaxs(1, 1); mv.visitEnd(); return new ByteArrayClassLoader().defineClass(classWriter.toByteArray()); }

When I run this code JVM signals with java.lang.VerifyError that

Type uninitialized 6 (current frame, stack[3]) is not assignable to 'java/lang/Object'

Adding constructor invokation works as expected

mv.visitTypeInsn(NEW, getInternalName(Object.class)); mv.visitInsn(DUP); mv.visitMethodInsn(INVOKESPECIAL, getInternalName(Object.class), "<init>", "()V", false); mv.visitInsn(AASTORE);

Now it works fine. But the behavior is not clear. I expected the uninitialized and initialized objects have the same type. As specified in JVMS we do not have a special uninitialized type. So I expected JVM allows to load the class with uninitialized reference.

What did I miss?

最满意答案

有一个未初始化的类型,但它只存在于验证程序中,resp。 在堆栈映射表条目中应该帮助验证者。 由于严格要求包含NEW指令的方法必须通过invokespecial调用构造invokespecial ,并且必须在使用该对象之前调用它,因此无需在常规类型系统中对其进行建模。 一旦验证器确保每个方法都正确初始化对象,您就不会在不适当的位置遇到未初始化的对象。

§4.10.1.2。 验证类型系统 :

Verification type hierarchy: top ____________/\____________ / \ / \ oneWord twoWord / | \ / \ / | \ / \ int float reference long double / \ / \_____________ / \ / \ uninitialized +------------------+ / \ | Java reference | / \ | type hierarchy | uninitializedThis uninitialized(Offset) +------------------+ | | null

uninitializedThis是在调用超类构造函数之前构造函数中this引用的类型。 uninitialized(Offset)是在调用构造函数之前由NEW创建的实例的类型。 “ Offset ”是指方法字节代码中NEW指令的指令偏移量。 这允许跟踪可能飞来飞去的多个未初始化的实例,例如在执行new Foo(new Bar(new Baz()))或甚至new Foo(new Foo(new Foo())) 。 正如在这个答案中详细说明的那样,将未初始化的实例绑定到创建NEW指令会对代码结构施加一些限制,例如,即使它们在调用构造函数后具有相同的引用类型,也无法合并未初始化类型的不同NEW指令。

There is an uninitialized type, but it only exists in the verifier, resp. in stack map table entries supposed to aid the verifier. Since it is a strict requirement that your method, which contains the NEW instruction, must invoke the constructor via invokespecial and it must invoke it before using the object, there is no need to model it in the general type system. Once the verifier has made sure that every method initialize objects correctly, you won’t encounter uninitialized objects at inappropriate places.

The §4.10.1.2. Verification Type System:

Verification type hierarchy: top ____________/\____________ / \ / \ oneWord twoWord / | \ / \ / | \ / \ int float reference long double / \ / \_____________ / \ / \ uninitialized +------------------+ / \ | Java reference | / \ | type hierarchy | uninitializedThis uninitialized(Offset) +------------------+ | | null

uninitializedThis is the type of the this reference within a constructor, before the superclass constructor has been called. uninitialized(Offset) is the type of an instance created by NEW before the constructor has been called. “Offset” refers to the instruction offset of the NEW instruction within the method’s byte code. This allows to keep track of multiple uninitialized instances that may fly around, e.g. when doing new Foo(new Bar(new Baz())) or even new Foo(new Foo(new Foo())). As elaborated in this answer, tying the uninitialized instance to the creating NEW instruction imposes some restrictions on the code structure, e.g. you can not merge uninitialized types of different NEW instructions, even if they have the same reference type after invoking the constructor.

更多推荐

本文发布于:2023-04-13 12:21:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/dzcp/ec968582256d65777c6742841e7ac4bf.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:单元   对象   Java   objects   unitialized

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!