Skip to content

[browser][coreCLR] R2R: IL splitter — shard trimmed assemblies by namespace #130523

Description

@pavelsavara

IL splitter: shard trimmed assemblies by namespace (build-time producer)

Part of #130524.

Status: draft / issue candidate · Area: WASM build tasks, trimming, packaging · Related: #130515 (shard consumer), #130522 (R2R over in-memory IL), D2

Goal

A build-time task that splits large, trimmed, IL-only application and library assemblies into smaller namespace-aligned shard assemblies, so later phases (precompilation, packaging, and eventually lazy download) can work at sub-assembly granularity. The unit of work and of download drops from a whole assembly to a namespace-sized shard. Secondary motivation: the same shard layout later enables lazy IL download (including under JSPI), but that consumer is separate (#130515).

Position in the pipeline

Runs after IL trimming (it operates on already-trimmed assemblies) and before precompilation and packaging. It emits the shards, a facade for the original assembly, and per-shard metadata, and it updates the assembly lists that downstream phases consume so they pick up the new layout automatically.

Direction

  • Shard by namespace; namespace is atomic. Pack multiple small namespaces into one shard to approach a configurable optimal size; a namespace larger than optimal becomes its own oversized shard. Never split a single namespace across shards.
  • Merge cyclic namespaces. Because assembly references cannot form cycles, group mutually-dependent namespaces together (by strongly-connected components) so no two shards reference each other cyclically.
  • Facade + type-forwarders. The original assembly identity is preserved as a facade that keeps the unmovable content — types with no namespace (global namespace), module-level and compiler-internal types, forced-keep types, and assembly-level metadata — and forwards every moved type to the shard that now holds it. External references to the original assembly keep resolving; resolution follows the forwarder to the shard. The forwarder therefore already names the shard to bring in, so the shard assembly name is the primary locate key and namespace is a secondary index.
  • Per-shard namespace metadata. Each shard records the namespace(s) it contains; this becomes part of the shard's asset entry in the boot configuration, so tooling and the runtime can associate a namespace with its shard (useful for grouping and pre-fetch).
  • Boot-config assets: IL shards vs. R2R-only shards. IL shards are ordinary assembly assets from the boot configuration's perspective. In addition, the task extends the boot-config (boot json) generation to emit a new R2R-only asset type for lazily-loaded R2R shards — distinct from ordinary assembly assets and from eagerly-loaded startup R2R — carrying the sizing/locating metadata the runtime needs to fetch and instantiate a shard on demand. The live hotness trigger ([browser][coreCLR] R2R: Interpreter live hotness trigger for on-demand R2R shard download #130516) consumes this R2R-only asset.
  • Update downstream lists. The task rewrites the relevant assembly item lists so subsequent phases consume the facade plus shards instead of the original assembly.
  • Incremental. Keyed on input assemblies; unchanged inputs are not re-split.
  • Excludes the core library. The base class library assembly is out of scope (too central and entangled, and precompiled/handled specially).

Scope

In: the splitting task; facade and type-forwarder emission; cyclic-namespace merging; size packing to the optimal-size parameter; per-shard namespace metadata; boot-config generation extended with the new R2R-only asset type (IL shards remain ordinary assembly assets); downstream assembly-list updates; incrementality; exclusion of the core library.

Out: the runtime consumer that loads shards on demand (#130515); JSPI; precompilation itself.

Success criteria

  • A trimmed app builds into a facade plus namespace shards near the target size; downstream phases consume them transparently; the app runs identically.
  • Each shard carries its namespace metadata into the boot configuration.
  • Rebuilds are incremental with respect to input assemblies.

Open questions

  • Reflection/identity fidelity: how much reflection over the original assembly must keep working (type-forwarders handle type resolution; some assembly-enumeration or exotic reflection may observe the split). Best-effort for apps; validate.
  • Naming and versioning of shard assemblies (uniqueness, signing) — the prototype may keep this simple.
  • Coupling that crosses namespaces (nested/partial types, generics referencing other namespaces) — ensure the strongly-connected-component grouping captures all of it.
  • Interaction with precompilation (D2 assembly-level shards) and with the R2R metadata reuse ([browser][coreCLR] R2R: R2R that loads against IL already in memory #130522) across the facade+shard layout.

Note

This issue was drafted with GitHub Copilot assistance.

Metadata

Metadata

Assignees

Labels

Type

No type

Fields

No fields configured for issues without a type.

Projects

Status
No status

Relationships

None yet

Development

No branches or pull requests

Issue actions