Two GC-build sizing fixes for the same bug class — small GC builds
silently lost live roots under load, causing hash-table-ref to report
"missing key" on entries we just set.
1. HEAP_SIZE 0x100000 → 0x400000 (1 MB → 4 MB):
32 chunks × 1 MB capped the GC build at 32 MB. ecdsa
test-mod-inv-by at p=251 (n+1=9) OOM'd here even though gc was
reclaiming, because the fragmented free-list could not satisfy
the next n+1=9 sim batch. 4 MB × 32 chunks = 128 MB cap, still
well below the 512 MB ulimit -v envelope our asm tests run under.
2. GC_MARK_STACK_CAP 16K → 256K and gc_mark_stack .skip synced to
the constant:
gc_push_if_heap silently dropped tagged values when the mark
stack overflowed and claimed "correctness preserved (sweep won't
reclaim missed-roots, just leaks one cycle)" — but a dropped
value never reaches gc_mark_drain, so its header mark bit stays
clear and gc_sweep treats it as dead. ecdsa test-mod-inv-by at
p=251 walked ~17k tagged values in a single GC cycle and tipped
over the cap, after which live cons-cells started getting
reclaimed mid-simulate.
.skip 131072 was a hard-coded constant that didn't track the .equ,
so bumping the cap without resizing the buffer would smash adjacent
gc_mark_depth / gc_collections / gc_live_bytes; both lines moved
together. 256K × 8 = 2 MB of .bss, one HEAP_SIZE chunk's worth.
After fix: ecdsa test-mod-inv-by on lumbda-full inside QEMU guest
passes p ∈ {11, 13, 251} byte-equal to Python tier. Upstream asm
test.sh stays 158/158 GREEN. Discovered while working ecdsa task
#47, 2026-06-05.