next.js
e94513bf - fix(turbo-rcstr): make TaggedValue usable on wasm (#97577)

Commit
30 days ago
fix(turbo-rcstr): make TaggedValue usable on wasm (#97577) ### What? Makes `turbo-rcstr`'s tagged value work on wasm — and on any target whose pointer is narrower than the value — **without changing the representation or the inline capacity on any target**. `RcStr` stays 8 bytes wide everywhere, `MAX_INLINE_LEN` stays 7 everywhere, and `rcstr!` stays a `const`. ### Why? `TaggedValue` stored a `NonNull<()>` on 64-bit but a bare `NonZeroU64` when `target_pointer_width = "32"`. `rcstr!` expands to a `const`, so both constructors must be usable during const evaluation — and with integer storage `new_ptr` needs a pointer→integer cast, which const-eval forbids. Every `rcstr!` taking the static path failed to compile: ``` error[E0080]: unable to turn pointer into integer ``` Concretely, `cargo check -p turbopack-core --target wasm32-wasip1-threads` reported **4** of these before this change and **0** after. ### How? The fix rests on an asymmetry in const evaluation: | direction | const-eval | why | |---|---|---| | pointer → integer | **forbidden** | a pointer is an abstract (allocation, offset) pair; its numeric address doesn't exist until the linker assigns one | | integer → pointer | allowed | the result carries no provenance, which is fine as long as it is never dereferenced | 64-bit already only needs the legal directions: `new_ptr` is pointer→pointer, `new_tag` is integer→pointer. So rather than narrow the value on other targets, they now store a struct that keeps a **real pointer field**: ```rust #[repr(C, align(8))] struct RawLittle { ptr: NonNull<()>, pad: [u8; PAD] } ``` `new_ptr` stores the pointer as a pointer; `new_tag` transmutes an integer into the struct. Reading the value back as an integer (`get_ptr`, `get_value`, `tag_byte`) only happens at **run time**, where pointer→integer is perfectly legal. Three details are load-bearing, and each has a static assertion: - **`align(8)`** — a pointer field alone would align the struct to 4 on wasm32, and reading the value as a `u64` then traps with `RuntimeError: operation does not support unaligned accesses`. - **No padding** — the byte payload is sized to the pointer width, because padding bytes are uninitialised and would make the whole-value transmute in `new_tag` invalid. - **Endian-dependent field order** — the pointer's least-significant byte must land where the value's least-significant byte lives (offset 0 little-endian, last byte big-endian), since that is where the tag is read from. Both layouts are declared unconditionally so the big-endian assertion still compiles (and was verified to fail when deliberately broken) on a little-endian host. A union satisfies both constructors too, but unions carry no niche in rustc, so `Option<RcStr>` would grow to 16 bytes. The struct keeps it at 8 — also asserted. ### Testing - `turbo-rcstr`: **11 passed** on host, **10 passed / 1 ignored** on `wasm32-wasip1-threads` (the ignored one needs the static-`RcStr` registry, which depends on the link-section loader hook). - Round-trips every `rcstr!` length from 0 to 9 on both targets, covering both sides of the inline boundary and the static path. - Each of the new static assertions was verified to **fail** when deliberately broken, including the big-endian layout one. - `MAX_INLINE_LEN == 7` asserted on host and wasm. - The five `const … = rcstr!(…)` sites in the tree — including two `pub const`s in `turbopack-core` — are untouched and still compile as `const`. - `atom_size_128` still builds; its pre-existing const limitation is unchanged and out of scope. - `cargo fmt --check`, and clippy `-D warnings` for the host and for `wasm32-wasip1-threads`. Big-endian and 16-bit are compile-checked and assertion-protected, but not runtime-exercised — no such target is available here. <!-- NEXT_JS_LLM --> <!-- fleet b6d0486f-97c7-42a7-bdaf-3490774cdec3 --> Co-authored-by: vercel-fleet-prod[bot] <318278635+vercel-fleet-prod[bot]@users.noreply.github.com> Co-authored-by: Tobias Koppers <1365881+sokra@users.noreply.github.com> Co-authored-by: Luke Sandberg <210140+lukesandberg@users.noreply.github.com>
Author
Parents
Loading