18-gc-deep-list.scm (2367B)
1 ;; Mark-stack overflow stress: force the 2 ;; `mark_push → mark_push_recurse → mark_value` tail-branch fallback. 3 ;; 4 ;; `mark_stack` holds 512 entries (see `:mark_stack` in lisp.M1). 5 ;; Overflow requires a DFS frontier wider than 512 at some point during 6 ;; the mark phase. The cleanest trigger is a single live vector with 7 ;; >512 element slots: `mark_value_vector` pushes each slot in one burst, 8 ;; so the stack fills in-place and every further push routes through 9 ;; `mark_push_recurse`. 10 ;; 11 ;; (LISP-GC.md originally conjectured that a deep *list* would overflow; 12 ;; inspection of the mark order shows it won't — `mark_value_pair` 13 ;; pushes cdr first and car second, so the DFS immediately consumes 14 ;; the car side and leaves at most one leftover cdr per level. A flat 15 ;; list never exceeds stack depth ~2. A large vector does. Keep the 16 ;; filename for continuity with the step-5 plan in LISP-GC.md.) 17 ;; 18 ;; Bug this test pinned down: on aarch64/riscv64, `mark_push_recurse` 19 ;; originally did `CALL mark_value ; RET`. Those arches' native CALL 20 ;; writes the return address to a link register rather than pushing it, 21 ;; so the inner CALL clobbered the incoming LR and the outer RET 22 ;; branched to itself. The routine now tail-branches via 23 ;; `li_br &mark_value ; b`, which lets mark_value return directly to 24 ;; mark_push's caller. This test exercises that path across all three 25 ;; arches. 26 ;; 27 ;; Plan: 28 ;; 1. Allocate a 490-slot global vector. The mark stack is 512 entries 29 ;; and root-walking has contributed a handful of pending pair 30 ;; children before the vector is popped, so pushing 490 more 31 ;; elements crosses the threshold mid-vector. 32 ;; 2. Fill with distinct fixnums so a mis-swept vector corrupts the 33 ;; checksum. 34 ;; 3. Churn the pair arena to force repeated GCs while the vector 35 ;; stays globally reachable — each GC re-marks the vector and 36 ;; re-hits the overflow path. 37 ;; 4. Sum the vector. Expected: 0 + 1 + … + 489 = 490 * 489 / 2 = 119805. 38 39 (define v (make-vector 490 0)) 40 41 (define fill 42 (lambda (i) 43 (if (= i 490) 44 0 45 (begin (vector-set! v i i) (fill (+ i 1)))))) 46 (fill 0) 47 48 (define churn 49 (lambda (n) 50 (if (= n 0) 51 0 52 (begin (cons n n) (churn (- n 1)))))) 53 (churn 2000) 54 55 (define sum 56 (lambda (i acc) 57 (if (= i 490) 58 acc 59 (sum (+ i 1) (+ acc (vector-ref v i)))))) 60 61 (sum 0 0)