commit d80b64a01e501747c6ebf914861cb0f32ff2dd72
parent 7f820b9f5375d42ba9882124c34606070da99310
Author: Ben Visness <bvisness@mozilla.com>
Date: Mon, 13 Oct 2025 12:29:31 +0000
Bug 1992014: Shrink stack maps down to 32 bits. r=rhunt
The stack map header was a full 8 bytes, and for seemingly no reason.
This patch shrinks the number of bits used for numMappedWords to
something more reasonable.
Differential Revision: https://phabricator.services.mozilla.com/D267109
Diffstat:
2 files changed, 38 insertions(+), 8 deletions(-)
diff --git a/js/src/jit-test/tests/wasm/gc/giant-frames.js b/js/src/jit-test/tests/wasm/gc/giant-frames.js
@@ -0,0 +1,14 @@
+// |jit-test| test-also=--setpref=wasm_test_serialization=true
+
+const { test } = wasmEvalText(`(module
+ (import "" "gc" (func $gc))
+ (func (export "test") (param ${"anyref ".repeat(1_000)}) (result anyref)
+ (local ${"anyref ".repeat(50_000 - 1_000)})
+
+ ${[...new Array(10_000).keys()].map(i => `local.get ${i}`).join("\n")}
+ call $gc
+ ${"drop\n".repeat(10_000 - 1)}
+ )
+)`, {"": {gc}}).exports;
+
+assertEq(test(5), 5);
diff --git a/js/src/wasm/WasmGC.h b/js/src/wasm/WasmGC.h
@@ -46,17 +46,24 @@ using ExitStubMapVector = Vector<bool, 32, SystemAllocPolicy>;
struct StackMapHeader {
explicit StackMapHeader(uint32_t numMappedWords = 0)
: numMappedWords(numMappedWords),
+#ifdef DEBUG
numExitStubWords(0),
+#endif
frameOffsetFromTop(0),
- hasDebugFrameWithLiveRefs(0) {}
+ hasDebugFrameWithLiveRefs(0) {
+ MOZ_ASSERT(numMappedWords <= maxMappedWords);
+ }
// The total number of stack words covered by the map ..
- static constexpr size_t MappedWordsBits = 30;
+ static constexpr size_t MappedWordsBits = 18;
+ static_assert(((1 << MappedWordsBits) - 1) * sizeof(void*) >= MaxFrameSize);
uint32_t numMappedWords : MappedWordsBits;
// .. of which this many are "exit stub" extras
static constexpr size_t ExitStubWordsBits = 6;
+#ifdef DEBUG
uint32_t numExitStubWords : ExitStubWordsBits;
+#endif
// Where is Frame* relative to the top? This is an offset in words. On every
// platform, FrameOffsetBits needs to be at least
@@ -71,8 +78,11 @@ struct StackMapHeader {
// gets a stackmap.
uint32_t hasDebugFrameWithLiveRefs : 1;
- WASM_CHECK_CACHEABLE_POD(numMappedWords, numExitStubWords, frameOffsetFromTop,
- hasDebugFrameWithLiveRefs);
+ WASM_CHECK_CACHEABLE_POD(numMappedWords,
+#ifdef DEBUG
+ numExitStubWords,
+#endif
+ frameOffsetFromTop, hasDebugFrameWithLiveRefs);
static constexpr uint32_t maxMappedWords = (1 << MappedWordsBits) - 1;
static constexpr uint32_t maxExitStubWords = (1 << ExitStubWordsBits) - 1;
@@ -93,9 +103,11 @@ struct StackMapHeader {
WASM_DECLARE_CACHEABLE_POD(StackMapHeader);
-// This is the expected size for the header
-static_assert(sizeof(StackMapHeader) == 8,
+#ifndef DEBUG
+// This is the expected size for the header, when in release builds
+static_assert(sizeof(StackMapHeader) == 4,
"wasm::StackMapHeader has unexpected size");
+#endif
// A StackMap is a bit-array containing numMappedWords*2 bits, two bits per
// word of stack. Index zero is for the lowest addressed word in the range.
@@ -182,10 +194,12 @@ struct StackMap final {
// Record the number of words in the map used as a wasm trap exit stub
// save area. See comment above.
void setExitStubWords(uint32_t nWords) {
- MOZ_ASSERT(header.numExitStubWords == 0);
MOZ_RELEASE_ASSERT(nWords <= header.maxExitStubWords);
+#ifdef DEBUG
+ MOZ_ASSERT(header.numExitStubWords == 0);
MOZ_ASSERT(nWords <= header.numMappedWords);
header.numExitStubWords = nWords;
+#endif
}
// Record the offset from the highest-addressed word of the map, that the
@@ -241,8 +255,10 @@ struct StackMap final {
}
};
+#ifndef DEBUG
// This is the expected size for a map that covers 32 or fewer words.
-static_assert(sizeof(StackMap) == 12, "wasm::StackMap has unexpected size");
+static_assert(sizeof(StackMap) == 8, "wasm::StackMap has unexpected size");
+#endif
// A map from an offset relative to the beginning of a code block to a StackMap
using StackMapHashMap =