Skip to content

Unboxed Types and VM Magic

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

Unboxed Types and VM Magic

Unboxed types (Address, Word, Offset, Extent) represent raw machine values that the JIT compiler translates into native instructions, bypassing Java object allocation.

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 that appear as Java classes but are compiled directly into machine registers by the JIT compiler.

The key insight from the source code (every unboxed class has this 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."

The Four Core Unboxed Types

All four types share a common structure:

  • final long v — the underlying machine value
  • Private constructor (only BootImageBuilder can create instances)
  • Static factory methods (fromInt, zero, max)
  • Arithmetic and comparison operations
  • toWord() / toOffset() / toExtent() conversion methods

Address

File: core/src/vmmagic/org/vmmagic/unboxed/Address.java

Represents a raw memory pointer. This is the primary type for:

  • Memory-mapped I/O operations
  • DMA buffer addressing
  • Direct memory access
Address ptr = Address.fromInt(0x1000);
Address ptr2 = ptr.add(16);  // pointer arithmetic
int value = ptr.loadInt();    // read 4 bytes from memory
ptr.store(value + 1);          // write 4 bytes to memory

Key operations:

  • add(Offset), sub(Offset) — pointer arithmetic
  • loadInt(), loadLong(), loadAddress() — memory reads
  • store(int), store(Address) — memory writes
  • prepareWord(), attempt(old, new) — atomic compare-and-swap
  • diff(Address) — returns Offset between two pointers

Word

File: core/src/vmmagic/org/vmmagic/unboxed/Word.java

An unsigned machine-word integer. Used for:

  • Low-level bitwise operations
  • Bit masking and shifting
  • Atomic operations
Word bits = Word.zero();
bits = bits.or(new Word(0xFF));
int shifted = bits.lsh(4).toInt();

Key operations:

  • and(Word), or(Word), xor(Word) — bitwise
  • lsh(int), rshl(int), rsha(int) — shifts (logical/arithmetic)
  • not() — bitwise negation
  • toAddress(), toOffset() — type conversions

Offset

File: core/src/vmmagic/org/vmmagic/unboxed/Offset.java

A signed offset value, used for pointer arithmetic:

  • Field offset calculations in object layout
  • Array index calculations
  • Memory region sizing
Offset fieldOffset = Offset.fromInt(12);
ObjectReference obj = ...;
Address fieldAddr = obj.toAddress().add(fieldOffset);
int fieldValue = fieldAddr.loadInt();

Key operations:

  • add(int), sub(int) — arithmetic
  • sLT(), sLE(), sGT(), sGE() — signed comparisons
  • EQ(), NE() — equality checks

Extent

File: core/src/vmmagic/org/vmmagic/unboxed/Extent.java

An unsigned size/length value. Used for:

  • Memory allocation sizes
  • Buffer lengths
  • Data structure sizes
Extent size = Extent.fromInt(1024);
Extent remaining = size.sub(Extent.fromInt(256));

Key operations:

  • add(Extent), sub(Extent) — arithmetic
  • LT(), LE(), GT(), GE() — unsigned comparisons

Compiler Treatment: How Unboxing Works

The JIT compiler recognizes these four types specially:

  1. No object allocation — When the compiler sees new Address(value), it allocates the value in a register instead of on the heap.

  2. Inline machine instructions — Method calls like address.loadInt() are intercepted by MagicHelper and replaced with MOV instructions:

    address.loadInt()  →  MOV eax, [address]
  3. Register-based arithmetic — Operations like ptr.add(16) become ADD ptr, 16 directly in a register.

  4. No null checks — Unlike normal object references, unboxed types don't trigger null pointer exceptions until the actual memory access occurs.

UnboxedObject Interface

All unboxed types implement UnboxedObject (marker interface with no methods):

public interface UnboxedObject {}

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

ObjectReference

File: core/src/vmmagic/org/vmmagic/unboxed/ObjectReference.java

A raw pointer to a Java object header. Unlike Address, this type is:

  • Used exclusively for GC operations
  • Guaranteed to point to a valid object
  • Convertible to/from Java objects
ObjectReference ref = ObjectReference.fromObject(myObject);
Address objAddress = ref.toAddress();
// Now we can use objAddress for memory scanning

MagicHelper Integration

The JIT compilers (L1, L1b, L2) contain MagicHelper classes that handle unboxed operations:

  • MagicHelper.processIntrinsic() — recognizes unboxed type operations
  • Emits x86 instructions directly (MOV, ADD, SUB, CMP, etc.)
  • Handles the signed/unsigned distinction for comparisons

Gotchas

  • Signed vs unsigned confusionOffset uses signed comparisons (sLT), while Extent uses unsigned (LT). Mixing them up causes subtle bugs.
  • No object header — Unboxed types have no identity, can't be stored in Object variables, and can't be used with instanceof against normal classes.
  • Private constructors — Normal code cannot create unboxed types directly. Use factory methods (fromInt, zero, max).
  • Method bodies are stubs — The actual Java implementations in these classes are never executed. All real work happens in the JIT's MagicHelper.
  • Address != ObjectReferenceAddress is for raw memory; ObjectReference is specifically for pointing at object headers in the GC heap.

Related Pages

  • VM-Magic — The broader magic framework including annotations
  • Code-Conventions — Guidelines on using unboxed types
  • Object-Layout — How the GC uses ObjectReference for heap scanning
  • JIT-Compilers — How MagicHelper integrates into the compiler pipeline

Clone this wiki locally