Skip to content

Field Offset Calculation

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

Field Offset Calculation

Runtime computation of instance field positions within Java objects and TIB array indexing for type metadata access.

Overview

Field offset calculation determines where each instance field resides in memory relative to an object's base address. This is critical for JIT compilers to generate efficient field access code, for the VM to perform fast GETFIELD/PUTFIELD operations, and for understanding object memory layout. JNode calculates field offsets during class loading and stores them in VmInstanceField objects for runtime use.

Object Memory Layout

Every JNode object consists of:

┌─────────────────────────────────────────────────────────────┐
│  OBJECT HEADER (2 slots)                                    │
├─────────────────────┬───────────────────────────────────────┤
│  FLAGS_SLOT (-2)    │  TIB_SLOT (-1)                        │
└─────────────────────┴───────────────────────────────────────┘
         │                        │
         ▼                        ▼
   Offset -2 * SLOT_SIZE    Offset -1 * SLOT_SIZE
         │                        │
         ▼                        ▼
[Object Start] ──────────► Instance Fields Start at Offset 0

The header consumes 2 slots (defined in ObjectLayout.HEADER_SLOTS). Instance fields begin at offset 0, immediately after the header.

Field Offset Calculation Process

1. Initial Offset Assignment (ClassDecoder)

During class loading, ClassDecoder assigns preliminary field offsets in declaration order:

// ClassDecoder.java:761-775
final int fieldOffset = objectSize;  // Start after header
if (wide)
    objectSize += 8;      // long/double
else if (Modifier.isPrimitive(signature))
    objectSize += 4;      // int, float, etc.
else
    objectSize += slotSize;  // reference (4 or 8 bytes)
fs = new VmInstanceField(name, signature, modifiers, fieldOffset, cls, slotSize);

The offset is initially relative to the class's own object size. Later, ClassResolver.resolveFieldOffsets() adjusts these to be relative to the complete object (including superclass fields).

2. Offset Resolution (VmNormalClass)

Subclass field offsets must account for the complete inheritance chain:

// VmNormalClass.java:143-146
for (VmInstanceField inf : instanceFields) {
    inf.resolveOffset(superClassSize);  // Add superclass field size
}

3. Runtime Access (VmInstanceField)

At runtime, the stored offset is used directly:

// VmInstanceField.java:60-62
public final int getOffset() {
    return offset;
}

The JIT compilers use this offset to generate direct memory accesses like:

  • mov eax, [ebx + offset] (GETFIELD)
  • mov [ebx + offset], value (PUTFIELD)

TIB Array Indexing (TIBLayout)

The TIB (Type Information Block) is an Object[] array containing type metadata. Indexes are defined in TIBLayout:

Index Constant Type Purpose
0 VMTYPE_INDEX VmType The VmType instance
1 IMT_INDEX Object[] Interface Method Table
2 IMTCOLLISIONS_INDEX boolean[] IMT collision flags
3 COMPILED_IMT_INDEX Object Compiled IMT
4 SUPERCLASSES_INDEX VmType[] Superclass chain
5+ FIRST_METHOD_INDEX Virtual method table

TIB array indexing is distinct from field offset calculation—it addresses the TIB array itself, not object instance fields.

Key Components

Class / File Role
core/src/core/org/jnode/vm/classmgr/ObjectLayout.java Defines FLAGS_SLOT (-2), TIB_SLOT (-1), HEADER_SLOTS (2), OBJECT_ALIGN (8)
core/src/core/org/jnode/vm/classmgr/TIBLayout.java TIB array index constants (VMTYPE_INDEX through SUPERCLASSES_INDEX)
core/src/core/org/jnode/vm/classmgr/VmInstanceField.java Stores runtime field offset in offset field, provides getOffset()
core/src/core/org/jnode/vm/classmgr/ClassDecoder.java Initial field offset calculation during class loading (lines 761-775)
core/src/core/org/jnode/vm/classmgr/VmNormalClass.java Resolves field offsets for inheritance (resolveOffset method)
core/src/core/org/jnode/vm/classmgr/VmType.java Coordinates field layout computation

How It Works

  1. Class Loading: ClassDecoder reads bytecode field info and assigns sequential offsets starting at 0 (after the 2-slot header)

  2. Inheritance Resolution: VmNormalClass.resolveFieldOffsets() adds the superclass size to each inherited field's offset

  3. Runtime Access: JIT-compiled code uses VmInstanceField.getOffset() to generate direct memory accesses

  4. TIB Access: JIT compilers use TIBLayout constants to index into the TIB array for method dispatch, type checking, and GC

Gotchas & Non-Obvious Behavior

  • Negative header offsets: The object header extends before the object address—FLAGS_SLOT is at -2, TIB_SLOT at -1
  • Slot size varies: 32-bit mode uses 4-byte slots, 64-bit uses 8-byte slots—offsets scale accordingly
  • Wide field alignment: long and double fields (8 bytes) may introduce padding to maintain alignment
  • Object alignment: Final object size is aligned to 8 bytes (ObjectLayout.OBJECT_ALIGN), affecting heap allocation
  • TIB indexing vs field offsets: TIBLayout defines array indexes in the TIB metadata array, not object field positions
  • Static fields not included: Static fields are stored in a separate statics area, not in the object layout

Related Pages

Clone this wiki locally