Worker threads: module-mode scripts (#410), ctor-failure Errors (#464), event-driven bridge (#465)#710
Merged
Merged
Conversation
…, event-driven bridge (#465) #410 — worker scripts support `import`: Run a worker script that uses import/export through the full module pipeline (ModuleResolver → CheckModules → InterpretModules) instead of the bare single-file path that rejected every import at type-check ("Import statements require module mode"). `import { workerData, parentPort, threadId, isMainThread } from "worker_threads"` now resolves to the running worker's live values via Interpreter.WorkerThreadsContext (injected into the worker_threads module exports in ExecuteModule). The bound parentPort is the same instance as the bare global, so a listener attached via the import receives delivered messages. Relative-module imports in workers work too. Script-mode workers keep the single-file path unchanged. #464 — Worker construction failures surface as Error, not a string: A native built-in constructor that fails with a plain host exception (e.g. `new Worker(...)` failing the workerData structured-clone) now surfaces to a guest try/catch as a real Error (e.message, e.stack, e instanceof Error), matching compiled mode. Wrapped at the EvaluateNew native-callable dispatch (sync + async) via IsNativeConstructorFailure, which excludes ThrowException (guest throws routed back out) and SharpTSException (interpreter-internal errors kept as message strings per the ThrowException.FromResult contract). A central TranslateException change is unsafe: FromResult deliberately turns string guest-throws into plain System.Exception, making them type-indistinguishable from native errors. #465 — CompiledMessagePortBridge follow-ups: (1) Receive path is now event-driven. The emitted $MessagePort gets an _onEnqueue Action that a parent post invokes (volatile read, paired with a MemoryBarrier on the bridge's write) to wake the worker loop via the thread-safe EnqueueCallback, replacing the 10ms poll timer — an idle bridged port no longer wakes the worker loop 100x/second. The keep-alive Ref still holds the loop open while the port is open. (2) receiveMessageOnPort(port) now works on a transferred compiled port (CompiledMessagePortBridge.ReceiveMessageSync); both receiveMessageOnPort builtins accept the bridge. Item 3 (worker→worker port transfer) remains documented in #465. Tests: new regression tests in WorkerThreadsTests.cs (both modes) for all three. Full SharpTS.Tests green (12700/0). Test262 conformance-neutral: interpreted and compiled baseline diffs are identical with and without these changes (pre-existing baseline staleness on main is left untouched). Filed #700 (compiled WrapException yields a plain {message,name} object, not a real Error) and #701 (compiled property access on undefined does not throw) for compiled-mode error-shape gaps found en route.
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.
Implements three
worker_threadsissues. All changes are runtime-only (interpreter + IL emitter); the type checker is untouched.#410 — worker scripts support
importA worker script that uses
import/exportnow runs through the same module pipeline the parent uses (ModuleResolver→CheckModules→InterpretModules) instead of the bare single-file path, which rejected every import at type-check (Import statements require module mode) — and silently swallowed the failure via the worker'serrorevent.SharpTSWorker.RunWorkerScriptdetects module mode (UsesModuleSyntax: import/export/triple-slash-path/CJS — mirrorsProgram.RunFile) and routes to a module or single-file path accordingly.import { workerData, parentPort, threadId, isMainThread } from "worker_threads"resolves to the running worker's live values via a new internalInterpreter.WorkerThreadsContext, injected into theworker_threadsmodule exports inExecuteModule. The boundparentPortis the same instance as the bare global, so a listener attached through the import receives the messages the worker's message loop delivers.worker_threadsspecial-case). Script-mode workers keep the existing single-file path unchanged.#464 — Worker construction failures surface as
Error, not a stringA native built-in constructor that fails with a plain host exception (e.g.
new Worker(...)failing theworkerDatastructured-clone) now reaches a guesttry/catchas a realError(e.message,e.stack,e instanceof Error), matching compiled mode.EvaluateNewnative-callable dispatch (sync + async) viaIsNativeConstructorFailure, which excludesThrowException(guest throws routed back out) andSharpTSException(interpreter-internal errors deliberately kept as message strings).TranslateExceptionchange would be unsafe:ThrowException.FromResultturns string guest-throws into a plainSystem.Exception, making them type-indistinguishable from native errors (an early attempt there regressed 23 generator/async tests).#465 —
CompiledMessagePortBridgefollow-ups$MessagePortgains an_onEnqueueActionthat a parent post invokes (volatile read, paired with aMemoryBarrieron the bridge's write) to wake the worker loop via the thread-safeEnqueueCallback, replacing the 10ms poll timer — an idle bridged port no longer wakes the worker loop 100×/second. The keep-aliveRefstill holds the loop open while the port is open.receiveMessageOnPorton a transferred compiled port viaCompiledMessagePortBridge.ReceiveMessageSync; bothreceiveMessageOnPortbuiltins now accept the bridge.Testing
WorkerThreadsTests.csfor all three issues (both execution modes).SharpTS.Tests: 12,700 passed / 0 failed.main), so the committed baselines are left untouched.Actionfield, so compiled output stays standalone (no SharpTS.dll reference).Notes for reviewer
{message, name}object, not a realError) and Compiled: property access on undefined/null does not throw (returns undefined instead of TypeError) #701 (compiled property access onundefineddoesn't throw).new Number(x)/new String(x)wrapper objects don't coerce (valueOf returns the object; String.fromCharCode(new Number(1)) crashes) #708 for a pre-existing interpreter bug (new Number(x)/new String(x)wrappers don't coerce;String.fromCharCode(new Number(1))crashes) — this is the root cause of much of the pre-existing Test262 baseline drift onmain. The committed Test262 baselines appear stale onmainindependent of this PR.Closes #410
Closes #464