Skip to content

VM Level1A compiler: 'Register(s) in use' Error at X86RegisterPool.reset during boot-time Main invocation #614

Description

@LSantha

Summary

The Level1A x86 JIT compiler aborts with java.lang.Error: Register(s) in use (thrown by X86RegisterPool.reset, core/src/core/org/jnode/vm/x86/compiler/l1a/X86RegisterPool.java:236) while compiling a method invoked reflectively at boot time. Reproducible: the boot crashes right at the installer Main-Class invocation, every run.

Repro (QEMU)

  1. Build a boot initjar whose Main-Class is a normal Java class (e.g. the installer, org.jnode.install.Main) — see all/conf/install-plugin-list.xml.
  2. Boot it in QEMU (GRUB "JNode Install" entry / index 5 of the CD menu).
  3. Kernel, plugins and filesystems start fine; then the process dies at org.jnode.boot.Main.vmMain:
Error in compilation: java.lang.RuntimeException: Error in compilation
...
Caused by: java.lang.Error: Register(s) in use
	at org.jnode.vm.x86.compiler.l1a.X86RegisterPool.reset(X86RegisterPool.java:236)

Invocation point: core/src/core/org/jnode/boot/Main.java:95 — mainMethod.invoke(null, new Object[]{proc.getMainClassArguments()}).

Reproduced on two consecutive boots (same install initjar). The boot-time reflection Method.invoke triggers JIT compilation of the target method; the register pool is left non-empty when the compiled method returns, so the pooled register leak is detected as a fatal error.

Analysis

  • X86RegisterPool.reset(X86Assembler os) (X86RegisterPool.java:225-238) walks all registers and throws Error("Register(s) in use") if any is still allocated at reset time.
  • reset is called from EmitterContext.reset(os) (EmitterContext.java:96-97) at the end of a compilation (X86BytecodeVisitor.java:305-308), i.e. after each method body is emitted.
  • A thrown Error here aborts the whole boot (not just the offending method), which makes any boot-time Main-Class flow fragile: any single method that leaks a register kills the system.
  • No "Warning: register in use" was visible for the specific register before the throw, and the crash is deterministic for this workload, so it is a genuine leak (or a mid-method reset) rather than a rare race.

Impact

Any plugin with a Main-Class that does real work via the reflection invoke path (Main.java:91-95) is at risk. This currently blocks the JNode installer (see linked feature request) and would affect any future boot-time Main-Class plugin.

Suggested next steps

  1. Identify the compiled method that leaks the register (add a debug log of the current method name in X86RegisterPool.reset before the throw).
  2. Fix the leak (a missing release in some bytecode path, or an early reset mid-method).
  3. Consider making reset log-and-continue instead of throwing Error when the pool is dirty — a leaked register should be a warning + auto-release, not a fatal boot abort — while keeping the assertion during testing.

Reference

  • core/src/core/org/jnode/vm/x86/compiler/l1a/X86RegisterPool.java:225-238 (reset, throw at :236)
  • core/src/core/org/jnode/vm/x86/compiler/l1a/EmitterContext.java:96-97 (caller)
  • core/src/core/org/jnode/vm/x86/compiler/l1a/X86BytecodeVisitor.java:305-308 (reset sequence)
  • core/src/core/org/jnode/boot/Main.java:91-95 (reflection invoke that triggers the compile)

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/vmJVM internals: JIT compilers, GC, VM magic, type system.kind/bugConfirmed bug report with a repro or stack trace.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions