blob: 07e1e796f0b163f4275f46c6055457470b4827b5 [file] [log] [blame]
Object layout for Java objects
------------------------------
Each Java object will have the following basic layout:
struct llvm_java_object_base {
struct llvm_java_object_header header;
struct llvm_java_object_vtable* vtable;
};
Additional fields go to the end of the struct.
The 'llvm_java_object_header' is not defined yet.
struct llvm_java_object_header {
// gc info, hash info, locking
};
The vtable holds a nested struct of a 'llvm_java_object_typeinfo'
object. All methods are added after the nested struct and calls to
them are made by fetching the correct function pointer from the vtable
at runtime.
struct llvm_java_object_vtable {
struct java_object_typeinfo typeinfo;
};
For each class we keep track of its depth and an array of vtables to
all its superclasses. The depth of a class is the number of
superclasses it has. So java.lang.Object has depth 0, class A (extends
java.lang.Object) has depth 1 and so on. We also keep an array of
pointers to interface vtables. Each interface (vtable) gets a unique
number and it is indexed to this array. This mostly empty array is
filled up to the last interface implemented (the interface with the
largest index in this array). Since interfaces cannot implement other
interfaces (they can only extend) the lastIface and interfaces are
used to differentiate between class typeinfo's and interface
typeinfo's. More specifically if interfaces == -1 then this typeinfo
is for an interface and the lastIface field is the unique number of
this interface in the objects interfaces array. The field lastIface is
the max index of all implemented interfaces. For a class that doesn't
implement any it is -1. An additional field describes the elementSize
of an array. This allows us to implement System.arraycopy().
struct llvm_java_object_typeinfo {
jint depth;
struct llvm_java_object_vtable** vtables;
jint lastIface;
union {
struct llvm_java_object_vtable** interfaces;
jint interfaceFlag;
};
jint elementSize;
};
The structure of llvm_java_object_typeinfo allows constant time
dynamic type checks:
int isInstanceOf(struct llvm_java_object_base* obj,
struct llvm_java_object_vtable* clazz) {
struct llvm_java_object_vtable* objClazz = obj->vtable;
if (objClazz == clazz)
return 1;
// we are checking against a class' typeinfo
if (clazz->typeinfo.interfaceFlag != -1)
return objClazz->typeinfo.depth > clazz->typeinfo.depth &&
objClazz->typeinfo.vtables[clazz->typeinfo.depth] == clazz;
// otherwise we are checking against an interface's typeinfo
else
return objClazz->typeinfo.lastIface >= clazz->typeinfo.lastIface &&
objClazz->typeinfo.interfaces[clazz->typeinfo.lastIface];
}
Object Layout for Java Arrays
-----------------------------
Java primitive arrays inherit from java.lang.Object so they will at
minimum have a nested java.lang.Object struct as their first element.
struct javaIntArray {
struct java_lang_Object;
int length;
int array[0];
};
The typeinfo struct inside this class' vtable will be filled in the
same way as if this was a proper class. This will allow isInstanceOf
to work transparently for primitive java arrays.
For reference type arrays we use the same struct for all types. The
only difference is the vtable (actually the vtables are identical but
they have different typeinfo structs to reflect the hierarchy of the
contained elements):
struct javaObjectArray {
struct java_lang_Object;
int length;
java_lang_Object array[0];
};
The typeinfo struct will reflect a hierarchy of array types as if B[]
derives from A[] if B derives from A. This will allow isInstanceOf to
work transparently for object arrays as well.