Skip to content

Monitor oracle/graal#7520: remove platform thread workaround when Truffle fixes virtual thread support #665

Description

@mkjsix

Background

Issue #663 required routing all Truffle operations through a single dedicated platform thread ("RH JS PLT") to work around DefaultContextThreadLocal.fastGet() throwing ArrayIndexOutOfBoundsException: Index -1 when virtual threads are used (oracle/graal#7520).

This serializes all JS plugin execution onto one thread, which reduces parallelism under concurrent load.

Upstream dependency

What to monitor

  1. Truffle CHANGELOG for any mention of virtual thread support (GR-40931 was partial support in 24.1)
  2. GraalVM release notes for DefaultContextThreadLocal changes
  3. Whether truffle-api changes its fastGet() to handle virtual thread IDs correctly

How to test if upstream fix works

When a new GraalVM version ships with the fix:

  1. Update graalvm.version in root pom.xml to the new version

  2. Run the existing regression tests (they should still pass):

    ./mvnw test -pl polyglot -DskipUpdateLicense=true

    Key tests:

    • ContextQueueVirtualThreadTest — creates/enters/evals Context from virtual threads
    • ContextLifecycleTest.pooledContextWorksFromVirtualThread — pooled Context from virtual thread
    • ContextLifecycleTest.concurrentVirtualThreadsUseSameContextQueue — 20 concurrent virtual threads
  3. Disable the platform thread workaround and verify tests still pass:

    ./mvnw test -pl polyglot -DskipUpdateLicense=true \
      -Drestheart.polyglot.force-platform-threads=false

    All 28 tests must pass with force-platform-threads=false. If they do, Truffle's virtual thread support is working.

  4. Docker end-to-end test with the workaround disabled:

    docker run -d -p 8080:8080 \
      -e JAVA_TOOL_OPTIONS="-Drestheart.polyglot.force-platform-threads=false" \
      -v ./examples/js-plugin:/opt/restheart/plugins/js-plugin \
      softinstigate/restheart-snapshot:latest
    
    curl http://localhost:8080/hello
    # Expected: {"msg":"Hello World! from Italy with Love","note":"..."}

    Both services and interceptors must work.

  5. Performance test: compare JS plugin throughput with force-platform-threads=true (current) vs false (virtual threads). With false, concurrent JS requests should execute in parallel rather than serializing.

What to change when removing the workaround

If upstream fix is confirmed, these changes can be reverted/simplified:

File What to change
PolyglotThreadUtils.java Remove getPlatformExecutor(), isAlreadyOnPlatformThread(). Simplify onPlatformThread() to always call directly. Set FORCE_PLATFORM default to false
JSPlugin.java Simplify engine() to direct Engine.create() (no lazy init, no platform thread dispatch)
ContextQueue.java Constructor creates pool directly (no onPlatformThread). newContext() restores addBindings() call. Remove populatePool() helper
JSStringService.java Remove onPlatformThreadIO() wrapper. Restore Source.findLanguage() if useful
JSInterceptorFactory.java Same as JSStringService

Performance implications of the workaround

With force-platform-threads=true (current):

  • All JS plugin execution serializes on one "RH JS PLT" thread
  • Under concurrent load, JS latency grows linearly with concurrency
  • REST request handling (non-JS) continues on virtual threads — no impact

With force-platform-threads=false (after upstream fix):

  • JS plugin execution runs on virtual threads in parallel
  • Full concurrency restored
  • No platform thread overhead

Decision criteria

Remove the workaround when ALL of these are true:

  • GraalVM version ≥ X that fixes Virtual Thread support in Truffle/Native Image oracle/graal#7520
  • All 28 polyglot tests pass with force-platform-threads=false
  • Docker e2e test passes with force-platform-threads=false
  • No ArrayIndexOutOfBoundsException in DefaultContextThreadLocal.fastGet()
  • No performance regression in concurrent JS plugin execution

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions