heap.scm 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Allocation
  3. ; s48-*hp* is the heap pointer and s48-*limit* is the limit beyond which no
  4. ; storage should be allocated. Both of these are addresses (not
  5. ; descriptors).
  6. (define s48-*hp*)
  7. (define s48-*limit*)
  8. (define *oldspace-hp*)
  9. (define *oldspace-limit*)
  10. ; These are all in address units
  11. (define *newspace-begin*)
  12. (define *newspace-end*)
  13. (define *oldspace-begin*)
  14. (define *oldspace-end*)
  15. (define *new-heap-start-addr* null-address)
  16. (define (heap-begin)
  17. *newspace-begin*)
  18. (define (get-new-heap-start-addr)
  19. *new-heap-start-addr*)
  20. (define (heap-pointer)
  21. s48-*hp*)
  22. (define (set-heap-pointer! new)
  23. (set! s48-*hp* new))
  24. (define (heap-limit)
  25. *newspace-end*)
  26. ;----------------
  27. (define (s48-initialize-heap max-heap-size image-start-address image-size)
  28. (let* ((minimum-size (* 4 image-size))
  29. (heap-size (if (< max-heap-size minimum-size)
  30. (begin
  31. (write-error-string "Heap size ")
  32. (write-error-integer max-heap-size)
  33. (write-error-string " is too small, using ")
  34. (write-error-integer minimum-size)
  35. (write-error-string " cells")
  36. (write-error-newline)
  37. minimum-size)
  38. max-heap-size))
  39. (heap (allocate-memory (* 2 (cells->a-units heap-size)))))
  40. (if (null-address? heap)
  41. (error "unable to allocate heap space"))
  42. (let ((semisize (cells->a-units heap-size)))
  43. (set! *newspace-begin* heap)
  44. (set! *newspace-end* (address+ *newspace-begin* semisize))
  45. (set! *oldspace-begin* *newspace-end*)
  46. (set! *oldspace-end* (address+ *oldspace-begin* semisize))
  47. (if (address= *oldspace-begin* image-start-address)
  48. (swap-spaces))
  49. (set! *oldspace-hp* *oldspace-begin*)
  50. (set! *oldspace-limit* *oldspace-end*)
  51. (set! s48-*hp* *newspace-begin*)
  52. (set! s48-*limit* *newspace-end*)
  53. (set! *new-heap-start-addr* *newspace-begin*))))
  54. ; The check is already done in S48-INITIALIZE-HEAP
  55. ; This is only for the PreScheme compiler
  56. (define (s48-check-heap-size!)
  57. (unspecific))
  58. ; To write images we need to be able to undo the swapping.
  59. (define-syntax swap!
  60. (syntax-rules ()
  61. ((swap! a b)
  62. (let ((temp a))
  63. (set! a b)
  64. (set! b temp)))))
  65. (define (swap-spaces)
  66. (swap! s48-*limit* *oldspace-limit*)
  67. (swap! s48-*hp* *oldspace-hp*)
  68. (swap! *newspace-begin* *oldspace-begin*)
  69. (swap! *newspace-end* *oldspace-end*))
  70. ;----------------
  71. (define (s48-available? cells)
  72. (address< (address+ s48-*hp* (cells->a-units cells)) s48-*limit*))
  73. (define (bytes-available? bytes)
  74. (address< (address+ s48-*hp* (bytes->a-units bytes)) s48-*limit*))
  75. (define (s48-available)
  76. (a-units->cells (address-difference s48-*limit* s48-*hp*)))
  77. (define (s48-heap-size)
  78. (address-difference *newspace-end* *newspace-begin*))
  79. ; check if we're running out of space
  80. (define (in-trouble?)
  81. (< (s48-available)
  82. (quotient (s48-max-heap-size) 10)))
  83. ; it's the same here
  84. (define (s48-max-heap-size)
  85. (bytes->cells (address-difference *newspace-end* *newspace-begin*)))
  86. (define (store-next! descriptor)
  87. (store! s48-*hp* descriptor)
  88. (set! s48-*hp* (address1+ s48-*hp*)))
  89. (define (allocate len)
  90. (let ((new s48-*hp*))
  91. (set! s48-*hp* (address+ s48-*hp* (bytes->a-units len)))
  92. new))
  93. (define (s48-write-barrier stob address value)
  94. (address+ address (+ stob value)) ; for the type checker
  95. (unspecific))
  96. ;----------------
  97. ; Keeping track of all the areas.
  98. (define *pure-areas*)
  99. (define *impure-areas*)
  100. (define *pure-sizes*)
  101. (define *impure-sizes*)
  102. (define *pure-area-count* 0)
  103. (define *impure-area-count* 0)
  104. (define (s48-register-static-areas pure-count pure-areas pure-sizes
  105. impure-count impure-areas impure-sizes)
  106. (set! *pure-area-count* pure-count)
  107. (set! *pure-areas* pure-areas)
  108. (set! *pure-sizes* pure-sizes)
  109. (set! *impure-area-count* impure-count)
  110. (set! *impure-areas* impure-areas)
  111. (set! *impure-sizes* impure-sizes))
  112. (define (walk-areas proc areas sizes count)
  113. (let loop ((i 0))
  114. (cond ((>= i count)
  115. #t)
  116. ((proc (vector-ref areas i)
  117. (address+ (vector-ref areas i)
  118. (vector-ref sizes i)))
  119. (loop (+ i 1)))
  120. (else
  121. #f))))
  122. (define (walk-pure-areas proc)
  123. (if (< 0 *pure-area-count*)
  124. (walk-areas proc *pure-areas* *pure-sizes* *pure-area-count*)
  125. #t))
  126. (define (walk-impure-areas proc)
  127. (if (< 0 *impure-area-count*)
  128. (walk-areas proc *impure-areas* *impure-sizes* *impure-area-count*)
  129. #t))
  130. ;----------------------------------------------------------------
  131. ; Finding and gathering things in the heap.
  132. ;; GATHER-THUNK gathers objects, storing them via STORE-NEXT! until
  133. ;; finished (when it returns #t) or heap space runs out (when it
  134. ;; returns #f). GATHER-OBJECTS-INTO-VECTOR then returns a vector of
  135. ;; the results.
  136. (define (gather-objects-into-vector gather-thunk)
  137. (let ((start-hp s48-*hp*))
  138. (store-next! 0) ; reserve space for header
  139. (cond ((gather-thunk)
  140. (let ((size (address-difference s48-*hp* (address1+ start-hp))))
  141. (store! start-hp (make-header (enum stob vector) size) )
  142. (address->stob-descriptor (address1+ start-hp))))
  143. (else
  144. (set! s48-*hp* start-hp) ; out of space, so undo and give up
  145. false))))
  146. ; Gather, for a given iterator procedure FOR-EACH-OBJECT, all objects
  147. ; matching a given predicate PREDICATE into a vector.
  148. (define *collect-predicate*)
  149. (define (s48-gather-objects predicate for-each-object)
  150. (set! *collect-predicate* predicate)
  151. (gather-objects-into-vector
  152. (lambda ()
  153. (for-each-object
  154. (lambda (obj)
  155. (cond ((not (*collect-predicate* obj)) #t)
  156. ((s48-available? (cells->a-units 1))
  157. (store-next! obj)
  158. #t)
  159. (else #f)))))))
  160. (define *finding-type* (enum stob symbol)) ; work around lack of closures
  161. ; Call PREDICATE on all objects of type *FINDING-TYPE* found between START and
  162. ; END. The objects for which PREDICATE returns #T are pushed onto the heap
  163. ; using STORE-NEXT!. Returns #T for success and #F for failure.
  164. (define (collect-type-in-area predicate)
  165. (lambda (start end)
  166. (let ((type *finding-type*))
  167. (let loop ((addr start))
  168. (if (address>= addr end)
  169. #t
  170. (let* ((d (fetch addr))
  171. (next (address+ addr
  172. (+ (cells->a-units stob-overhead)
  173. (header-length-in-a-units d)))))
  174. (cond ((not (header? d))
  175. (write-string "heap is in an inconsistent state."
  176. (current-error-port))
  177. #f)
  178. ((not (= type (header-type d)))
  179. (loop next))
  180. (else
  181. (let ((obj (address->stob-descriptor (address1+ addr))))
  182. (cond ((not (predicate obj))
  183. (loop next))
  184. ((s48-available? (cells->a-units 1))
  185. (store-next! obj)
  186. (loop next))
  187. (else
  188. #f)))))))))))
  189. ; Returns a procedure that will walk the heap calling PREDICATE on every
  190. ; object of a particular type. Returns a vector containing all objects
  191. ; for which PREDICATE returns #t. If the heap is screwed up or there isn't
  192. ; room for the vector we return FALSE.
  193. (define (generic-find-all predicate)
  194. (let ((proc (collect-type-in-area predicate)))
  195. (lambda (type)
  196. (set! *finding-type* type) ; we don't have closures
  197. (let ((start-hp s48-*hp*))
  198. (gather-objects-into-vector
  199. (lambda ()
  200. (and (proc *newspace-begin* start-hp)
  201. (walk-impure-areas proc)
  202. (walk-pure-areas proc))))))))
  203. ; Find everything with a given type.
  204. (define s48-find-all
  205. (generic-find-all (lambda (thing) #t)))
  206. ; Find all records of a given record type (as determined by the first slot
  207. ; in each record).
  208. (define s48-find-all-records
  209. (let* ((the-record-type false)
  210. (finder (generic-find-all
  211. (lambda (record)
  212. (vm-eq? (record-type record)
  213. the-record-type)))))
  214. (lambda (record-type)
  215. (set! the-record-type record-type)
  216. (finder (enum stob record)))))
  217. ; Functions for accessing records. Getting these from STRUCT would introduce
  218. ; a circular module dependency.
  219. (define (record-type record)
  220. (record-ref record -1))
  221. (define (record-ref record offset)
  222. (fetch (address+ (address-after-header record)
  223. (cells->a-units (+ offset 1)))))
  224. ;----------------
  225. ; Checks for heap consistency. Quits after ERROR-COUNT problems have been
  226. ; found.
  227. (define (s48-check-heap error-count)
  228. (set! *heap-errors-left* error-count)
  229. (and (check-area *newspace-begin* s48-*hp*)
  230. (walk-impure-areas check-area)
  231. (walk-pure-areas check-area)))
  232. (define *heap-errors-left* 0)
  233. (define (check-area start end)
  234. (let loop ((addr start))
  235. (if (address>= addr end)
  236. #t
  237. (let* ((d (fetch addr))
  238. (next (address+ addr
  239. (+ (cells->a-units stob-overhead)
  240. (header-length-in-a-units d)))))
  241. (cond ((not (header? d))
  242. (check-lost "Heap-check: unexpected non-header."))
  243. ((address< end next)
  244. (check-lost "Heap-check: header too large."))
  245. ((b-vector-header? d)
  246. (loop next))
  247. ((check-stob-contents (address1+ addr) next)
  248. (loop next))
  249. (else
  250. #f))))))
  251. ; Check the descriptors from START (inclusive) to END (exclusive). This does
  252. ; not accept internal headers, which are normally allowed but not currently
  253. ; used by the system.
  254. (define (check-stob-contents start end)
  255. (let loop ((addr start))
  256. (if (address= addr end)
  257. #t
  258. (let ((x (fetch addr)))
  259. (cond ((header? x)
  260. (check-lost "Heap-check: unexpected header."))
  261. ((or (not (stob? x))
  262. (check-stob x))
  263. (loop (address1+ addr)))
  264. (else
  265. #f))))))
  266. ; Check that STOB points into the heap just after a header. This will fail
  267. ; if there are any pure or impure areas.
  268. (define (check-stob stob)
  269. (let ((addr (address-at-header stob)))
  270. (cond ((or (address< addr *newspace-begin*)
  271. (address<= s48-*hp* addr))
  272. (check-lost "Heap-check: address out of bounds."))
  273. ((not (header? (fetch addr)))
  274. (check-lost "Heap-check: stob has no header."))
  275. (else
  276. #t))))
  277. (define s48-stob-in-heap? check-stob)
  278. (define (s48-initialize-image-areas s sd l ld w wd)
  279. (= s 0) (= l 0) (= w 0) ; for the typechecker
  280. (= sd 0) (= ld 0) (= wd 0) ; for the typechecker
  281. (unspecific))
  282. (define (check-lost message)
  283. (write-string message (current-error-port))
  284. (newline (current-error-port))
  285. (set! *heap-errors-left* (- *heap-errors-left* 1))
  286. (< *heap-errors-left* 1))