Skip to content

Simplify single-threaded CoreCLR thread and static machinery - #135250

Merged
jkoritzinsky merged 23 commits into
mainfrom
dev/jkoritzinsky/single-thread-coreclr
Oct 14, 2026
Merged

jkoritzinsky merged 23 commits into
mainfrom
dev/jkoritzinsky/single-thread-coreclr

Conversation

@jkoritzinsky

Copy link
Copy Markdown
Member

CoreCLR builds without FEATURE_MULTITHREADING, including browser and WASI wasm, still carry machinery for multiple native threads and per-thread static storage. This change uses one native Thread and removes multithreading-only code and data from those builds.

Approach

  • Simplify native thread IDs and ThreadStore around the sole native thread. Preserve the DirectOnThreadLocalData native-thread pointer and managed unstarted Thread objects, whose start operations remain unsupported.
  • Treat managed thread statics as ordinary statics when multithreading is disabled. Update crossgen2 and ReadyToRun metadata to encode the single-threaded model, and exclude native thread-static machinery from these builds.
  • Split managed Thread implementation and startup helpers into multithreading/single-threading partials. Compile out native startup, utility-thread, priority, finalization, and helper FCalls; disable multicore JIT without multithreading.
  • Make cDAC thread-static data optional and update its contracts, descriptors, documentation, and tests.

Wasm retains its native GC-poll implementation. The managed polling fallback still performs a GC transition. The single-threaded spin-wait cap is zero; multithreaded behavior is retained.

Validation

  • Browser Debug and Release native runtime/CoreLib builds, including Release R2R CoreLib.
  • WASI Debug native runtime/CoreLib builds.
  • Windows Checked runtime/CoreLib builds and Thread tests: 55 passed, 4 skipped.
  • Browser Thread tests: 14 passed, 33 skipped.
  • cDAC unit tests: 3,240 passed during the descriptor changes.
  • NativeAOT CoreLib build to validate the shared Thread partial split.
  • Inspected built CoreLib metadata/IL to verify feature-specific methods and constants.

Release size comparison

Both sides use browser-wasm Release. Baseline: b9bafb9d14ef9e02a3940f97164b6b231d3595bb; changed source: 40327fe044c. Values are bytes. Brotli uses .NET BrotliStream with CompressionLevel.SmallestSize.

Artifact Format Baseline Changed Reduction
dotnet.native.wasm Uncompressed 4,553,180 4,505,348 47,832 (1.05%)
dotnet.native.wasm Brotli 1,324,802 1,313,959 10,843 (0.82%)
R2R System.Private.CoreLib.wasm Uncompressed 26,683,738 26,648,519 35,219 (0.13%)
R2R System.Private.CoreLib.wasm Brotli 4,194,214 4,189,499 4,715 (0.11%)

Combined reduction: 83,051 bytes uncompressed and 15,558 bytes Brotli-compressed. The CoreLib measurement is the R2R wasm artifact, not the IL DLL.

Note

This pull request description and code changes were generated with GitHub Copilot assistance.

jkoritzinsky and others added 6 commits October 2, 2026 13:51
…READING

On single-threaded CoreCLR targets (browser/WASI WASM), simplify the runtime
to model exactly one native Thread*:

- Managed thread ID is always 1; no ID dispenser is needed.
- ThreadStore holds a single thread entry.
- Thread statics are process-global, and the runtime publishes the main
  thread's managed object into Thread.s_currentThread at startup.
- Split Thread.CoreCLR.cs into shared, Multithreading, and SingleThreading
  partial files. The single-threaded file provides managed implementations
  (Yield, OS thread ID, priority, IsBackground, Join, etc.) so the
  corresponding QCalls are compiled out under !FEATURE_MULTITHREADING.
- Move WASI helpers out of Thread.Unix.cs into Thread.Wasi.cs and add
  Thread.SingleThreading.cs for CoreCLR single-threaded Join/Sleep.
- Skip GC-time priority boosting when multithreading is unavailable.
- Update DAC/cDAC and the Thread data contract docs accordingly.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
On builds without FEATURE_MULTITHREADING (browser/WASI wasm) there is only
one thread, so [ThreadStatic] fields are now laid out and accessed as
regular statics.

- VM: classify [ThreadStatic] fields as regular statics, hard-code the
  managed thread ID, and compile out the thread-static machinery (TLS index
  allocation, in-flight TLS data, the TLS index map, per-thread data arrays,
  GC root scanning, the GetThreadStaticsBy* QCalls, and the thread-static
  JIT helpers).
- CoreLib: compile out the thread-static StaticsHelpers and the wasm-only
  GetThreadStaticsBaseNative FCall.
- crossgen2: add --target-single-threaded, which lays out thread statics as
  regular statics, skips rooting the thread-static helpers, and sets a new
  READYTORUN_FLAG (0x2000, R2R minor version 30.1). The runtime rejects
  images whose flag does not match its threading model.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…EADING

