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.

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