3

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?

St.Antario
  • 26,175
  • 41
  • 130
  • 318

1 Answers1

4

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.

Holger
  • 285,553
  • 42
  • 434
  • 765