Compile out Thread::m_ThreadLocalDataPtr and the TLS data descriptors (ThreadStaticsInfo, ThreadLocalData, InFlightTLSData, TLSIndex, NumberOfTlsOffsetsNotUsedInNoncollectibleArray) in single-threaded builds. The cDAC treats Thread.ThreadLocalDataPtr as optional and skips thread-static base lookups for types without thread-static fields. Update contract docs and add a unit test.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Conditionally build threadstatics.cpp and threadstatics.h using FEATURE_MULTITHREADING, and guard their VM consumers and MethodTable layouts.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Guard Thread priority declarations and definitions, initialize single-threaded managed priority to Normal, and guard the finalizer priority boost.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Split shared Thread startup logic into feature-specific partials, remove single-threaded native startup and finalization paths, disable multicore JIT without multithreading, and inline single-threaded helper behavior.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @agocke
See info in area-owners.md if you want to be subscribed.

@jkoritzinsky jkoritzinsky added the arch-wasm WebAssembly architecture label Oct 5, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

jkoritzinsky and others added 3 commits October 5, 2026 15:16
Adapt single-threaded helper rooting to the upstream managed-helper table and advance the single-threaded ReadyToRun format extension to version 31.1.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Remove unreachable dead-thread branches from Join and IsThreadPoolThread, and allocate managed IDs without synchronization while retaining the exhaustion guard.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Integrate shared Thread spin/yield helpers and platform OS thread IDs while retaining single-threaded stubs. Keep the WASM thread-static bootstrap FCall limited to multithreaded builds.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Preserve the feature-specific threading implementation while incorporating main's dead-code cleanup. Remove staticallocationhelpers.inl, which has no remaining consumers.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Comment thread src/coreclr/debug/daccess/reimpl.cpp
Comment thread src/coreclr/vm/comsynchronizable.cpp
Comment thread src/coreclr/vm/gcenv.ee.cpp
Comment thread src/coreclr/vm/methodtablebuilder.cpp Outdated
Comment thread src/coreclr/vm/threads.cpp
Comment thread src/coreclr/vm/threads.h
Comment thread src/coreclr/vm/threads.h
jkoritzinsky and others added 2 commits October 8, 2026 13:57
Make single-threaded Thread.PollGC a no-op and restrict PollGCInternal and its native QCall to FEATURE_MULTITHREADING.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Compile the native thread-exit helper only with FEATURE_MULTITHREADING, leaving single-threaded setup-failure and detach paths unchanged.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
jkoritzinsky and others added 2 commits October 9, 2026 10:53
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Remove the unused managed WASM GC polling fallback, simplify Thread properties and source selection, and ignore ThreadStatic attributes on RVA fields.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
jkoritzinsky and others added 2 commits October 9, 2026 14:04
Pass the single-threaded target setting in WASM layout tests and regenerate browser and WASI call helpers.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Gate the GC-to-EE thread creation contract and server/background GC on FEATURE_MULTITHREADING. Propagate the feature to NativeAOT and the GC sample, and guard background-only region diagnostics.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Comment thread src/coreclr/inc/jithelpers.h Outdated
Comment thread src/coreclr/inc/jithelpers.h Outdated
Comment thread src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj Outdated
Comment thread src/coreclr/vm/methodtablebuilder.cpp Outdated
Comment thread src/coreclr/vm/threads.cpp
Comment thread src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems Outdated
Comment thread src/coreclr/vm/threads.h Outdated
@jkotas

jkotas commented Oct 10, 2026

Copy link
Copy Markdown
Member

The test failures look related, e.g.:

Unhandled exception. System.PlatformNotSupportedException: Operation is not supported on this platform.
at System.Threading.Thread.JoinInternal(Int32 millisecondsTimeout)

Comment thread src/coreclr/gc/gcinterface.ee.h Outdated
jkoritzinsky and others added 2 commits October 10, 2026 22:36
This reverts commit e343bf7.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Simplify threading feature guards, make profile optimization a no-op without multithreading, and implement finite self-joins as timed sleeps.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Comment thread src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems Outdated
@jkotas

jkotas commented Oct 11, 2026 •

Copy link
Copy Markdown
Member

Revert "Exclude GC thread creation without multithreading"

I think the commit had a bunch of good changes like disabling BACKGROUND GC based of FEATURE_MULTITHREADING or not building ServerGC with FEATURE_MULTITHREADING . I would keep those.

@jkoritzinsky

Copy link
Copy Markdown
Member Author

/ba-g MSBuild-CMake leg broken by prexisting issue.

@jkoritzinsky
jkoritzinsky merged commit c5e1d63 into main Oct 14, 2026
182 of 188 checks passed
@jkoritzinsky
jkoritzinsky deleted the dev/jkoritzinsky/single-thread-coreclr branch October 14, 2026 17:34
@github-project-automation github-project-automation Bot moved this to Done in AppModel Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-VM-coreclr

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants