Skip to content

VmType Hierarchy

opencode-agent[bot] edited this page May 10, 2026 · 1 revision

VmType Hierarchy

The class hierarchy that represents Java types at runtime: VmType as the abstract root, with VmClassType (normal/interface classes), VmArrayClass (arrays), and VmPrimitiveClass (primitives) as concrete branches.

Overview

JNode's runtime type representation forms a hierarchy rooted at VmType. Each branch handles a distinct category of Java types. The hierarchy manages loading state, field/method tables, constant pools, TIB construction, and initialization. Understanding the hierarchy is essential for working on JIT compilation, garbage collection, and class loading.

Key Components

Class File Purpose
VmType classmgr/VmType.java Abstract root of the type hierarchy
VmClassType classmgr/VmClassType.java Base for class-like types with TIB/vtable support
VmNormalClass classmgr/VmNormalClass.java Regular (non-interface, non-array) class
VmInterfaceClass classmgr/VmInterfaceClass.java Interface type
VmArrayClass classmgr/VmArrayClass.java Array type
VmPrimitiveClass classmgr/VmPrimitiveClass.java Primitive type (boolean, int, etc.)
VmArray classmgr/VmArray.java Base class for array instances (not VmType hierarchy)
JvmType classmgr/VmType.java Integer constants for JVM type categories

How It Works

Class Hierarchy Diagram

VmAnnotatedElement
  └── VmType (abstract)                           // Root of type hierarchy
        ├── VmClassType (abstract)                 // Has vtable/TIB
        │     ├── VmNormalClass                    // Regular class
        │     │     └── VmPrimitiveClass            // boolean, int, long, etc.
        │     └── VmInterfaceClass                 // Interface
        │     └── VmArrayClass                     // Array type
        └── (VmInterfaceClass also extends VmType directly)

Note: VmArrayClass extends VmClassType, while VmInterfaceClass extends VmType directly (not through VmClassType).

VmType — Abstract Root

VmType (2508 lines) is the abstract base for all type representations. It holds:

  • Identity: name, superClassName, modifiers, signature
  • Structure: methodTable, fieldTable, interfaceTable
  • State: state (char flags per VmTypeState: LOADED, PREPARED, VERIFIED, COMPILED, LINKED, INITIALIZED)
  • Loading: loader (VmClassLoader), protectionDomain
  • Memory: mmType (memory manager type info), typeSize
  • TIB support: isolatedStaticsIndex, sharedStaticsIndex
  • Arrays: Lazy arrayClass creation for component types
  • Constant pool: cp (VmCP)

Key methods:

  • link() — orchestrates prepare → verify → compile
  • initialize() — invokes <clinit> via doInitialize()
  • isPrimitive(), isArray(), isInterface() — type categorization
  • getSuperClass(), getField(), getMethod() — inheritance lookup
  • getArrayClassName() — generates JVM array descriptor syntax

VmType.initializeForBootImage() creates the 12 system primitive classes and their array classes during VM bootstrap:

BooleanClass = new VmPrimitiveClass("boolean", ObjectClass, clc, JvmType.BOOLEAN, 1, false, pd);
IntClass = new VmPrimitiveClass("int", ObjectClass, clc, JvmType.INT, 4, false, pd);
// ...
BooleanArrayClass = BooleanClass.getArrayClass("[Z");

VmClassType — TIB-bearing Class Base

VmClassType (277 lines) extends VmType for types that have a virtual method table. It adds:

  • tib — the Object[] array containing vtable, IMT, and type metadata
  • instanceCount — instance creation counter
  • syntheticAbstractMethods — cloned interface methods for abstract classes

prepareTIB() constructs the TIB by:

  1. Initializing TIBBuilder from superclass's TIB
  2. Walking declared methods, adding new virtual methods or overriding existing slots
  3. For abstract classes, cloning unimplemented interface methods as synthetic entries
  4. Building the IMT via prepareIMT() for interface method dispatch

prepareIMT() iterates all implemented interfaces, mapping each interface method to a concrete implementation and adding it to IMTBuilder for the 64-slot hash table.

VmNormalClass — Regular Class

VmNormalClass (168 lines) extends VmClassType for regular classes (non-interface, non-array). It adds:

  • objectSize — size in bytes of instances
  • referenceOffsets — array of field offsets for GC heap tracing

prepareForInstantiation() walks the superclass chain, accumulating objectSize and collecting referenceOffsets:

int sc_size = (superCls != null) ? superCls.getObjectSize() : 0;
objectSize += sc_size;
// ... walk fields, resolve offsets ...
referenceOffsets = new int[refOffsetsSize];

