Skip to content

Reduce redundant work in CoreCLR WebAssembly type-loader code generation #134631

Closed

Description

@jkoritzinsky

Description

Inspecting Release browser-wasm code for ClassLoader::CreateTypeHandleForTypeDefThrowing and its callees revealed redundant loads, unnecessary RVA-resolution paths, repeated signature parsing, and exception-handling code caused by contracts that are not visible to the C++ optimizer. This issue tracks targeted, behavior-preserving improvements to those paths.

The baseline was built from dc614919f33834bb38d5020651864321a1de121b with:

.\build.cmd -os browser -c Release -subset clr+libs

Inspect artifacts\bin\browser-wasm.Release\corehost\dotnet.native.wasm, using its matching dotnet.native.js.symbols to identify functions. Function indices are build-specific.

Configuration

Windows x64 build host, browser-wasm target, Release configuration, Emscripten 6.0.2. The relevant native translation unit is compiled with -O3, WebAssembly exceptions, and -fno-strict-aliasing.

Regression?

Not established as a regression. This is an investigation of existing code-generation opportunities, not a demonstrated application-throughput or startup regression.

Data

Isolated source-copy probes, compiled with the original TU options and relinked with private archive copies, produced these function-body sizes:

Isolated change Function Before After
Use raw field offsets during placement HandleAutoLayout 2,300 B 2,119 B
Snapshot placement pointer/counts HandleAutoLayout 2,300 B 2,253 B
Compare the retained MethodImpl token PlaceMethodImpls 1,618 B 1,578 B
Cache the initial allocator pointer CreateTypeHandleForTypeDefThrowing 55,856 B 55,819 B
Group initial builder-state allocations CreateTypeHandleForTypeDefThrowing 55,856 B 55,732 B

The raw-offset probe also eliminated two unreachable-for-valid-instance-fields RVA paths and a 16-byte linear-memory stack frame. The placement loop's four-bucket region changed from 17 loads to five. The token comparison changed from five loads plus reconstruction arithmetic to two loads.

Separately, 19 enumeration-cleanup sites in the baseline entry function have catch-all/terminate wrappers around HENUMInternal::ClearEnum, whose nonthrowing implementation is not expressed through a C++ exception specification.

These are static code-generation measurements, not execution frequencies or speedups. The probes were independent; their savings must not be assumed additive. Functional regression and performance validation are required for the final changes.

Analysis

Planned changes, kept independently reviewable:

  1. Use FieldDesc::GetOffsetRaw() for loading-phase instance-field placement sentinels in HandleAutoLayout.
  2. Expose stable placement state and the initial stacking allocator through locals, without enabling strict aliasing globally.
  3. Use the token retained by bmtMDMethod::MethodSignature in bmtMethodImplInfo::IsBody, rather than reconstructing it from MethodDesc.
  4. Express audited nonthrowing enumeration cleanup consistently through HENUMInternal::ClearEnum and CStructArray::Clear; retain real cleanup and outer unwinding.
  5. Parse the outer signature header once on a local cursor in SigPointer::PeekValueTypeTokenClosed, preserving nonconsuming API behavior and malformed-signature handling.
  6. Group the initial builder records into one arena allocation while preserving initialization, alignment and lifetime; evaluate the allocation-space tradeoff.
  7. Locally express the nonreturning native-reader fatal path under HOST_WASM, inside the existing non-DAC branch. Preserve the host-native diagnostic rationale for not globally marking EEPolicy::HandleFatalError as nonreturning.

Reducing the entry function merely by restricting late inlining is not the objective: an isolated Binaryen inlining-budget experiment reduced that function's size but increased total module size.

Note

This issue was generated by GitHub Copilot from a local code-generation investigation.

Activity

  1. dotnet-policy-service commented on Sep 25, 2026

    @dotnet-policy-service
    Contributor

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

  2. self-assigned this
    on Sep 25, 2026
  3. dotnet-policy-service commented on Sep 25, 2026

    @dotnet-policy-service
    Contributor

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

  4. locked and limited conversation to collaborators on Oct 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

  • Status
    No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions