Pre-initialize TRegex in the Graal fallback classloader - #72
Merged
Conversation
TRegex resolves its static loggers the first time a regex is compiled.
That lookup validates the "regex" language id against the languages
visible from the thread context classloader, which on a server thread is
NeoForge's classloader that does not see the packaged Graal jars:
java.lang.IllegalArgumentException: Unknown language or instrument id
regex, known ids: debugger, engine, graal, sandbox
at TruffleLogger$LoggerCache.getOrCreateLogger
at com.oracle.truffle.regex.tregex.util.Loggers.<clinit>
at com.oracle.truffle.regex.tregex.TRegexCompiler.compile
Because it happens inside a static initializer, the failure is permanent
for the JVM session, and every later script using a regex only reports
"NoClassDefFoundError: Could not initialize class
com.oracle.truffle.regex.tregex.util.Loggers".
Graal 25.0 cached this id set on the logger cache, so it was resolved once
during startup. Since 25.1 it is resolved per call, which is why this only
appeared after the Graal bump.
Compiling a regex during the startup pre-load initializes TRegex while the
context classloader still points to the Graal fallback classloader, where
all other Graal initialization already happens.
Closes #68
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwXjG9jWXimuecAeHk5oby
Coverage Report for CI Build 33665833901Coverage increased (+0.2%) to 46.158%Details
Uncovered ChangesNo uncovered changes found. Coverage RegressionsNo coverage regressions found. Coverage Stats
💛 - Coveralls |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #68 (regex usage breaking since 1.0.26).
The bug
Reproduced in a game test on a clean dev environment. The reporter's visible error is only a follow-on symptom:
The actual first failure is:
TRegex resolves its static loggers the first time a regex literal is compiled. That lookup validates the
regexlanguage id against the languages visible from the thread context classloader, which on a server thread is NeoForge's classloader and does not see the packaged Graal jars (note thatjsis missing from the known ids too). Because this happens inside a static initializer, the failure is permanent for the whole JVM session, so every later script using a regex only ever reports theNoClassDefFoundErrorabove, no matter how the script is edited.Why it started at 1.0.26
Graal 25.0 resolved this id set through
EngineSupport.getLanguageIds()and cached it on the logger cache (TruffleLogger$LoggerCache.knownIds). Since 25.1 it is resolved per call viaEngineSupport.isKnownLoggerId(...)againstLanguageCache.languages(), which depends on the current thread context classloader. That matches the report: fine on 1.0.24 (Graal 25.0.x), broken on 1.0.26 (25.2.4).The fix
Compile a regex during the existing startup pre-load, so TRegex initializes while the context classloader still points to the Graal fallback classloader, which is where all other Graal initialization already happens.
Tests
Added
testScriptsDisplayScriptRegex, which applies a script function containing a regex literal. It fails on master with exactly the reporter'sNoClassDefFoundError, and passes with this change../gradlew buildand./gradlew runGameTestServerboth pass on this branch (all 22 game tests).master-1.20-lts
Not applicable, for two independent reasons:
PackagedDependenciesLoader/UnsafeHelper. It ships Graal throughshadowJarwith package relocation, so Graal is on the mod's own classpath and there is no fallback classloader to be blind to. There is also no game test infrastructure there for the regression test.graal_version=25.0.1, which predates the Graal change described above.🤖 Generated with Claude Code
https://claude.ai/code/session_01DwXjG9jWXimuecAeHk5oby
Generated by Claude Code