Field offset resolution happens in VmInstanceField.resolveOffset(), which calculates the aligned offset based on field size.

VmArrayClass — Array Type

VmArrayClass (182 lines) extends VmClassType for array types. Unlike regular classes, it:

  • Stores componentType (the element VmType)
  • Auto-implements Cloneable and Serializable
  • Implements isPrimitiveArray() by delegating to componentType.isPrimitive()
  • Inherits getArrayClassName() from VmType which builds [ descriptors: [[I for int[], [Ljava/lang/String; for object arrays

createSuperClassesArray() builds the class hierarchy including component type arrays:

final int length = compLength + 2 + allInterfaces.size();
final VmType<?>[] array = new VmType[length];
array[0] = this;
array[1] = this.getSuperClass(); // always Object
for (int i = 0; i < compLength; i++) {
    array[2 + i] = compSuperClasses[i].getArrayClass(false);
}

Arrays are always direct subclasses of java.lang.Object but include the component type's hierarchy as additional superclasses at indices 2+.

VmInterfaceClass — Interface Type

VmInterfaceClass (96 lines) extends VmType directly (not through VmClassType) because interfaces do not have a vtable. Constructor enforces:

  • Superclass must be java.lang.Object
  • Cannot be an array class
  • Must have the ACC_INTERFACE modifier

Methods prepareTIB() and prepareIMT() return null — interfaces have no TIB.

VmPrimitiveClass — Primitive Type

VmPrimitiveClass (92 lines) extends VmNormalClass for the 9 built-in types (boolean, byte, char, short, int, long, float, double, void). It adds:

  • jvmType — the JvmType integer constant (1–10)
  • floatingPoint — true for float/double
  • wide — true for long/double (2-word values)

The constructor accepts the JvmType value and forwards typeSize (1, 2, 4, or 8 bytes) to VmNormalClass. getJvmType() returns the stored integer.

VmArray — Array Instance Base (Not VmType)

VmArray (77 lines) extends VmSystemObject and is the runtime representation of array instances (the object header). It is not part of the VmType hierarchy. It defines:

public static final int LENGTH_OFFSET = 0;
public static final int DATA_OFFSET = LENGTH_OFFSET + 1;

The actual array data follows the object header (flags + TIB) and length word. Static helper methods (equals(char[], char[]), equals(char[], String)) are used during boot image verification.

JvmType — Type Constants

JvmType (297 lines) provides integer constants for all JVM type categories:

Constant Value Notes
UNKNOWN 0
BOOLEAN 1
BYTE 2
SHORT 3
CHAR 4
INT 5
LONG 6 2-word category
FLOAT 7
DOUBLE 8 2-word category
REFERENCE 9
VOID 10

Key methods:

  • getCategory(int type) — returns 2 for long/double, 0 for void, 1 otherwise
  • SignatureToType(char) — maps JVM signature characters (Z, B, I, J, F, D, L, [, etc.) to JvmType constants
  • getArgumentTypes(String) — parses method signatures into type arrays
  • getReturnType(String) — extracts return type from method signature

Gotchas

  • VmArray vs VmArrayClass: VmArray is the runtime object header for array instances (extends VmSystemObject), while VmArrayClass is the type metadata (extends VmClassType). Do not confuse the two.
  • VmInterfaceClass skips VmClassType: Interfaces have no vtable, so VmInterfaceClass extends VmType directly. prepareTIB() returns null.
  • Array class naming: VmType.getArrayClassName() generates JVM array descriptors with [ prefix and L...; for reference types. Component types are resolved lazily.
  • Statics isolation: Each VmType has both a sharedStaticsIndex (via @SharedStatics) and an isolatedStaticsIndex for per-isolate static fields.
  • Primitive class bootstrap: VmType.initializeForBootImage() creates all primitive classes and their array classes in one pass, but loadFromBootClassArray() must reconstruct the static references from the boot image.
  • Synthetic abstract method cloning: When a class implements an interface but doesn't override all methods, VmClassType.prepareTIB() clones the abstract method. The clone is necessary because the VMT offset is set on the original and must not be shared across abstract classes.

Related Pages

  • Type-System-Internals — Broader type system context, class loading pipeline, TIB construction
  • Object-Layout — Object header structure, instance field layout, alignment
  • TIB — Type Information Block construction and contents
  • vtable — Virtual method table slot assignment
  • IMT — Interface Method Table hash-based dispatch
  • Virtual-Methods-Dispatch — Dispatch mechanisms (vtable, IMT, CompiledIMT)
  • JIT-Compilers — Method compilation triggered by VmType

Clone this wiki locally