Skip to content

VMMagic Annotations

Levente Santha edited this page May 11, 2026 · 1 revision

VMMagic Annotations

JVM annotations directing JIT compiler behavior and thread scheduler guarantees.

Overview

JNode uses annotations in org.jnode.annotation to provide the compiler and runtime with special information about methods and classes. These annotations are critical for kernel-level code that must avoid garbage collection safepoints or context switches.

Key Annotations

Annotation File Purpose
@Uninterruptible core/src/classlib/org/jnode/annotation/Uninterruptible.java Prevents context switches and GC safepoints
@Inline core/src/classlib/org/jnode/annotation/Inline.java Hints to JIT to inline the method
@NoInline core/src/classlib/org/jnode/annotation/NoInline.java Prevents JIT from inlining
@MagicPermission core/src/classlib/org/jnode/annotation/MagicPermission.java Grants access to Unsafe/VmMagic
@KernelSpace core/src/classlib/org/jnode/annotation/KernelSpace.java Marks ring-0 privilege
@LoadStatics core/src/classlib/org/jnode/annotation/LoadStatics.java Skip boot image serialization
@SharedStatics core/src/classlib/org/jnode/annotation/SharedStatics.java Share statics across isolates

@Uninterruptible

Purpose

The @Uninterruptible annotation marks methods that must run to completion without being preempted by the thread scheduler. This is critical for:

  • Lock implementation (spinlocks)
  • Interrupt handlers
  • GC-safe operations that cannot tolerate safepoints

Compiler Treatment

The L1/L2 JIT compilers recognize @Uninterruptible methods:

  • No yieldpoint injection (no INT 0x30)
  • No GC safepoint checks
  • Direct call without scheduling overhead

Runtime Behavior

When a thread enters an @Uninterruptible method:

  1. The TSI (Thread State Indicator) flag is set
  2. The scheduler skips this thread for preemption
  3. GC does not stop this thread for safepoints
// From SpinLock.java
@Uninterruptible
public final void lock() {
    while (!compareAndSet(false, true)) {
        // Busy-wait - will NOT be preempted
    }
}

@Inline / @NoInline

@Inline

Hints to the JIT compiler that the method should be inlined:

@Inline
public final int add(int a, int b) {
    return a + b;
}

The L2 compiler's InlinePolicy evaluates methods based on:

  • Code size (smaller is preferred)
  • Call frequency (hotter is preferred)
  • Complexity (simple control flow is preferred)

@NoInline

Prevents inlining, useful for:

  • Methods with side effects that depend on call depth
  • Debugging - keep stack frames readable
  • Security-sensitive code requiring distinct call stacks

@MagicPermission

Required to use org.jnode.vm.Unsafe or org.jnode.vm.VmMagic:

@MagicPermission("org.jnode.driver.DriverManager")
public class DriverManager extends BasicKernelObject {
    // Can now call Unsafe.getAddress(), VmMagic.getObjectType(), etc.
}

The @MagicPermission annotation specifies which class grants permission—this is checked at class loading time.

@LoadStatics

Used by BootImageBuilder to skip static field serialization:

@LoadStatics
public class SomeClass {
    // Statics will be re-initialized at runtime, not serialized in boot image
    static int counter = computeInitialValue();
}

See LoadStatics-Annotation for details.

@SharedStatics

By default, each isolate has its own static fields. @SharedStatics makes statics shared across all isolates:

@SharedStatics
public class SystemClass {
    static int systemState;  // Same across all isolates
}

Code Example

From core/src/core/org/jnode/vm/scheduler/SpinLock.java:

@Uninterruptible
public final boolean tryLock() {
    return compareAndSet(false, true);
}

From core/src/core/org/jnode/vm/Unsafe.java:

@MagicPermission("org.jnode.vm.Unsafe")
@Uninterruptible
public static Address getObjectAddress(Object obj) {
    return VmMagic.getObjectAddress(obj);
}

Gotchas

  • @Uninterruptible methods cannot allocate objects (GC interactions)
  • @Uninterruptible cannot call non-@Uninterruptible methods (would introduce safepoint)
  • @Inline is only a hint—JIT may ignore it based on InlinePolicy
  • @LoadStatics methods must be idempotent (called at both build and runtime)

Related Pages

Clone this wiki locally