Guile gc experiment: add garbage collection.
[mes.git] / guile / gc.scm
index 66177c050e523c23a915a4a635aeed3f0d8497ab..12a6ae954869052103b8e7dd90c40da1b661357b 100644 (file)
 (define the-cars (make-vector gc-size '(* . *)))
 (define the-cdrs (make-vector gc-size '(* . *)))
 (define gc-free 0)
-(define (show-gc)
+(define (gc-show)
   (display "\nfree:") (display gc-free) (newline)
+  (display "       0       1       2       3       4       5       6       7       8       9\n")
   (display "cars:") (display the-cars) (newline)
   (display "cdrs:") (display the-cdrs) (newline))
-(show-gc)
 
-(define (cell-type c) (car (gc-cell c)))
-(define cell-index cdr)
-(define (cell-value c) (cdr (gc-cell c)))
+(define (gc-show-new)
+  (display "\nfree:") (display gc-free) (newline)
+  (display "       0       1       2       3       4       5       6       7       8       9\n")
+  (display "ncar:") (display new-cars) (newline)
+  (display "ncdr:") (display new-cdrs) (newline))
+(gc-show)
+
+(define (gc-car c)
+  (vector-ref the-cars (cell-index c)))
+
+(define (gc-cdr c)
+  (vector-ref the-cdrs (cell-index c)))
+
+(define (gc-set-car! c x)
+  (if (gc-pair? c) (vector-set! the-cars (cell-index c) x)))
+
+(define (gc-set-cdr! c x)
+  (if (gc-pair? c) (vector-set! the-cdrs (cell-index c) x)))
+
+(define (gc-null? x) (eq? (car x) 'e))
+
+(define (gc-pair? c)
+  (and (pair? c) (eq? (car c) 'p)))
+
+(define (cell-index c)
+  (if (eq? (car c) 'p)
+      (cdr c)))
+
+(define (cell-value c)
+  (if (member (car c) '(n s))
+   (cdr c)))
 
 (define (make-cell type . x)
   (cons type (if (pair? x) (car x) '*)))
 
 (define (gc-alloc)
+  (if (= gc-free gc-size) (gc))
   ((lambda (index)
      (set! gc-free (+ gc-free 1))
-     (make-cell '* index))
+     (make-cell 'p index))
    gc-free))
 
 (define (make-number x)
   ((lambda (cell)
      (vector-set! the-cars (cell-index cell) (make-cell 'n x))
-     cell)
+     (gc-car cell))
    (gc-alloc)))
 
 (define (make-symbol x)
   ((lambda (cell)
      (vector-set! the-cars (cell-index cell) (make-cell 's x))
-     cell)
+     (gc-car cell))
    (gc-alloc)))
 
 (define (gc-cons x y)
   ((lambda (cell)
-     (vector-set! the-cars (cell-index cell) (make-cell 'p (cell-index x)))
+     (vector-set! the-cars (cell-index cell) x)
      (vector-set! the-cdrs (cell-index cell) y)
      cell)
    (gc-alloc)))
 
-(define (gc-car c)
-  (vector-ref the-cars (cell-index c)))
-
-(define (gc-cdr c)
-  (vector-ref the-cdrs (cell-index c)))
-
-(define gc-cell gc-car)
-(define (gc-pair? c)
-  (eq? (cell-type c) 'p))
-
-(define (gc-set-car! c x)
-  (if (gc-pair? c) (vector-set! the-cars (cell-index c) x)))
-
-(define (gc-set-cdr! c x)
-  (if (gc-pair? c) (vector-set! the-cdrs (cell-index c) x)))
-
-(display "number 7=") (display (make-number 7)) (newline)
-(define first (make-number 8)) (newline)
-(show-gc)
-(define second (make-number 9)) (newline)
-(show-gc)
-(define pair (gc-cons first second))
-(show-gc)
-(display "pair:") (display pair) (newline)
-
-(display "car:") (display (gc-car pair)) (newline)
-(display "cdr:") (display (gc-cdr pair)) (newline)
-
-(define (gc-null? x) (eq? (car x) 'e))
-
 (define gc-nil (make-cell 'e 0))
-(display "nil: ") (display gc-nil) (newline)
-
 (define (gc-list . rest)
   (if (null? rest) gc-nil
       (gc-cons (car rest) (apply gc-list (cdr rest)))))
 
-(define lst (gc-list (make-symbol 'a) (make-symbol 'b) (make-symbol 'c)))
-(display "lst:") (display lst) (newline)
-(show-gc)
-
 (define (gc-display x . cont?)
   (if (gc-pair? x) (begin (if (null? cont?) (display "("))
                           (gc-display (gc-car x))
                           (if (gc-pair? (gc-cdr x)) (display " "))
-                          (gc-display (gc-cdr x) #t)
+                          (if (not (gc-null? (gc-cdr x)))
+                              (gc-display (gc-cdr x) #t))
                           (if (null? cont?) (display ")")))
       (if (gc-null? x) (if (not cont?) (display "()"))
           (display (cell-value x)))))
-(display "gc-display lst=") (gc-display lst) (newline)
-(show-gc)
+
+(define (gc-root)
+  (filter gc-pair? (module-map (lambda (x y) (variable-ref y)) (current-module)))
+  list1234)
+
+(define new-cars (make-vector (+ gc-size root-size) '(* . *)))
+(define new-cdrs (make-vector (+ gc-size root-size) '(* . *)))
+
+#!
+     begin-garbage-collection
+       (assign free (const 0))
+       (assign scan (const 0))
+       (assign old (reg root))
+       (assign relocate-continue
+               (label reassign-root))
+       (goto (label relocate-old-result-in-new))
+     reassign-root
+       (assign root (reg new))
+       (goto (label gc-loop))
+
+     gc-loop
+       (test (op =) (reg scan) (reg free))
+       (branch (label gc-flip))
+       (assign old
+               (op vector-ref)
+               (reg new-cars)
+               (reg scan))
+       (assign relocate-continue
+               (label update-car))
+       (goto (label relocate-old-result-in-new))
+
+
+     update-car
+       (perform (op vector-set!)
+                (reg new-cars)
+                (reg scan)
+                (reg new))
+       (assign  old
+                (op vector-ref)
+                (reg new-cdrs)
+                (reg scan))
+       (assign  relocate-continue
+                (label update-cdr))
+       (goto (label relocate-old-result-in-new))
+     update-cdr
+       (perform (op vector-set!)
+                (reg new-cdrs)
+                (reg scan)
+                (reg new))
+       (assign  scan (op +) (reg scan) (const 1))
+       (goto (label gc-loop))
+
+
+     relocate-old-result-in-new
+       (test (op pointer-to-pair?) (reg old))
+       (branch (label pair))
+       (assign new (reg old))
+       (goto (reg relocate-continue))
+     pair
+       (assign  oldcr
+                (op vector-ref)
+                (reg the-cars)
+                (reg old))
+       (test (op broken-heart?) (reg oldcr))
+       (branch  (label already-moved))
+       (assign  new (reg free)) ; new location for pair
+       ;; Update ‘free’ pointer.
+       (assign free (op +) (reg free) (const 1))
+       ;; Copy the ‘car’ and ‘cdr’ to new memory.
+       (perform (op vector-set!)
+                (reg new-cars)
+                (reg new)
+                (reg oldcr))
+       (assign  oldcr
+                (op vector-ref)
+                (reg the-cdrs)
+                (reg old))
+       (perform (op vector-set!)
+                (reg new-cdrs)
+                (reg new)
+                (reg oldcr))
+       ;; Construct the broken heart.
+       (perform (op vector-set!)
+                (reg the-cars)
+                (reg old)
+                (const broken-heart))
+       (perform (op vector-set!)
+                (reg the-cdrs)
+                (reg old)
+                (reg new))
+       (goto (reg relocate-continue))
+     already-moved
+       (assign  new
+                (op vector-ref)
+                (reg the-cdrs)
+                (reg old))
+       (goto (reg relocate-continue))
+
+     gc-flip
+       (assign temp (reg the-cdrs))
+       (assign the-cdrs (reg new-cdrs))
+       (assign new-cdrs (reg temp))
+       (assign temp (reg the-cars))
+       (assign the-cars (reg new-cars))
+       (assign new-cars (reg temp))
+
+!#
+
+(define scan 0)
+
+(define (gc)
+  (let ((root (gc-root)))
+    (display "gc root=") (display root) (newline)
+    (set! gc-free 0)
+    (set! scan 0)
+    (gc-loop (gc-relocate root))))
+
+(define (gc-loop new)
+  (gc-show)
+  (gc-show-new)
+  (display "gc-loop new=") (display new) (newline)
+  (display "gc-loop scan=") (display scan) (newline)
+  (display "gc-loop free=") (display gc-free) (newline)
+
+  (if (eq? scan gc-free) (gc-flip)
+      (let ((old (vector-ref new-cars scan)))
+        (let ((new (gc-relocate old)))
+          (let ((old (gc-update-car new))) 
+            (let ((new (gc-relocate old)))
+              (gc-update-cdr new)
+              (gc-loop new)))))))
+
+(define (gc-update-car new) ; -> old
+  (vector-set! new-cars scan new)
+  (vector-ref new-cdrs scan))
+
+(define (gc-update-cdr new)
+  (vector-set! new-cdrs scan new)
+  (set! scan (+ 1 scan)))
+
+(define (broken-heart? c) (eq? (car c) '<))
+(define gc-broken-heart '(< . 3))
+(define (gc-relocate old) ; old -> new
+  (display "gc-relocate old=") (display old) (newline)
+  (display "gc-relocate old is pair?=") (display (gc-pair? old)) (newline)
+  
+  (if (not (gc-pair? old)) old
+      (let ((oldcr (vector-ref the-cars (cell-index old))))
+        (display "gc-relocate oldcr=") (display oldcr) (newline)
+        (if (broken-heart? oldcr) old
+            (let ((new (cons 'p gc-free)))
+              (set! gc-free (+ 1 gc-free))
+              (vector-set! new-cars (cell-index new) oldcr)
+              (let ((oldcr (vector-ref the-cdrs (cell-index old))))
+                (display "gc-relocate oldcr=") (display oldcr) (newline)
+                (vector-set! new-cdrs (cell-index new) oldcr)
+                (vector-set! the-cars (cell-index old) gc-broken-heart)
+                (vector-set! the-cdrs (cell-index old) new))
+              new)))))
+
+(define (gc-flip)
+  (let ((cars the-cars)
+        (cdrs the-cdrs))
+    (set! the-cars new-cars)
+    (set! the-cdrs new-cdrs)
+    (set! new-cars cars)
+    (set! new-cdrs cdrs))
+  (gc-show))
+
+(define first (make-symbol 'F)) (newline)
+
+(define one (make-number 1))
+(display "\n one=") (display one) (newline)
+(define two (make-number 2))
+(define pair2-nil (gc-cons two gc-nil))
+(display "\npair2-nil=") (display pair2-nil) (newline)
+(gc-show)
+
+(define list1-2 (gc-cons one pair2-nil))
+(display "\nlist1-2=") (display list1-2) (newline)
+(gc-show)
+
+(define three (make-number 3))
+(define four (make-number 4))
+(define pair4-nil (gc-cons four gc-nil))
+(define list3-4 (gc-cons three pair4-nil))
+(define list1234 (gc-cons list1-2 list3-4))
+(gc-show)
+
+(display "\nlist1-2=") (display list1-2) (newline)
+(display "\nlist3-4=") (display list3-4) (newline)
+(display "lst=") (display list1234) (newline)
+(gc-show)
+
+(display "sicp-lst:") (gc-display list1234) (newline)
+(gc-show)
+
+(define next (gc-list (make-symbol 'N) (make-symbol 'X)))
+(set! list1234 '(p . 0))
+(display "sicp-lst:") (gc-display list1234) (newline)
+(gc-show)
+(display "next=") (display next) (newline)
+(display "gc-next=") (gc-display next) (newline)
+(gc-show)