commit e43969a17afb5202cc1ec0f5752c34350a6f4475
parent ca3b28606cf90cb1a43bfc82ba92858c587971d2
Author: Ryan Sepassi <rsepassi@gmail.com>
Date: Tue, 28 Apr 2026 08:53:56 -0700
cc: CC-SCRATCH Phase 1 pre-refactors
Six semantically-null refactors that shrink the cross-decl boundary
contract ahead of Phase 3's promote walkers:
- 1.1 Drop ps-typedefs; typedef? derives from scope-lookup.
- 1.2 Drop cg-globals; cg-emit-global/extern still emit bytes.
- 1.3 Eliminate ctype mutation in parse-enum-spec and the array-init
fixup path. Only mutation left is complete-agg! for forward
struct/union completion. parse-init-global now returns
(values pieces final-ty); handle-decl defers sm construction for
inferred-length arrays so sym-type captures the resolved length.
- 1.4 Introduce shared world record (scope/tags/str-pool); pstate
and cg both reference one. Shim accessors keep callers unchanged.
- 1.5 Drop the bytevector-append "cc__" precompute in handle-decl
and parse-fn-body. sym-slot becomes #f for fn / global var;
%const-init-piece mangles on demand via %cg-mangle-global.
- 1.6 Document sym immutability on the record definition.
Tests on aarch64: cc-util 14/14, cc-lex 16/16, cc-pp 31/31,
cc-cg 52/52, cc 143/143, scheme1 111/111.
Diffstat:
| M | cc/cc.scm | | | 275 | ++++++++++++++++++++++++++++++++++++++++++++++--------------------------------- |
1 file changed, 161 insertions(+), 114 deletions(-)
diff --git a/cc/cc.scm b/cc/cc.scm
@@ -319,11 +319,9 @@
;; --------------------------------------------------------------------
;; ctype — C type.
;;
-;; Fields that mutate over a ctype's lifetime:
-;; size and align — set to -1/-1 on forward struct/union decl,
-;; fixed when the type is completed.
-;; ext — same; struct/union ext changes shape when
-;; the body is parsed.
+;; size/align/ext mutate only on forward struct/union completion (see
+;; complete-agg!). Every other ctype is constructed in its final shape
+;; and treated as immutable thereafter.
;; --------------------------------------------------------------------
(define-record-type ctype
(%ctype kind size align ext)
@@ -357,6 +355,12 @@
;; var) from a definition (fn body, var with initializer, tentative def
;; without `extern`). scope-bind! merges compatible decls; only two
;; defined? syms with the same name fire a redefinition error.
+;;
+;; sym is immutable — no `sym-*-set!` accessor exists. scope-bind!'s
+;; merge logic constructs a fresh sym rather than mutating in place.
+;; Promotion (Phase 3 of CC-SCRATCH) relies on this: a deep-copied
+;; sym in main heap is guaranteed structurally identical to its
+;; scratch original.
;; --------------------------------------------------------------------
(define-record-type sym
(%sym name kind storage type slot defined?)
@@ -365,7 +369,8 @@
(kind sym-kind) ; symbol from §1.7
(storage sym-storage) ; symbol from §1.8 or #f
(type sym-type) ; ctype
- (slot sym-slot) ; fixnum | bv | #f, per kind
+ (slot sym-slot) ; fixnum (auto local / param / enum-const value)
+ ; | #f (fn / global var / typedef)
(defined? sym-defined?)) ; #t = definition, #f = decl-only
;; --------------------------------------------------------------------
@@ -402,6 +407,23 @@
(labels fn-ctx-labels fn-ctx-labels-set!))
;; --------------------------------------------------------------------
+;; world — cross-decl persistent parser/cg state. The same world record
+;; is shared by pstate and cg so its three slots — scope (var/typedef
+;; bindings), tags (struct/union/enum tags), str-pool (interned string
+;; literals) — can be reasoned about as one boundary contract.
+;; Phase 3's promote walkers will deep-copy from this single root.
+;; --------------------------------------------------------------------
+(define-record-type world
+ (%world scope tags str-pool)
+ world?
+ (scope world-scope world-scope-set!)
+ (tags world-tags world-tags-set!)
+ (str-pool world-str-pool world-str-pool-set!))
+
+(define (make-world)
+ (%world (list '()) (list '()) '()))
+
+;; --------------------------------------------------------------------
;; pstate — parser state. Owned by parse.scm; read-only to cg.
;; --------------------------------------------------------------------
;; iter holds a tok-iter (typically a pp-iter chained over a lex-iter).
@@ -409,15 +431,18 @@
;; so the parser pulls one token at a time, with no full materialized
;; token list.
(define-record-type pstate
- (%pstate iter scope tags loops fn-ctx typedefs cg)
+ (%pstate iter world loops fn-ctx cg)
pstate?
- (iter ps-iter ps-iter-set!)
- (scope ps-scope ps-scope-set!)
- (tags ps-tags ps-tags-set!)
- (loops ps-loops ps-loops-set!)
- (fn-ctx ps-fn-ctx ps-fn-ctx-set!)
- (typedefs ps-typedefs ps-typedefs-set!)
- (cg ps-cg))
+ (iter ps-iter ps-iter-set!)
+ (world ps-world)
+ (loops ps-loops ps-loops-set!)
+ (fn-ctx ps-fn-ctx ps-fn-ctx-set!)
+ (cg ps-cg))
+
+(define (ps-scope ps) (world-scope (ps-world ps)))
+(define (ps-scope-set! ps v) (world-scope-set! (ps-world ps) v))
+(define (ps-tags ps) (world-tags (ps-world ps)))
+(define (ps-tags-set! ps v) (world-tags-set! (ps-world ps) v))
;; --------------------------------------------------------------------
;; cg — codegen state. Owned by cg.scm.
@@ -432,17 +457,12 @@
;; in-fn? discriminates "currently inside a function body" so
;; %cg-emit-buf can route emits to fn-buf during the body and cg-text
;; outside it (entry stub, etc.).
-;; cg-globals: user-visible globals only (cg-emit-global / cg-emit-extern).
-;; Stable except when user code adds a global — which is exactly what the
-;; parse-fn-body rewind-safety check probes.
;;
;; cg-fn-meta: transient per-function state (fn-name, ret-slot, ret-type,
;; vararg-first-slot, indirect-slots, switch-case lists, ...). Reset on
-;; cg-fn-begin/v; reads via %cg-fn-get / writes via %cg-fn-set!. Kept
-;; out of cg-globals so rewind-safety checks on cg-globals aren't
-;; tripped by every fn-begin.
+;; cg-fn-begin/v; reads via %cg-fn-get / writes via %cg-fn-set!.
(define-record-type cg
- (%cg text data bss vstack frame-hi label-ctr str-pool globals fn-meta fn-buf prologue-buf max-outgoing in-fn?)
+ (%cg text data bss vstack frame-hi label-ctr world fn-meta fn-buf prologue-buf max-outgoing in-fn?)
cg?
(text cg-text)
(data cg-data)
@@ -450,14 +470,16 @@
(vstack cg-vstack cg-vstack-set!)
(frame-hi cg-frame-hi cg-frame-hi-set!)
(label-ctr cg-label-ctr cg-label-ctr-set!)
- (str-pool cg-str-pool cg-str-pool-set!)
- (globals cg-globals cg-globals-set!)
+ (world cg-world)
(fn-meta cg-fn-meta cg-fn-meta-set!)
(fn-buf cg-fn-buf)
(prologue-buf cg-prologue-buf)
(max-outgoing cg-max-outgoing cg-max-outgoing-set!)
(in-fn? cg-in-fn? cg-in-fn?-set!))
+(define (cg-str-pool cg) (world-str-pool (cg-world cg)))
+(define (cg-str-pool-set! cg v) (world-str-pool-set! (cg-world cg) v))
+
;; --------------------------------------------------------------------
;; Symbol alphabets — canonical alists.
;; --------------------------------------------------------------------
@@ -2557,9 +2579,7 @@
(define (%n n) (number->string n 10))
;; Per-fn metadata (name, ret-slot, ret-type, switch-case lists, ...)
-;; lives on cg-fn-meta, reset at every cg-fn-begin/v. Keeping it off
-;; cg-globals means cg-globals only mutates when the user emits a real
-;; global, which is what parse-fn-body's rewind-safety check needs.
+;; lives on cg-fn-meta, reset at every cg-fn-begin/v.
(define (%cg-fn-set! cg key val)
(cg-fn-meta-set! cg (alist-update key (lambda (_) val) (cg-fn-meta cg))))
@@ -2788,8 +2808,7 @@
'() ; vstack
0 ; frame-hi
0 ; label-ctr
- '() ; str-pool
- '() ; globals
+ (make-world) ; world (shared with pstate)
'() ; fn-meta
(make-buf/cap %BUF-CAP-FN) ; fn-buf (reused per fn)
(make-buf/cap %BUF-CAP-PROLOGUE) ; prologue-buf (reused per fn)
@@ -3916,12 +3935,9 @@
(zero-loop (- rem 8) (cons "$(0)\n" acc)))
(else
(zero-loop (- rem 1) (cons "!(0)\n" acc))))))))))
- (cg-globals-set! cg (alist-set (sym-name sym) sym (cg-globals cg)))
0))
-(define (cg-emit-extern cg sym)
- (cg-globals-set! cg (alist-set (sym-name sym) sym (cg-globals cg)))
- 0)
+(define (cg-emit-extern cg sym) 0)
(define (cg-intern-string cg bv-content)
(let ((p (alist-ref bv-content (cg-str-pool cg))))
@@ -3949,7 +3965,7 @@
;; cc/parse.scm — recursive-descent + Pratt parser. Minimal scheme1.
(define (make-pstate iter cg)
- (%pstate iter (list '()) (list '()) '() #f '() cg))
+ (%pstate iter (cg-world cg) '() #f cg))
(define (peek ps) (iter-peek (ps-iter ps)))
(define (peek2 ps) (iter-peek2 (ps-iter ps)))
@@ -4050,10 +4066,9 @@
(cond ((null? f) #f)
(else (let ((v (alist-ref n (car f))))
(if v v (loop (cdr f))))))))
-(define (typedef-add! ps n)
- (ps-typedefs-set! ps (alist-set n #t (ps-typedefs ps))))
(define (typedef? ps n)
- (if (alist-ref n (ps-typedefs ps)) #t #f))
+ (let ((sm (scope-lookup ps n)))
+ (and sm (eq? (sym-kind sm) 'typedef))))
(define (%mk-ptr p) (%ctype 'ptr 8 8 p))
(define (%mk-arr e n)
@@ -4110,11 +4125,10 @@
((at-kw? ps 'enum)
(loop sto sn lg (parse-enum-spec ps) #t))
((and (not b) (eq? (tok-kind t) 'IDENT)
- (typedef? ps (tok-value t)))
+ (let ((sm (scope-lookup ps (tok-value t))))
+ (and sm (eq? (sym-kind sm) 'typedef))))
(let* ((tk (advance ps)) (sm (scope-lookup ps (tok-value tk))))
- (if (and sm (eq? (sym-kind sm) 'typedef))
- (loop sto sn lg (sym-type sm) #t)
- (die (tok-loc tk) "typedef no sym" (tok-value tk)))))
+ (loop sto sn lg (sym-type sm) #t)))
(else
(cond ((not saw) (die (tok-loc t) "expected decl-spec"
(tok-value t)))
@@ -4217,24 +4231,28 @@
(cond
((at-punct? ps 'lbrace)
(advance ps)
- (let ((ct (%ctype 'enum 4 4 (list tag '()))))
- (if tag (tag-bind! ps tag ct))
- (let loop ((vs '()) (nv 0))
- (cond
- ((at-punct? ps 'rbrace)
- (advance ps)
- (ctype-ext-set! ct (list tag (reverse vs))) ct)
- (else
- (let* ((nt (advance ps)) (nm (tok-value nt))
- (val (cond ((at-punct? ps 'assign)
- (advance ps) (parse-const-int ps))
- (else nv))))
- (scope-bind! ps nm
- (%sym nm 'enum-const #f %t-i32 val #t))
- (cond ((at-punct? ps 'comma) (advance ps))
- ((at-punct? ps 'rbrace) #t)
- (else (die (tok-loc (peek ps)) "enum")))
- (loop (cons (cons nm val) vs) (+ val 1))))))))
+ ;; Parse all members first, then construct the enum ctype with
+ ;; the final members list and tag-bind it. Members reference
+ ;; earlier enum-consts via scope-lookup (not via the enum tag),
+ ;; so deferring tag-bind! is safe.
+ (let loop ((vs '()) (nv 0))
+ (cond
+ ((at-punct? ps 'rbrace)
+ (advance ps)
+ (let ((ct (%ctype 'enum 4 4 (list tag (reverse vs)))))
+ (if tag (tag-bind! ps tag ct))
+ ct))
+ (else
+ (let* ((nt (advance ps)) (nm (tok-value nt))
+ (val (cond ((at-punct? ps 'assign)
+ (advance ps) (parse-const-int ps))
+ (else nv))))
+ (scope-bind! ps nm
+ (%sym nm 'enum-const #f %t-i32 val #t))
+ (cond ((at-punct? ps 'comma) (advance ps))
+ ((at-punct? ps 'rbrace) #t)
+ (else (die (tok-loc (peek ps)) "enum")))
+ (loop (cons (cons nm val) vs) (+ val 1)))))))
(tag (let ((e (tag-lookup ps tag)))
(cond (e e)
(else (let ((c (%ctype 'enum 4 4 (list tag '()))))
@@ -4719,12 +4737,10 @@
(cond
((not n) (die #f "no name"))
((eq? sto 'typedef)
- (typedef-add! ps n)
(scope-bind! ps n (%sym n 'typedef #f ty #f #t)))
((ctype-is-fn? ty)
(scope-bind! ps n
- (%sym n 'fn (or sto 'extern) ty
- (bytevector-append "cc__" n) #f)))
+ (%sym n 'fn (or sto 'extern) ty #f #f)))
;; §I: block-scope `static` routes to a global with a name mangled
;; on the enclosing function so two functions can each have their
;; own `static int n;` without colliding. The sym's NAME holds the
@@ -4733,15 +4749,20 @@
;; remains the original identifier for source-level lookup.
((and (eq? sto 'static) (ps-fn-ctx ps))
(let* ((fname (fn-ctx-name (ps-fn-ctx ps)))
- (mangled (bytevector-append fname "__" n))
- (sm (%sym mangled 'var 'static ty
- (bytevector-append "cc__" mangled) #t)))
- (scope-bind! ps n sm)
+ (mangled (bytevector-append fname "__" n)))
(cond
((at-punct? ps 'assign)
(advance ps)
- (cg-emit-global (ps-cg ps) sm (parse-init-global ps ty)))
- (else (cg-emit-global (ps-cg ps) sm #f)))))
+ ;; Parse init first so an inferred-length array picks up its
+ ;; resolved type before sm is constructed (sym is immutable).
+ (let-values (((pieces ty2) (parse-init-global ps ty)))
+ (let ((sm (%sym mangled 'var 'static ty2 #f #t)))
+ (scope-bind! ps n sm)
+ (cg-emit-global (ps-cg ps) sm pieces))))
+ (else
+ (let ((sm (%sym mangled 'var 'static ty #f #t)))
+ (scope-bind! ps n sm)
+ (cg-emit-global (ps-cg ps) sm #f))))))
(else
(cond
((not (ps-fn-ctx ps))
@@ -4749,18 +4770,20 @@
;; (initializer present, or no `extern` keyword) is a definition
;; or tentative def, so the merge logic in scope-bind! treats it
;; as the authoritative binding.
- (let* ((init? (at-punct? ps 'assign))
- (def? (or init? (not (eq? sto 'extern))))
- (sm (%sym n 'var (or sto 'extern) ty
- (bytevector-append "cc__" n) def?)))
- (scope-bind! ps n sm)
- (cond
- (init?
- (advance ps)
- (cg-emit-global (ps-cg ps) sm
- (parse-init-global ps ty)))
- ((eq? sto 'extern) (cg-emit-extern (ps-cg ps) sm))
- (else (cg-emit-global (ps-cg ps) sm #f)))))
+ (cond
+ ((at-punct? ps 'assign)
+ (advance ps)
+ (let-values (((pieces ty2) (parse-init-global ps ty)))
+ (let ((sm (%sym n 'var (or sto 'extern) ty2 #f #t)))
+ (scope-bind! ps n sm)
+ (cg-emit-global (ps-cg ps) sm pieces))))
+ (else
+ (let* ((def? (not (eq? sto 'extern)))
+ (sm (%sym n 'var (or sto 'extern) ty #f def?)))
+ (scope-bind! ps n sm)
+ (cond
+ ((eq? sto 'extern) (cg-emit-extern (ps-cg ps) sm))
+ (else (cg-emit-global (ps-cg ps) sm #f)))))))
(else
(let* ((sz (max (ctype-size ty) 1))
(al (max (ctype-align ty) 1))
@@ -4843,7 +4866,7 @@
(and (eq? (sym-kind sm) 'var)
(or (eq? (sym-storage sm) 'static)
(eq? (sym-storage sm) 'extern))))
- (cons 'label-ref (sym-slot sm)))
+ (cons 'label-ref (%cg-mangle-global (sym-name sm))))
(else
(die (tok-loc it) "init: &x must reference a global"
(tok-value it))))))
@@ -4860,7 +4883,7 @@
(eq? (sym-storage sm) 'extern)))))))
(advance ps)
(let ((sm (scope-lookup ps (tok-value t))))
- (cons 'label-ref (sym-slot sm))))
+ (cons 'label-ref (%cg-mangle-global (sym-name sm)))))
;; Plain string literal as char* initializer.
((eq? (tok-kind t) 'STR)
(advance ps)
@@ -4879,11 +4902,12 @@
;; Declared array length (-1 = inferred).
(cond ((eq? (ctype-kind ty) 'arr) (cdr (ctype-ext ty))) (else -1)))
-(define (%init-fix-array-size! ty count)
- ;; Patch an inferred-length array to `count`.
- (let ((elem (car (ctype-ext ty))))
- (ctype-ext-set! ty (cons elem count))
- (ctype-size-set! ty (* count (ctype-size elem)))))
+(define (%init-fixed-arr-type ty count)
+ ;; Construct a fresh array ctype with the inferred length resolved
+ ;; to `count`. Pure — does not mutate `ty`. For non-inferred or
+ ;; non-array `ty`, callers should detect this themselves and just
+ ;; pass `ty` through.
+ (%mk-arr (car (ctype-ext ty)) count))
(define (%init-struct-fields ty)
;; Return ((name-bv ctype offset) ...) for a struct/union ctype.
@@ -4900,6 +4924,9 @@
(make-bytevector nbytes 0))
;; ----- Global initializers ---------------------------------------------
+;; Returns (values pieces final-ty). For inferred-length array `ty`,
+;; final-ty is a freshly-built array ctype with the resolved length;
+;; otherwise final-ty is `ty` unchanged.
(define (parse-init-global ps ty)
(pmatch (peek ps)
;; String literal initializer for char[]
@@ -4910,12 +4937,14 @@
(advance ps)
(let* ((slen (bytevector-length s))
(decl (cdr (ctype-ext ty)))
- (final (cond ((< decl 0) (+ slen 1)) (else decl))))
- (cond ((< decl 0) (%init-fix-array-size! ty final)))
+ (final (cond ((< decl 0) (+ slen 1)) (else decl)))
+ (final-ty (cond ((< decl 0) (%init-fixed-arr-type ty final))
+ (else ty))))
(let ((bv (make-bytevector final 0)))
(let loop ((i 0))
(cond
- ((or (= i slen) (>= i final)) (list bv))
+ ((or (= i slen) (>= i final))
+ (values (list bv) final-ty))
(else
(bytevector-u8-set! bv i (bytevector-u8-ref s i))
(loop (+ i 1))))))))
@@ -4924,18 +4953,27 @@
(advance ps)
(cond
((eq? (ctype-kind ty) 'arr)
- (%parse-init-array-list ps ty))
+ (let-values (((pieces count) (%parse-init-array-list ps ty)))
+ (let* ((decl (%init-array-decl-len ty))
+ (final-ty (cond ((< decl 0)
+ (%init-fixed-arr-type ty count))
+ (else ty))))
+ (values pieces final-ty))))
((or (eq? (ctype-kind ty) 'struct) (eq? (ctype-kind ty) 'union))
- (%parse-init-struct-list ps ty))
+ (values (%parse-init-struct-list ps ty) ty))
(else
;; Brace-wrapped scalar: { expr }
(let ((piece (%const-init-piece ps ty)))
(cond ((at-punct? ps 'comma) (advance ps)))
(expect-punct ps 'rbrace)
- (list piece)))))
+ (values (list piece) ty)))))
;; Bare scalar initializer
- (else (list (%const-init-piece ps ty)))))
+ (else (values (list (%const-init-piece ps ty)) ty))))
+;; Returns (values pieces count). `count` is the number of element
+;; initializers actually consumed (used by parse-init-global to resolve
+;; an inferred top-level length). C99 forbids inferred length in
+;; nested array elements, so recursive callers ignore `count`.
(define (%parse-init-array-list ps ty)
;; Element-list array initializer; assumes `{` already consumed.
(let* ((elem (%init-array-elem-type ty))
@@ -4945,14 +4983,15 @@
(cond
((at-punct? ps 'rbrace)
(advance ps)
- (cond ((< decl 0) (%init-fix-array-size! ty count)))
;; Pad to declared length if longer than count.
(let* ((final (cond ((< decl 0) count) (else decl)))
(pad (- final count)))
- (cond
- ((> pad 0)
- (reverse (cons (%pad-piece (* pad esize)) acc)))
- (else (reverse acc)))))
+ (values
+ (cond
+ ((> pad 0)
+ (reverse (cons (%pad-piece (* pad esize)) acc)))
+ (else (reverse acc)))
+ count)))
(else
(let ((piece
(cond
@@ -4962,7 +5001,8 @@
;; element is itself struct/array
(cond
((eq? (ctype-kind elem) 'arr)
- (%parse-init-array-list ps elem))
+ (let-values (((p _c) (%parse-init-array-list ps elem)))
+ p))
((or (eq? (ctype-kind elem) 'struct)
(eq? (ctype-kind elem) 'union))
(%parse-init-struct-list ps elem))
@@ -5075,7 +5115,8 @@
(advance ps)
(cond
((eq? (ctype-kind fty) 'arr)
- (%parse-init-array-list ps fty))
+ (let-values (((p _c) (%parse-init-array-list ps fty)))
+ p))
((or (eq? (ctype-kind fty) 'struct)
(eq? (ctype-kind fty) 'union))
(%parse-init-struct-list ps fty))
@@ -5110,10 +5151,15 @@
(let ((et (car (ctype-ext ty))))
(or (eq? et %t-i8) (eq? et %t-u8)))))
(advance ps)
+ ;; Note: for inferred-length (`int x[] = "..."`) auto arrays the
+ ;; sm-type still records the original (size=-1) ctype — `sizeof(x)`
+ ;; in the body would not see the resolved length. The slot is also
+ ;; sized off the original (= 1 byte), so the path is pre-existing
+ ;; broken; we don't paper over it here. Real C bootstrap code uses
+ ;; statics/globals for inferred-length arrays.
(let* ((slen (bytevector-length s))
(decl (cdr (ctype-ext ty)))
(final (cond ((< decl 0) (+ slen 1)) (else decl))))
- (cond ((< decl 0) (%init-fix-array-size! ty final)))
;; Emit byte stores for each char in s, plus NUL for the
;; trailing slot if final > slen.
(let loop ((i 0))
@@ -5156,7 +5202,9 @@
(cond
((at-punct? ps 'rbrace)
(advance ps)
- (cond ((< decl 0) (%init-fix-array-size! ty i)))
+ ;; Inferred-length auto path is pre-existing broken (slot
+ ;; allocated off size=-1, sm-type unfixed). See note in
+ ;; parse-init-local-aggregate STR branch.
;; Zero out remaining slots if any (declared length > i).
(let ((final (cond ((< decl 0) i) (else decl))))
(let zlp ((k i))
@@ -5320,30 +5368,29 @@
;; so it survives. Inner scope frames are popped via scope-leave! before
;; the rewind, so their cells become unreachable; rewind reclaims them.
;;
-;; Rewind-safety guard: the body might add user-visible globals
-;; (block-statics), strings (literals), tags, or typedefs. Those entries
-;; are post-mark and would dangle on rewind. We snapshot the relevant
-;; alists before parsing and skip the rewind if any changed — paying
-;; full heap cost only for functions that genuinely mutate global state.
+;; Rewind-safety guard: the body might add string-pool entries (string
+;; literals) or tags. Those entries are post-mark and would dangle on
+;; rewind. We snapshot the relevant alists before parsing and skip the
+;; rewind if any changed — paying full heap cost only for functions
+;; that genuinely mutate global state.
+;; (Block-scope typedefs and block-static syms are popped with
+;; scope-leave! so their cells become unreachable cleanly; emitted
+;; .data/.bss bytes for block-statics live in pre-mark fixed-storage
+;; bufs and are unaffected by rewind.)
(define (parse-fn-body ps name dt)
;; Hoist the recursive-binding scope-bind! out of the marked region
;; so the fn-sym cons survives rewind. defined?=#t marks this as a
;; definition so a prior forward decl gets overwritten and a second
;; definition with the same name fires sym-merge's redefinition error.
(scope-bind! ps name
- (%sym name 'fn 'extern dt
- (bytevector-append "cc__" name) #t))
+ (%sym name 'fn 'extern dt #f #t))
(let* ((cg (ps-cg ps))
(mark (heap-mark))
- (globals-before (cg-globals cg))
(str-pool-before (cg-str-pool cg))
- (typedefs-before (ps-typedefs ps))
(tags-before (ps-tags ps)))
(%parse-fn-body-inner ps name dt)
(cond
- ((and (eq? globals-before (cg-globals cg))
- (eq? str-pool-before (cg-str-pool cg))
- (eq? typedefs-before (ps-typedefs ps))
+ ((and (eq? str-pool-before (cg-str-pool cg))
(eq? tags-before (ps-tags ps)))
;; cg-fn-meta points at post-mark alist conses (fn metadata,
;; switch-case lists, indirect-slots). Drop the reference before