Skip to content

Unboxed Types

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

Unboxed Types

Unboxed types (Address, Word, Offset, Extent) provide high-performance numeric and pointer types that avoid object allocation overhead, enabling low-level systems code to run efficiently.

Overview

JNode's VM needs to manipulate raw memory addresses and perform low-level operations that normal Java cannot express. The org.vmmagic.unboxed package provides four value types (Address, Word, Offset, Extent) that appear as Java classes but are compiled directly into machine registers by the JIT compiler.

The key insight (from every source file's header comment):

"This class contains some 'magic' methods that are interpreted by the VM itself, instead of being executed as normal java methods. The actual method bodies are never used."

Unlike regular Java objects, unboxed types carry no object header, no TIB reference, and no GC bookkeeping. They are pure machine values held in a final long field. When the JIT compiler encounters an unboxed type operation, MagicHelper intercepts the call and emits native instructions (MOV, ADD, SUB, CMP, etc.) directly. The result is performance equivalent to C, while retaining Java's type safety and the full IDE/tooling experience.

Key Components

Class / File Role
core/src/vmmagic/org/vmmagic/unboxed/Address.java Raw memory pointer type with load/store operations
core/src/vmmagic/org/vmmagic/unboxed/Word.java Unsigned machine-word integer with bitwise operations
core/src/vmmagic/org/vmmagic/unboxed/Offset.java Signed offset value for pointer arithmetic
core/src/vmmagic/org/vmmagic/unboxed/Extent.java Unsigned size/length value for buffer sizes
core/src/vmmagic/org/vmmagic/unboxed/ObjectReference.java Raw pointer to a Java object header
core/src/vmmagic/org/vmmagic/unboxed/UnboxedObject.java Marker interface (no methods) for unboxed type identification
core/src/vmmagic/org/vmmagic/unboxed/AddressArray.java Unboxed address array
core/src/vmmagic/org/vmmagic/unboxed/WordArray.java Unboxed word array
core/src/vmmagic/org/vmmagic/unboxed/OffsetArray.java Unboxed offset array
core/src/vmmagic/org/vmmagic/unboxed/ExtentArray.java Unboxed extent array
core/src/vmmagic/org/vmmagic/unboxed/ObjectReferenceArray.java Unboxed object reference array

How It Works

Common Structure

All four core scalar types share the same pattern:

public final class Xxx implements UnboxedObject {
    final long v;          // the underlying machine value
    private Xxx(long v) { this.v = v; }  // only BootImageBuilder can create
    public static Xxx fromInt(int val) { return new Xxx(val); }
    public static Xxx zero() { return new Xxx(0); }
    public static Xxx max() { return new Xxx(0xFFFFFFFFFFFFFFFFL); }
}

The Four Core Types

Address — A raw memory pointer. Used for memory-mapped I/O, DMA buffers, direct memory access.

Address ptr = Address.fromInt(0x1000);
Address ptr2 = ptr.add(Offset.fromInt(16));
int value = ptr.loadInt();
ptr.store(value + 1);

Key operations: add(Offset), sub(Offset), loadInt(), loadLong(), store(int), prepareWord(), attempt(old, new), diff(Address).

Word — An unsigned machine-word integer. Used for bitwise operations, bit masking, atomic operations.

Word bits = Word.zero().or(new Word(0xFF));
int shifted = bits.lsh(4).toInt();

Key operations: and(Word), or(Word), xor(Word), lsh(int), rshl(int), rsha(int), not().

Offset — A signed offset value for pointer arithmetic and field offset calculations.

Offset fieldOffset = Offset.fromInt(12);
int fieldValue = objRef.toAddress().add(fieldOffset).loadInt();

Key operations: add(int), sub(int), sLT(), sLE(), sGT(), sGE() — all signed.

Extent — An unsigned size/length value for memory allocation sizes and buffer lengths.

Extent size = Extent.fromInt(1024);
Extent remaining = size.sub(Extent.fromInt(256));

Key operations: add(Extent), sub(Extent), LT(), LE(), GT(), GE() — all unsigned.

JIT Compiler Treatment

The JIT compiler (both L1 and L2) recognizes unboxed types via MagicHelper:

  1. No object allocationnew Address(value) allocates the value in a register, not on the heap.
  2. Inline machine instructionsaddress.loadInt() becomes MOV eax, [address].
  3. Register-based arithmeticptr.add(16) becomes ADD ptr, 16 in a register.
  4. No GC overhead — Unboxed types are invisible to the garbage collector.

UnboxedObject Marker Interface

All unboxed types implement UnboxedObject:

public interface UnboxedObject {
    int toInt();
    long toLong();
}

This interface allows the compiler to quickly identify unboxed types via instanceof checks.

ObjectReference

ObjectReference is a raw pointer to a Java object header. Unlike Address, it is used exclusively for GC operations and is guaranteed to point to a valid object:

ObjectReference ref = ObjectReference.fromObject(myObject);
Address objAddress = ref.toAddress();

Array Types

The org.vmmagic.unboxed package also provides unboxed arrays (AddressArray, WordArray, OffsetArray, ExtentArray, ObjectReferenceArray) for performance-critical array operations where regular Java arrays would incur boxing overhead.

Gotchas & Non-Obvious Behavior

  • Method bodies are stubs — The actual Java implementations in these classes are never executed at runtime. All real work happens in the JIT's MagicHelper.
  • Signed vs unsigned confusionOffset uses signed comparisons (sLT, sLE, etc.), while Extent uses unsigned (LT, LE, etc.). Word uses unsigned comparisons. Mixing them up causes subtle bugs.
  • Private constructors — Normal code cannot create unboxed types directly. Use static factory methods (fromInt, zero, max).
  • No object header — Unboxed types have no identity, cannot be stored in Object variables, and cannot be used with instanceof against normal classes.
  • Address != ObjectReferenceAddress is for raw memory; ObjectReference is specifically for pointing at object headers in the GC heap.
  • @Uninterruptible annotation — Most unboxed type operations are annotated @Uninterruptible, meaning they cannot be preempted by thread switches. This is critical for safe memory operations.
  • Boxing overhead — Converting between unboxed and boxed types (e.g., Integer, Long) defeats the purpose. Keep values in unboxed form throughout hot paths.

Related Pages

Clone this wiki locally