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.