[wasm][R2R] crossgen2/RyuJIT emits a single wasm function exceeding V8's max function size limit
- Dominant language
- C#
- Stars
- 18.3k
- Forks
- 5.6k
- PR merge metrics
- PR metrics pending
Description
## Description
When building an application R2R (ReadyToRun) for `browser-wasm`, crossgen2/RyuJIT can emit a single wasm function whose body exceeds V8's maximum function size, and the module fails to instantiate:
```
WebAssembly.instantiateStreaming(): size 9524947 > maximum function size 7654321 @+3555152
```
V8 enforces a hard per-function body-size limit of `7654321` bytes (`kV8MaxWasmFunctionSize`). A single R2R-compiled method whose native (wasm) code exceeds that limit makes the entire `.wasm` module unloadable — it is not a graceful degradation, the whole assembly fails to instantiate.
The fix belongs in RyuJIT/crossgen2: it should avoid producing a wasm function over the limit (e.g. by splitting the generated code, falling back to a non-R2R / interpreter path for that method, or otherwise keeping each emitted wasm function under `kV8MaxWasmFunctionSize`).
## Concrete repro / context
Observed while R2R-compiling **MudBlazor.Docs** for `browser-wasm`.
The offending function is the static constructor of the partial class **`MudBlazor.Docs.Models.ApiDocumentation`**:
- Function: `MudBlazor_Docs_MudBlazor_Docs_Models_ApiDocumentation__cctor`
- Body size: **9,524,948 bytes** (`> 7,654,321`)
- Offset in the module: `0x363f57`
- The next-largest function in the same module is only ~66 KB, so this `.cctor` is a massive outlier.
`ApiDocumentation` is a `static partial class`. The hand-written part declares empty dictionaries (`Types`, `Properties`, `Methods`, `Fields`, `Events`), and MudBlazor's docs generator emits **additional generated partial declarations** of the same class that populate those dictionaries with thousands of entries (full XML doc strings, parameters, etc.). The C# compiler merges all static field initializers and static-init code from every partial declaration into a **single** synthesized static constructor `ApiDocumentation..cctor`, which R2R then compiles into one enormous wasm function that blows past V8's limit.
Source (hand-written partial, dictionaries initialized empty):
- https://github.com/MudBlazor/MudBlazor/blob/dev/src/MudBlazor.Docs/Models/Generated/ApiDocumentation.cs
This pattern (large generated types with a huge `.cctor`, JSON/serializer source-generator contexts, big generated tables, etc.) is common enough that R2R on wasm needs to handle oversized methods rather than emit an unloadable module.
## Expected behavior
R2R for `browser-wasm` should never emit a wasm function larger than `kV8MaxWasmFunctionSize` (`7654321`). When a method would exceed the limit, RyuJIT/crossgen2 should keep it under the cap (split/outline) or skip R2R for that method and leave it to the runtime interpreter/JIT — without failing module instantiation.
## Notes
- V8 limit constant: `kV8MaxWasmFunctionSize = 7654321`.
- Related tracking issue: #130524 ([browser][coreCLR] R2R on WebAssembly (R1) — tracking).
- Sibling wasm/R2R crossgen2 limit issue: #132855 (function types exceeding the 1000-parameter wasm limit).
Contributor guide
Assessment
This issue has not been assessed yet.