Skip to content

VM Unsafe

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

VM Unsafe

Low-level operations for direct memory access, hardware I/O, and VM introspection in JNode.

Overview

org.jnode.vm.Unsafe (often called "VM Unsafe" to distinguish from sun.misc.Unsafe) provides a constrained set of low-level operations unavailable in standard Java. Unlike sun.misc.Unsafe, it is restricted to classes annotated with @MagicPermission and exposes only a carefully curated API. The class is complemented by UnsafeX86 for x86-specific operations like MSR read/write and CPUID.

VM Unsafe is a bridge between Java and the native world without JNI—the JIT compiler recognizes Unsafe calls and emits direct machine instructions.

Key Components

Class / File Role
core/src/core/org/jnode/vm/Unsafe.java Main API: memory access, debug output, CPU operations, port I/O
core/src/core/org/jnode/vm/x86/UnsafeX86.java x86-specific: GDT/TSS, MSR, CPUID, VBE, AP boot code
core/src/core/org/jnode/vm/compiler/BaseMagicHelper.java Base helper recognizing Unsafe calls during compilation
core/src/core/org/jnode/vm/x86/compiler/l1a/MagicHelper.java L1 compiler intrinsic generation for Unsafe operations
core/src/core/org/jnode/vm/x86/compiler/l2/MagicHelper.java L2 compiler intrinsic generation for Unsafe operations
core/src/native/x86/unsafe.asm Assembly helpers (e.g., Unsafe.yieldPoint via INT 0x30)

How It Works

Security Model

@MagicPermission annotation marks classes allowed to use Unsafe. Any class using Unsafe or VmMagic methods must carry this annotation. The JIT compiler checks this at compile time and refuses to compile calls from unmarked classes.

@MagicPermission
public final class Unsafe {
    // All public methods are accessible from @MagicPermission classes
}

Memory Operations

Unsafe provides typed bulk memory operations that map directly to native memset/memcpy equivalents:

Unsafe.setInts(addr, value, count);   // memset to int
Unsafe.setLongs(addr, value, count);  // memset to long
Unsafe.setObjects(addr, object, count); // set object references
Unsafe.clear(memPtr, size);           // zero memory (SLOT_SIZE aligned)
Unsafe.copy(src, dest, size);         // memcpy (non-overlapping)

Each typed variant includes bitwise AND/OR/XOR operations for atomic modifications without a loop.

Debug Output

Unsafe.debug(...) is the only logging mechanism available before the class library is initialized. Unlike System.out.println, it requires no object allocation or synchronization.

Unsafe.debug("boot: ");
Unsafe.debug(42);
Unsafe.debug(new Address(0x1000));
Unsafe.debugStackTrace(); // print current stack to debug console

CPU Operations

x86-specific operations via UnsafeX86:

UnsafeX86.getCR3();           // Read CR3 register (page directory pointer)
UnsafeX86.getCPUID(input, result); // CPU identification
UnsafeX86.readMSR(index);      // Read Model Specific Register
UnsafeX86.writeMSR(index, value); // Write Model Specific Register
UnsafeX86.getMultibootMMap(); // Get GRUB memory map

Port I/O

Direct x86 port access for hardware communication:

Unsafe.inPortByte(portNr);
Unsafe.inPortWord(portNr);
Unsafe.inPortDword(portNr);
Unsafe.outPortByte(portNr, value);
Unsafe.outPortWord(portNr, value);
Unsafe.outPortDword(portNr, value);

Used by drivers (IDE, serial) to communicate with hardware via standard I/O port ranges.

Address Information

System memory layout queries:

Unsafe.getMemoryStart()/getMemoryEnd()     // Available physical memory
Unsafe.getKernelStart()/getKernelEnd()     // Kernel image bounds
Unsafe.getBootHeapStart()/getBootHeapEnd() // Boot-time heap
Unsafe.getInitJarStart()/getInitJarEnd()   // Embedded plugin JAR

Jump Table

Unsafe.getJumpTable() and Unsafe.getJumpTableEntry(index) provide access to the native method dispatch jump table. This requires JNodePermission("getJumpTable") and is used by the JIT to resolve native method addresses.

Gotchas

  • No JNI: Unsafe methods are not native in the traditional sense—they have no JNI overhead. The JIT compiler recognizes the class name and emits inline assembly directly.
  • @MagicPermission required: Any class calling Unsafe methods must be annotated. The compiler enforces this.
  • 32-bit vs 64-bit: Some methods (e.g., getJumpTableEntry) use architecture-specific ReferenceSize to compute offsets.
  • Alignment for clear: Unsafe.clear() requires memPtr to be VmObject.SLOT_SIZE aligned and size to be a multiple of SLOT_SIZE.
  • VBE is deprecated: Unsafe.callVbeFunction is explicitly marked bogus and untested—avoid it.
  • UnsafeObjectResolver: Inner class extending ObjectResolver for object-to-address mapping during boot image assembly.

Related Pages

Clone this wiki locally