-
Notifications
You must be signed in to change notification settings - Fork 0
VM Class Manager
JNode's class management system distributed across VmType, ClassDecoder, and VmClassLoader — handles bytecode decoding, type loading, linking pipeline, TIB construction, and JIT compilation orchestration.
JNode does not have a single "VmClassManager" or "VmTypeManager" class. Instead, class management functionality is distributed across three core components:
-
VmType (2508 lines) — The central type representation. An abstract class that manages the entire class lifecycle: loading, verification, preparation, compilation, linking, and initialization. It holds all type metadata including the constant pool, method table, field table, interface tables, and state flags.
-
ClassDecoder (1503 lines) — The bytecode parser that decodes
.classfiles intoVmTypeinstances. It parses the JVM class file format (magic number, constant pool, fields, methods, attributes) and createsVmNormalClass,VmInterfaceClass,VmArrayClass, orVmPrimitiveClassinstances. -
VmClassLoader (150 lines) — The abstract classloader contract defining
loadClass(),defineClass(),findLoadedClass(), and JIT compilation hooks. Concrete implementations (VmSystemClassLoader,VmJavaClassLoader,PluginClassLoaderImpl) provide the actual class loading logic.
Together, these three components implement the full JVM class loading pipeline: bytecode decoding → type creation → linking (prepare, verify, compile) → initialization.
| Class / File | Role |
|---|---|
core/src/core/org/jnode/vm/classmgr/VmType.java |
Central type representation (2508 lines): lifecycle management, constant pool, method/field tables, state machine |
core/src/core/org/jnode/vm/classmgr/ClassDecoder.java |
Bytecode parser (1503 lines): decodes .class files into VmType instances |
core/src/core/org/jnode/vm/classmgr/VmClassLoader.java |
Abstract classloader contract (150 lines): loadClass, defineClass, JIT hooks |
core/src/core/org/jnode/vm/classmgr/VmClassType.java |
Abstract base for TIB-bearing types (277 lines): prepareTIB(), prepareIMT() |
core/src/core/org/jnode/vm/classmgr/VmNormalClass.java |
Regular class representation (168 lines): object size, reference offsets for GC |
core/src/core/org/jnode/vm/classmgr/VmArrayClass.java |
Array type metadata (182 lines): component type, total/maxLength |
core/src/core/org/jnode/vm/classmgr/VmInterfaceClass.java |
Interface representation (96 lines): no TIB, no IMT |
core/src/core/org/jnode/vm/classmgr/VmPrimitiveClass.java |
Primitive type representation (92 lines): jvmType, floatingPoint, wide |
core/src/core/org/jnode/vm/classmgr/VmTypeState.java |
State flag bitmasks: LOADED, PREPARED, VERIFIED, COMPILED, LINKED, INITIALIZED |
core/src/core/org/jnode/vm/classmgr/TIBBuilder.java |
Vtable builder (180 lines): inheritance-copy, method append/override |
core/src/core/org/jnode/vm/classmgr/IMTBuilder.java |
Interface Method Table builder (148 lines): 64-slot hash table with collision chaining |
core/src/core/org/jnode/vm/classmgr/ObjectLayout.java |
Object memory layout constants: FLAGS_SLOT=-2, TIB_SLOT=-1, IMT_LENGTH=64 |
core/src/core/org/jnode/vm/classmgr/TIBLayout.java |
TIB array index constants: VMTYPE_INDEX=0, IMT_INDEX=1, FIRST_METHOD_INDEX=5 |
core/src/core/org/jnode/vm/classmgr/VmCP.java |
Runtime constant pool representation (256 lines): 12 JVM CP entry types |
The complete class loading and linking pipeline:
1. ClassDecoder.decodeClass(byte[])
→ parses .class file format
→ creates VmNormalClass, VmInterfaceClass, or VmArrayClass
→ populates constant pool, fields, methods, interfaces
2. VmType.link()
→ doPrepare() — build TIB (vtable), IMT, superclasses array, fix field offsets
→ doVerify() — verify superclass chain (TODO: full bytecode verification)
→ doCompile() — compile all methods via L1/L2 JIT compilers
→ sets ST_LINKED state flag
3. VmType.initialize()
→ invokes <clinit> via VmReflection.invokeStatic()
→ sets SST_INITIALIZED / IST_INITIALIZED state flag
VmType tracks class state through bit flags in VmTypeState:
ST_LOADED (0x0001) → Class bytes have been loaded
ST_DEFINED (0x0002) → Type has been defined in the VM
ST_PREPARING (0x0010) → TIB/IMT construction in progress
ST_PREPARED (0x0020) → TIB/IMT construction complete
ST_VERIFYING (0x0004) → Bytecode verification in progress
ST_VERIFIED (0x0008) → Bytecode verification complete
ST_COMPILING (0x0080) → JIT compilation in progress
ST_COMPILED (0x0040) → JIT compilation complete
ST_LINKED (0x2000) → prepare + verify + compile all done
ST_INITIALIZING → <clinit> execution in progress
ST_INITIALIZED → <clinit> execution complete
ST_INVALID (0x8000) → Class loading failed
State transitions are enforced by doPrepare(), doVerify(), doCompile(), and doInitialize() methods, each of which checks preconditions and sets the appropriate flags.
VmAnnotatedElement
└── VmType<T> (abstract, 2508 lines)
├── VmClassType<T> (abstract, 277 lines) — has TIB/vtable
│ ├── VmNormalClass<T> (168 lines) — regular classes
│ │ └── VmPrimitiveClass<T> (92 lines) — primitives
│ └── VmArrayClass<T> (182 lines) — array types
└── VmInterfaceClass<T> (96 lines) — interfaces (NO TIB)
See VmType-Hierarchy for detailed coverage of each class.
ClassDecoder parses the JVM class file format:
Class File Structure:
Magic Number (0xCAFEBABE)
Minor/Major Version
Constant Pool (12 entry types: UTF8, INT, FLOAT, LONG, DOUBLE,
CLASSREF, STRING, FIELDREF, METHODREF, IMETHODREF,
NAMEANDTYPE)
Access Flags
This Class / Super Class
Interfaces Table
Fields Table (with attributes: annotations, constant value)
Methods Table (with attributes: Code, Exceptions, Annotations)
Class Attributes (annotations, source file, signature, pragma flags)
Key parsing methods:
-
decodeClass()— main entry point, parses the entire class file -
readCode()— parses the Code attribute (max stack, locals, bytecode, exception table) -
readFields()— parses the field table, createsVmStaticFieldorVmInstanceField -
createFields()— allocates statics space, aligns fields, calculates offsets -
readMethods()— parses the method table, createsVmStaticMethod,VmSpecialMethod, orVmInstanceMethod -
readInterfaces()— parses the implemented interfaces table -
readRuntimeAnnotations()— parses annotation attributes -
getNativeCodeReplacement()— finds native method replacements (JNode's native method substitution mechanism)
The vtable is built by VmClassType.prepareTIB() using a TIBBuilder:
protected Object[] prepareTIB(HashSet<VmInterfaceClass<?>> allInterfaces) {
final VmNormalClass superClass = getSuperClass();
final TIBBuilder vmt;
if (superClass != null) {
// Inherit from superclass vtable
vmt = new TIBBuilder(this, superClass.getTIB(), tc_mtable_length);
} else {
// Root class (e.g., Object) starts with empty table
vmt = new TIBBuilder(this, tc_mtable_length);
}
// Process each declared instance method
for (VmInstanceMethod method : declaredMethods) {
if (!method.isStatic() && !method.isSpecial()) {
final int index = vmt.indexOf(name, signature);
if (index >= 0) {
if (vmt.overrides(index, method)) {
vmt.set(index, method); // Override
} else {
vmt.add(method); // Package-private: new slot
}
} else {
vmt.add(method); // New method: append
}
}
}
// Abstract classes: clone unimplemented interface methods
if (isAbstract()) {
for (VmInterfaceClass<?> icls : allInterfaces) {
for (VmMethod intfMethod : icls.getDeclaredMethods()) {
if (!intfMethod.isStatic()) {
final int index = vmt.indexOf(intfMethod.getName(), intfMethod.getSignature());
if (index < 0) {
vmt.add(new VmInstanceMethod(intfMethod)); // Clone
}
}
}
}
}
this.tib = vmt.toArray();
return tib;
}See Virtual-Methods-Dispatch for detailed coverage of vtable/IMT dispatch.
VmClassLoader defines the abstract classloader interface:
public abstract class VmClassLoader extends VmSystemObject {
public abstract VmType<?> loadClass(String className, boolean resolve);
public abstract VmType<?> findLoadedClass(String className);
public abstract VmType<?> defineClass(String name, byte[] data, ...);
public abstract VmType<?> defineClass(String name, ByteBuffer data, ...);
public abstract VmType<?> defineClass(VmType<?> createdType);
public abstract ClassLoader asClassLoader();
public abstract void disassemble(VmMethod vmMethod, int optLevel, ...);
public abstract CompiledIMT compileIMT(IMTBuilder builder);
public abstract VmArchitecture getArchitecture();
public abstract boolean isCompileRequired();
public abstract boolean isSystemClassLoader();
public abstract VmSharedStatics getSharedStatics();
public abstract VmIsolatedStatics getIsolatedStatics();
}Concrete implementations:
- VmSystemClassLoader — loads bootstrap classes from the boot image
- VmJavaClassLoader — loads application classes from the classpath
- PluginClassLoaderImpl — loads plugin classes with plugin-level delegation
See VM-Classloader for detailed coverage of each implementation.
VmType supports two compilation modes:
-
compileBootstrap()— called during boot image creation. Compiles all methods using the L1 compiler (fast, non-optimizing). Results are baked into the boot image. -
compileRuntime()— called at runtime viaLoadCompileService. Uses the L2 compiler (optimizing, SSA-based) for hot methods.
VmType maintains static singleton references for all 9 primitive classes and their array classes:
// Initialized during VM bootstrap via initializeForBootImage()
static VmPrimitiveClass BooleanClass, ByteClass, CharClass, ShortClass,
IntClass, LongClass, FloatClass, DoubleClass, VoidClass;
// Array classes for each primitive
static VmArrayClass BooleanArrayClass, ByteArrayClass, CharArrayClass, ...;These are reconstructed from the boot image via loadFromBootClassArray() when the VM starts.
-
No single "manager" class: The issue #75 referenced
VmTypeManager.javaandVmClassManager.java— these files do not exist. Class management is distributed acrossVmType,ClassDecoder, andVmClassLoader. -
Verification is a TODO:
VmType.doVerify()only checks the superclass chain. Full bytecode verification is not implemented — JNode trusts the class files it loads. -
Array classes delegate to component type:
VmArrayClass.prepare(),compile(), andverify()all delegate to the component type first, ensuring the component class is fully linked before the array class. -
Interfaces have no TIB:
VmInterfaceClass.prepareTIB()andprepareIMT()both return null. Interface method dispatch uses the IMT in the implementing class, not the interface itself. -
Pragma annotations control compilation: JNode uses custom
@Pragmaannotations to control JIT compilation behavior (e.g.,@NoInline,@Uninterruptible). ClassDecoder reads these during bytecode parsing. -
Native method replacement:
ClassDecoder.getNativeCodeReplacement()allows JNode to substitute native method implementations with Java code at class load time. - Duplicate ID detection in IMT only logs: The IMT builder logs duplicate selectors but does not prevent them — collision chains handle the resolution.
-
isAssignableFrom uses superClassesArray: The fast path for
isAssignableFrom()uses the precomputedsuperClassesArrayrather than walking the superclass chain at runtime.
- Type-System-Internals — VmType hierarchy, class loading pipeline, TIB construction
- VmType-Hierarchy — Detailed coverage of VmType, VmClassType, VmNormalClass, VmArrayClass, VmInterfaceClass, VmPrimitiveClass
- VM-Classloader — VmClassLoader contract and concrete implementations
- Virtual-Methods-Dispatch — vtable, IMT, CompiledIMT dispatch mechanisms
- JIT-Compilers — L1/L2 compiler pipeline, register allocation
- TIB — Type Information Block structure and construction
- vtable — Virtual method table construction and slot assignment
- IMT — Interface Method Table with 64-element hash table
- Object-Layout — Object header structure, TIB embedding, field alignment