Skip to content

Release the autoload claim when Autoload#load has nothing to load - #2

Draft
aminmansuri wants to merge 4 commits into
jruby-10.0from
fix-autoload-slot-after-require
Draft

Release the autoload claim when Autoload#load has nothing to load#2
aminmansuri wants to merge 4 commits into
jruby-10.0from
fix-autoload-slot-after-require

Conversation

@aminmansuri

@aminmansuri aminmansuri commented Sep 12, 2026

Copy link
Copy Markdown
Owner

Autoload#load records the claim (ctx) before it checks featureAlreadyLoaded. When the feature is already loaded or still loading there is nothing to load, but the claim is kept. Any constant that file then defines is treated as this autoload's own result and parked on the Autoload; the constant table keeps UNDEF, autoload? and const_defined? report correctly, and every later lookup from another thread (Marshal.load, const_get, class reopening) goes through LoadService#featureAlreadyLoaded again instead of reading the table.

The feature is "already loaded or loading" in three common shapes: a direct require of the autoload's file, several constants declared with autoload against one file (ActiveSupport::Autoload's autoload_at, the usual Rails layout) where the first one loaded parks its siblings, and a circular require between two autoloaded files.

On the command line that walk is cheap. Under a classloader-backed $LOAD_PATH (a WAR) each lookup costs about 450 µs; a page deserialising 89 cached objects spent 1,229 ms in Marshal.load, 36 ms once the slots held their values.

The fix releases the claim in the already-loaded branch. The specs pin what Ruby can observe (a Marshal.load and a $LOAD_PATH change from another thread no longer depend on the loader; remove_const returns the value; every constant of a shared file becomes a regular constant); the test/jruby cases pin the constant-table slot itself, including the sibling and circular shapes.

A direct require of the autoload's file defines the constant while the
claim is still held, so the value stays on the Autoload and the constant
table keeps UNDEF; every later lookup from another thread re-enters LoadService.
ruby/spec pins what Ruby can see (remove_const value, Marshal and $LOAD_PATH
independence from another thread); test/jruby pins the constant-table slot.
@aminmansuri aminmansuri reopened this Sep 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant