gc.scm 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
  2. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  3. ; Collector
  4. ; (S48-TRACE-LOCATIONS! start end) ; trace all roots
  5. ; (S48-TRACE-VALUE value) => copied value
  6. ; (S48-TRACE-STOB-CONTENTS! stob)
  7. (define *gc-count* 0)
  8. (define (s48-gc-count) *gc-count*)
  9. (define *gc-seconds* 0)
  10. (define *gc-mseconds* 0)
  11. (define (s48-gc-run-time)
  12. (values *gc-seconds* *gc-mseconds*))
  13. (define (s48-collect force-major?)
  14. (receive (start-seconds start-mseconds) (run-time)
  15. (set! *from-begin* (heap-begin))
  16. (set! *from-end* (heap-limit))
  17. (swap-spaces)
  18. (set-heap-pointer! (heap-begin))
  19. (set! *weak-pointer-hp* null-address)
  20. (s48-gc-root) ; trace the interpreter's roots
  21. (do-gc)
  22. (clean-weak-pointers)
  23. (s48-post-gc-cleanup #t ; it's always a major collection
  24. (in-trouble?))
  25. (set! *gc-count* (+ *gc-count* 1))
  26. (receive (end-seconds end-mseconds) (run-time)
  27. (if (>= end-mseconds start-mseconds)
  28. (begin
  29. (set! *gc-seconds* (+ *gc-seconds*
  30. (- end-seconds start-seconds)))
  31. (set! *gc-mseconds* (+ *gc-mseconds*
  32. (- end-mseconds start-mseconds))))
  33. (begin
  34. (set! *gc-seconds* (+ *gc-seconds*
  35. (- (- end-seconds start-seconds) 1)))
  36. (set! *gc-mseconds* (+ *gc-mseconds*
  37. (- (+ 1000 end-mseconds)
  38. start-mseconds))))))))
  39. (define *from-begin*)
  40. (define *from-end*)
  41. (define (in-oldspace? descriptor)
  42. (and (stob? descriptor)
  43. (let ((a (address-after-header descriptor)))
  44. (and (address>= a *from-begin*)
  45. (address< a *from-end*)))))
  46. (define (s48-trace-value stob)
  47. (if (in-oldspace? stob)
  48. (copy-object stob)
  49. stob))
  50. ; Scan the heap, copying pointed to objects, starting from START. Quit once
  51. ; the scanning pointer catches up with the heap pointer.
  52. (define (do-gc)
  53. (let loop ((start (heap-begin)))
  54. (let ((end (heap-pointer)))
  55. (s48-trace-locations! start end)
  56. (cond ((< (s48-available) 0)
  57. (error "GC error: ran out of space in new heap"))
  58. ((address< end (heap-pointer))
  59. (loop end))))))
  60. (define (s48-trace-stob-contents! stob)
  61. (let ((start (address-after-header stob))
  62. (size (bytes->a-units (header-length-in-bytes (stob-header stob)))))
  63. (s48-trace-locations! start (address+ start size))))
  64. ; Copy everything pointed to from somewhere between START (inclusive)
  65. ; and END (exclusive).
  66. (define (s48-trace-locations! start end)
  67. (let loop ((addr start) (frontier (heap-pointer)))
  68. (if (address< addr end)
  69. (let ((thing (fetch addr))
  70. (next (address1+ addr)))
  71. (cond ((header? thing)
  72. (cond ((b-vector-header? thing)
  73. (loop (address+ next (header-length-in-a-units thing))
  74. frontier))
  75. ((continuation-header? thing)
  76. (let ((size (header-length-in-a-units thing)))
  77. (set-heap-pointer! frontier)
  78. (trace-continuation next size)
  79. (loop (address+ next size)
  80. (heap-pointer))))
  81. (else
  82. (loop next frontier))))
  83. ((in-oldspace? thing)
  84. (receive (new-thing frontier)
  85. (real-copy-object thing frontier)
  86. (store! addr new-thing)
  87. (loop next frontier)))
  88. (else
  89. (loop next frontier))))
  90. (set-heap-pointer! frontier))))
  91. ; 0) ; for the type-checker
  92. ; Copy THING if it has not already been copied.
  93. (define (copy-object thing)
  94. (receive (new-thing new-hp)
  95. (real-copy-object thing (heap-pointer))
  96. (set-heap-pointer! new-hp)
  97. new-thing))
  98. ; Non-heap-pointer version for better code in TRACE-LOCATIONS
  99. (define (real-copy-object thing frontier)
  100. (let ((h (stob-header thing)))
  101. (cond ((stob? h) ;***Broken heart
  102. ;; (assert (in-newspace? h))
  103. (values h frontier))
  104. ((and (vm-eq? weak-pointer-header h)
  105. (in-oldspace? (fetch (address-after-header thing))))
  106. (copy-weak-pointer thing frontier))
  107. (else
  108. (store! frontier h)
  109. (let* ((data-addr (address+ frontier (cells->a-units stob-overhead)))
  110. (new (address->stob-descriptor data-addr)))
  111. (stob-header-set! thing new) ;***Break heart
  112. (copy-memory! (address-after-header thing)
  113. data-addr
  114. (header-length-in-bytes h))
  115. (values new
  116. (address+ data-addr (header-length-in-a-units h))))))))
  117. (define (s48-extant? thing)
  118. (or (not (stob? thing))
  119. (not (in-oldspace? thing))
  120. (stob? (stob-header thing))))
  121. ;----------------
  122. ; Weak pointers
  123. ;
  124. ; Weak pointers are copied into contiguous blocks so that they can be
  125. ; scanned after the main GC has finished. They have their own heap pointer
  126. ; and heap limit.
  127. (define *weak-pointer-hp*)
  128. (define *weak-pointer-limit*)
  129. ; header + one slot
  130. (define weak-pointer-size 2)
  131. ; The number of weak pointers in each block.
  132. (define weak-pointer-alloc-count 128)
  133. ; The size of a block of weak pointers.
  134. (define weak-pointer-alloc-quantum
  135. (cells->a-units (* weak-pointer-alloc-count weak-pointer-size)))
  136. ; Used both to detect weak pointers and for setting the headers when the
  137. ; weak-pointer blocks are scanned.
  138. (define weak-pointer-header
  139. (make-header (enum stob weak-pointer) (cells->bytes (- weak-pointer-size 1))))
  140. ; A header used to stop the GC from scanning weak-pointer blocks.
  141. (define weak-alloc-area-header
  142. (make-header (enum stob byte-vector)
  143. (cells->bytes (- (* weak-pointer-alloc-count weak-pointer-size)
  144. 1)))) ; don't count the header
  145. (define (copy-weak-pointer weak frontier)
  146. (let ((frontier (if (or (null-address? *weak-pointer-hp*)
  147. (address>= *weak-pointer-hp* *weak-pointer-limit*))
  148. (allocate-more-weak-pointer-space frontier)
  149. frontier)))
  150. (let ((new (address->stob-descriptor
  151. (address+ *weak-pointer-hp* (cells->a-units stob-overhead)))))
  152. (store! (address1+ *weak-pointer-hp*) (fetch (address-after-header weak)))
  153. (set! *weak-pointer-hp* (address2+ *weak-pointer-hp*))
  154. (stob-header-set! weak new) ;***Break heart
  155. (values new frontier))))
  156. ; The weak pointer blocks are linked in their third slot (= the header space
  157. ; of the second weak pointer). The header for the first weak pointer contains
  158. ; a header for the block, and the value slots contain the (untraced) values.
  159. (define (allocate-more-weak-pointer-space frontier)
  160. (let ((old *weak-pointer-hp*)
  161. (new-frontier (address+ frontier weak-pointer-alloc-quantum)))
  162. (set! *weak-pointer-hp* frontier)
  163. (set! *weak-pointer-limit* new-frontier)
  164. (store! *weak-pointer-hp* weak-alloc-area-header)
  165. (store! (address2+ *weak-pointer-hp*) (address->integer old))
  166. new-frontier))
  167. ; If any weak pointers were found, then get the limits of the most recently
  168. ; allocated block and scan it and the rest of the blocks. Put a string header
  169. ; on the unused portion of the block the most recent block.
  170. (define (clean-weak-pointers)
  171. (if (not (null-address? *weak-pointer-hp*))
  172. (let ((start (address- *weak-pointer-limit* weak-pointer-alloc-quantum))
  173. (end *weak-pointer-hp*))
  174. (scan-weak-pointer-blocks start end)
  175. (if (not (address>= end *weak-pointer-limit*))
  176. (let ((unused-portion (address-difference *weak-pointer-limit*
  177. (address1+ end))))
  178. (store! end (make-header (enum stob byte-vector)
  179. (cells->bytes
  180. (a-units->cells unused-portion)))))))))
  181. (define (scan-weak-pointer-blocks start end)
  182. (let loop ((start start) (end end))
  183. (let ((next (integer->address (fetch (address2+ start)))))
  184. (scan-weak-pointer-block start end)
  185. (if (not (null-address? next))
  186. (loop (address- next weak-pointer-alloc-quantum) next)))))
  187. ; Go from START to END putting headers on the weak pointers and seeing if
  188. ; their contents were traced.
  189. (define (scan-weak-pointer-block start end)
  190. (do ((scan start (address2+ scan)))
  191. ((address>= scan end))
  192. (store! scan weak-pointer-header)
  193. (let ((value (fetch (address1+ scan))))
  194. (if (and (in-oldspace? value)
  195. (stob? value))
  196. (store! (address1+ scan)
  197. (let ((h (stob-header value)))
  198. (if (stob? h) h false)))))))