Skip to content

VM Classloader

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

VM Classloader

JVM classloader implementation with plugin delegation.

Overview

JNode's VM classloader system bridges the JVM's class loading requirements with JNode's plugin-based architecture. The core abstraction is VmClassLoader (org.jnode.vm.classmgr.VmClassLoader), an abstract base class that extends VmSystemObject and defines the contract for loading classes into the VM. Unlike standard Java where ClassLoader is the primary interface, JNode's VmClassLoader is designed around the needs of a native OS: class definition from ByteBuffer/byte[], resource loading, statics management, JIT compiler integration, and architecture-aware IMT compilation.

The classloader hierarchy serves two distinct purposes. The first is the Java classloader delegation chain — the standard parent-first lookup pattern — which JNode implements via VmSystemClassLoader.loadClass() delegating to a ClassLoaderWrapper. The second is plugin-based class isolation — each plugin gets its own PluginClassLoaderImpl, which can only see classes from its own JAR and its declared prerequisites. These two systems are bridged by VmJavaClassLoader, which wraps a Java ClassLoader and converts Class<?> objects to VmType<?> instances.

Key Components

Class / File Role
core/src/core/org/jnode/vm/classmgr/VmClassLoader.java Abstract base class for all VM classloaders
core/src/core/org/jnode/vm/VmAbstractClassLoader.java Common defineClass logic, array class loading, security checks
core/src/core/org/jnode/vm/VmSystemClassLoader.java Default system classloader; loads from URLs, systemRtJar, or ResourceLoaders
core/src/core/org/jnode/vm/VmJavaClassLoader.java Wraps a Java ClassLoader, converts Class<?> to VmType<?>
core/src/core/org/jnode/plugin/model/PluginClassLoaderImpl.java Per-plugin classloader: loads from plugin JAR, delegates to prerequisites
core/src/core/org/jnode/plugin/model/PluginsClassLoader.java Aggregator that searches all non-system plugin classloaders

How It Works

Classloader Hierarchy

BootClassLoader (VM built-in — no Java representation)
  └── VmSystemClassLoader (default system classloader, ~ClassLoader.getSystemClassLoader())
        ├── VmJavaClassLoader [wraps arbitrary ClassLoaders]
        └── ClassLoaderWrapper [bridges VmClassLoader to java.lang.ClassLoader]

Loading a Class (VmSystemClassLoader)

The VmSystemClassLoader.loadClass(name, resolve) method implements the standard delegation:

  1. Check parent ClassLoader first (via parent.loadClass(name))
  2. Check if class is already loaded via findLoadedClass(name)
  3. Load from the boot class path:
    • If systemRtJar is set: look up in the JAR map, then in registered ResourceLoaders
    • Otherwise: open a resource stream from classesURL and read .class bytes
  4. Call ClassDecoder.defineClass() to parse bytecode into a VmType
  5. If resolve is true, call vmClass.link() to prepare the class

The key design choice is that VmSystemClassLoader enforces that only it can define java.lang.* and org.jnode.vm.* classes (via the isSystemClassLoader() check in VmAbstractClassLoader.defineClass()).

Array Class Loading

Array classes (byte[], MyClass[], etc.) are handled specially in VmAbstractClassLoader.loadArrayClass(). For reference arrays, the component type is loaded recursively, then VmType.getArrayClass() constructs the array class. Primitive arrays use predefined singletons from VmType.getPrimitiveArrayClass().

Plugin Classloading

Plugin classloaders (PluginClassLoaderImpl) work alongside the VM classloader system:

  1. Each plugin has a PluginClassLoaderImpl that loads from its JAR
  2. findPluginClass() checks prerequisite plugin classloaders first (dependency chain)
  3. Falls back to findLoadedClass(), then fragment JARs, then the plugin's own JAR
  4. On successful class load, the plugin is started automatically
  5. A PluginsClassLoader aggregates all non-system plugin classloaders as a fallback

Class Definition Flow

VmAbstractClassLoader.defineClass() synchronizes on the classloader instance and:

  1. Checks if the class is already loaded (returns the cached instance)
  2. Calls LoadCompileService.defineClass() to parse bytecode and create the VmType
  3. Verifies the class belongs to a package the classloader is allowed to define
  4. Adds the class to the loaded classes map

JIT Compiler Integration

VmClassLoader provides methods for JIT compiler support:

  • getArchitecture() — returns VmArchitecture for ISA-specific compilation
  • compileIMT(IMTBuilder) — generates architecture-specific interface method table code
  • disassemble(VmMethod, ...) — dumps compiled method bytecode for debugging
  • getSelectorMap() — maps method signatures to unique selectors
  • getSharedStatics() / getIsolatedStatics() — access static field storage

Gotchas & Non-Obvious Behavior

  • Bootstrap class gatingVmSystemClassLoader sets failOnNewLoad during boot image initialization to catch unexpected dynamic class loading. Once prepareAfterBootstrap() is called, normal class loading resumes.
  • Security restriction on class definitionVmAbstractClassLoader.defineClass() throws SecurityException if a non-system classloader attempts to define org.jnode.vm.* or java.lang.* classes. This prevents plugins from injecting classes into protected namespaces.
  • Array class cache — Array classes are cached on the component VmType via VmType.getArrayClass(). The same array class instance is returned for repeated Object[] lookups.
  • Parent-first is advisory — The parent.skipParentLoader(name) check in VmSystemClassLoader allows certain classes to bypass the parent loader. This is used to redirect core classes back to the VM's built-in mechanisms.
  • Plugin classloader delegationPluginClassLoaderImpl.findPluginClass() tries prerequisite loaders BEFORE checking findLoadedClass(). This means dependency classes are always loaded from their owning plugin, not from a parent that may have cached a different version.
  • ClassInfo wait/notifyVmSystemClassLoader.ClassInfo uses wait()/notifyAll() for concurrent class loading. Multiple threads requesting the same class block until the first thread completes the load.

Related Pages

Clone this wiki locally