-
Notifications
You must be signed in to change notification settings - Fork 0
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.
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.
| 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 |
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); }
}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.
The JIT compiler (both L1 and L2) recognizes unboxed types via MagicHelper:
-
No object allocation —
new Address(value)allocates the value in a register, not on the heap. -
Inline machine instructions —
address.loadInt()becomesMOV eax, [address]. -
Register-based arithmetic —
ptr.add(16)becomesADD ptr, 16in a register. - No GC overhead — Unboxed types are invisible to the garbage collector.
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 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();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.
-
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 confusion —
Offsetuses signed comparisons (sLT,sLE, etc.), whileExtentuses unsigned (LT,LE, etc.).Worduses 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
Objectvariables, and cannot be used withinstanceofagainst normal classes. -
Address != ObjectReference —
Addressis for raw memory;ObjectReferenceis 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.
- VM-Magic — The broader magic framework including annotations
- Unboxed-Types-and-VM-Magic — Existing companion page with additional compiler details
- JIT-Compilers — How MagicHelper integrates into the compiler pipeline
- Object-Layout — How the GC uses ObjectReference for heap scanning
- Code-Conventions — Guidelines on using unboxed types