072-cg-snapshot-rewind.scm (1838B)
1 ;; tests/cc-cg/72-cg-snapshot-rewind.scm — cg-snapshot / cg-rewind 2 ;; primitives. The pair underpins parse-side `sizeof EXPR` (no-eval): 3 ;; the parser learns the expression's type without retaining the code 4 ;; emission or vstack push the operand parse produced. 5 ;; 6 ;; Models, in C terms: 7 ;; int x = 5; 8 ;; /* "speculative" load+inc+store sequence, then rewound */ 9 ;; /* speculative pushes onto vstack, then rewound */ 10 ;; return x; /* must still be 5 */ 11 ;; 12 ;; Concretely: 13 ;; 1. x = 5 (committed). 14 ;; 2. cg-snapshot — capture vstack/fn-buf/frame-hi state. 15 ;; 3. Emit a postinc on x (loads, stores x+1) AND push extra opnds 16 ;; onto the vstack. 17 ;; 4. cg-rewind — discard the emitted bytes and the vstack pushes. 18 ;; 5. return x — must observe pre-snapshot value, exit 5. 19 ;; 20 ;; If snapshot/rewind fail to undo the fn-buf bytes, x is incremented 21 ;; to 6 and we'd exit 6 instead of 5. If the vstack rewind fails, the 22 ;; final cg-return sees the wrong opnd on top. 23 24 (let ((cg (cg-init))) 25 (cg-fn-begin cg "main" '() %t-i32) 26 (let* ((off-x (cg-alloc-slot cg 4 4)) 27 (sym-x (%sym "x" 'var 'auto %t-i32 off-x))) 28 ;; x = 5 (committed) 29 (cg-push-sym cg sym-x) 30 (cg-push-imm cg %t-i32 5) 31 (cg-assign cg) (cg-pop cg) 32 ;; snapshot: capture state before the speculative work 33 (let ((tag (cg-snapshot cg))) 34 ;; speculative emission: postinc on x — would make x = 6 35 (cg-push-sym cg sym-x) 36 (cg-postinc cg) 37 (cg-pop cg) 38 ;; speculative vstack push, never assigned: an extra imm 39 (cg-push-imm cg %t-i32 999) 40 ;; rewind: discard the postinc bytes AND the speculative pushes 41 (cg-rewind cg tag)) 42 ;; return x — should still be 5 43 (cg-push-sym cg sym-x) (cg-load cg) 44 (cg-return cg)) 45 (cg-fn-end cg) 46 (write-bv-fd 1 (cg-finish cg)))