write-image.scm 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. ; Copyright (c) 1993-2008 by Richard Kelsey and Jonathan Rees. See file COPYING.
  2. ; Steps:
  3. ; 1. Trace everything reachable from RESUME-PROC and from the exported
  4. ; bindings (which we must assume are reachable because we cannot trace
  5. ; from the imported bindigns via external data structures to the
  6. ; exported bindings). All reachable objects are assigned addresses in
  7. ; the image and put in a list in the order they will appear in the image.
  8. ; 2. Write the ASCII image header.
  9. ; 3. Traverse the list of reachable objects writing them out into the
  10. ; image file.
  11. ; 4. Write out the symbol, imported binding, and exported binding tables,
  12. ; updating the buckets to only include those values which were traced.
  13. ; 5. Write out a vector containing all records with resume methods.
  14. ;
  15. ; Several types of objects do not get copied as-is:
  16. ; - Weak pointers
  17. ; The value is written as #F if it is not in the image.
  18. ; - Symbols, shared-bindings
  19. ; The next fields, which link the buckets in the hash tables holding
  20. ; these, are written out so as to elide any bucket entries that were
  21. ; not found during tracing. Imported bindings have their values
  22. ; written as unassigned.
  23. ; - Channels
  24. ; Written out as closed.
  25. ; - Undumpable records
  26. ; These are treated as if they were the value in the record's first slot.
  27. ;
  28. ; We can run out of memory. When this happens we disable the hash table
  29. ; to keep from trying to make further progress. We can also get i/o errors,
  30. ; but these are mostly taken care by the image-writing utilities.
  31. (define (s48-write-image resume-proc undumpables port)
  32. (begin-making-image undumpables)
  33. (if (image-write-init port)
  34. (let ((resume-proc (trace-image-value resume-proc)))
  35. (trace-exported-bindings (s48-exported-bindings))
  36. (make-image)
  37. (cond ((table-okay? *stob-table*)
  38. (write-header *resumer-records* resume-proc image-descriptor port)
  39. (write-descriptor false) ; for endianess check
  40. (write-image)
  41. (empty-image-buffer!)
  42. (deallocate-areas)
  43. (deallocate-table *stob-table*)
  44. (image-write-terminate)
  45. (image-write-status))
  46. (else
  47. (deallocate-table *stob-table*)
  48. (image-write-terminate)
  49. (enum errors out-of-memory))))
  50. (enum errors out-of-memory)))
  51. ; The interface to the GC consists of the following, listed in the order in
  52. ; which they are called.
  53. ;
  54. ; (BEGIN-MAKING-IMAGE start-address undumpable) ; UNDUMPABLE is a vector
  55. ;
  56. ; (TRACE-IMAGE-VALUE value) -> value in image ; identifies roots
  57. ;
  58. ; (MAKE-IMAGE) ; scan
  59. ; Scan everything, then make the symbol and imported/exported tables.
  60. ; Walk the stob table to count the resumer records and create that table
  61. ; as well.
  62. ;
  63. ; (IMAGE-SIZE)
  64. ; (IMAGE-SYMBOL-TABLE) -> stob in image
  65. ; (IMAGE-EXPORTED-BINDINGS) -> stob in image
  66. ; (IMAGE-IMPORTED-BINDINGS) -> stob in image
  67. ; (RESUMER-RECORDS) -> stob in image
  68. ; To find the resumer records we walk the table looking for them.
  69. ; First to find out how many and then a second time when we write
  70. ; the vector out.
  71. ;
  72. ; (WRITE-IMAGE) ; must come last
  73. ; Write out all the objects in the stob table and then the symbol and
  74. ; imported/exported tables and finally the resumer records.
  75. (define (begin-making-image undumpable)
  76. (set! *stob-table* (make-table))
  77. (set! *first-stob* false)
  78. (set! *last-stob* (null-pointer))
  79. (set! *undumpable-records* undumpable)
  80. (set! *undumpable-count* 0)
  81. (set! *resumer-count* 0)
  82. (begin-making-image/gc-specific))
  83. (define *stob-table*) ; Table mapping stobs to image-location records.
  84. (define *first-stob*) ; The beginning and end of the list
  85. (define *last-stob*) ; of image-location records.
  86. (define *resumer-count*) ; Number of resumer records found so far.
  87. (define *resumer-records*) ; Vector of resumer records created in image.
  88. (define *undumpable-records*) ; Vector passed to us for undumpable records.
  89. (define *undumpable-count*) ; How many we have found so far.
  90. ; Is THING in the image.
  91. (define (image-extant? thing)
  92. (not (and (stob? thing)
  93. (null-pointer? (table-ref *stob-table* thing)))))
  94. ; Add THING to the image if it is not already there. Returns the value of
  95. ; THING in the image. If there has been an error in table we proceed without
  96. ; doing anything.
  97. (define (trace-image-value thing)
  98. (if (stob? thing)
  99. (let ((have (table-ref *stob-table* thing)))
  100. (cond ((not (null-pointer? have))
  101. (image-location-new-descriptor have))
  102. ((undumpable? thing)
  103. (trace-undumpable thing))
  104. (else
  105. (add-new-image-object thing))))
  106. thing))
  107. ; Note that we have seen THING and then trace its alias. We add an entry to
  108. ; the table so that THING will not be traced again and so that references to
  109. ; it will be written out as the alias.
  110. (define (trace-undumpable thing)
  111. (note-undumpable! thing)
  112. (let* ((alias (undumpable-alias thing))
  113. (new-alias (trace-image-value alias))
  114. (new (make-image-location new-alias)))
  115. (if (null-pointer? new)
  116. (break-table! *stob-table*)
  117. (table-set! *stob-table* thing new))
  118. new-alias))
  119. ; Allocate space for STOB in the image and create a new-descriptor record
  120. ; for it.
  121. (define (add-new-image-object stob)
  122. (receive (new-descriptor new)
  123. (allocate-new-image-object stob)
  124. (if (null-pointer? new)
  125. (break-table! *stob-table*)
  126. (begin
  127. (if (false? *first-stob*)
  128. (set! *first-stob* stob)
  129. (set-image-location-next! *last-stob* stob))
  130. (set! *last-stob* new)
  131. (set-image-location-next! new false)
  132. (table-set! *stob-table* stob new)
  133. (if (resumer-record? stob)
  134. (set! *resumer-count* (+ *resumer-count* 1)))
  135. (finalize-new-image-object stob)))
  136. new-descriptor))
  137. ; Return the value of THING in the image. If there has been an error the
  138. ; table is gone and we proceed without doing anything.
  139. (define (image-descriptor thing)
  140. (if (stob? thing)
  141. (let ((have (table-ref *stob-table* thing)))
  142. (if (null-pointer? have)
  143. (error "traced object has no descriptor in image"))
  144. (image-location-new-descriptor have))
  145. thing))
  146. ;----------------------------------------------------------------
  147. ; Walk the list of objects in the image, tracing the contents of each
  148. ; (which may add more objects to the list). The tables are traced at
  149. ; the end and are left off of the list of image objects because they
  150. ; have to be written out in a nonstandard way.
  151. (define (make-image)
  152. (let loop ((stob *first-stob*))
  153. (trace-contents stob)
  154. (if (table-okay? *stob-table*)
  155. (let ((next (image-location-next (table-ref *stob-table* stob))))
  156. (if (stob? next)
  157. (loop next)))))
  158. (let ((last *last-stob*))
  159. (note-traced-last-stob!)
  160. (trace-image-value (s48-symbol-table))
  161. (trace-image-value (s48-imported-bindings))
  162. (trace-image-value (s48-exported-bindings))
  163. (set-image-location-next! last false))
  164. (set! *resumer-records*
  165. (image-alloc (enum area-type-size small) (cells->a-units *resumer-count*)))
  166. (adjust-descriptors! *stob-table*))
  167. (define (trace-contents stob)
  168. (let ((header (stob-header stob)))
  169. (if (not (or (b-vector-header? header)
  170. (vm-eq? header weak-pointer-header)))
  171. (let* ((start (address-after-header stob))
  172. (end (address+ start (header-length-in-a-units header))))
  173. (do ((addr start (address1+ addr)))
  174. ((address= addr end))
  175. (trace-image-value (fetch addr)))
  176. (unspecific)))))
  177. ; The exported binding table does not contain normal pointers. This does
  178. ; the appropriate magic for finding the objects it contains.
  179. (define trace-exported-bindings
  180. (let ((walker (table-walker shared-binding-next)))
  181. (lambda (table)
  182. (walker (lambda (binding)
  183. (trace-image-value binding))
  184. table))))
  185. ;----------------------------------------------------------------
  186. ; Actually write out the image. This is follows the same sequence as
  187. ; MAKE-IMAGE.
  188. (define (write-image)
  189. (write-image-areas *first-stob* *stob-table* write-stob)
  190. (write-symbol-table (s48-symbol-table))
  191. (write-shared-table (s48-imported-bindings))
  192. (write-shared-table (s48-exported-bindings))
  193. (write-resumer-records))
  194. (define (write-stob stob)
  195. (cond ((weak-pointer? stob)
  196. (write-descriptor weak-pointer-header)
  197. (if (image-extant? (weak-pointer-ref stob))
  198. (write-descriptor (image-descriptor (weak-pointer-ref stob)))
  199. (write-descriptor false)))
  200. ((channel? stob)
  201. (write-channel stob))
  202. ((vm-symbol? stob)
  203. (write-symbol stob))
  204. ((shared-binding? stob)
  205. (write-shared stob))
  206. (else
  207. (let* ((header (stob-header stob))
  208. (start (address-after-header stob)))
  209. (write-descriptor header)
  210. (if (b-vector-header? header)
  211. (write-image-block start (header-length-in-a-units header))
  212. (write-descriptors start (header-length-in-cells header)))))))
  213. (define (write-descriptors start cells)
  214. (let ((end (address+ start (cells->a-units cells))))
  215. (do ((addr start (address1+ addr)))
  216. ((address= addr end))
  217. (write-descriptor (image-descriptor (fetch addr))))
  218. (unspecific)))
  219. ; Walk the list of objects one last time to find the resumer records.
  220. (define (write-resumer-records)
  221. (write-descriptor (make-header (enum stob vector)
  222. (cells->bytes *resumer-count*)))
  223. (let loop ((stob *first-stob*))
  224. (if (stob? stob)
  225. (let ((location (table-ref *stob-table* stob)))
  226. (if (resumer-record? stob)
  227. (write-descriptor (image-location-new-descriptor location)))
  228. (loop (image-location-next location))))))
  229. ; Write out as closed. The status is the first slot, for what it's worth.
  230. ; It would be nice to clobber the os-index as well, but I don't want to add
  231. ; any extra assumptions here about what is where.
  232. (define (write-channel channel)
  233. (let ((header (stob-header channel)))
  234. (write-descriptor header)
  235. (write-descriptor closed-status)
  236. (write-descriptors (address1+ (address-after-header channel))
  237. (- (header-length-in-cells header) 1))
  238. (write-error-string "Channel closed in dumped image: ")
  239. (let ((id (channel-id channel)))
  240. (if (fixnum? id)
  241. (write-error-integer (extract-fixnum id))
  242. (write-error-string (extract-low-string id)))
  243. (write-error-newline))
  244. (unspecific)))
  245. (define closed-status
  246. (enter-fixnum (enum channel-status-option closed)))
  247. ; The value of the next field is disguised as a non-pointer to fool the GC.
  248. ; We have to follow it until we find the next symbol that is in the image.
  249. (define (write-symbol symbol)
  250. (let ((header (stob-header symbol))
  251. (next (next-extant-symbol (link->value (vm-symbol-next symbol)))))
  252. (write-descriptor header)
  253. (write-descriptors (address-after-header symbol)
  254. (- (header-length-in-cells header) 1))
  255. (write-descriptor (value->link (image-descriptor next)))))
  256. (define (next-extant-symbol symbol)
  257. (do ((next symbol (link->value (vm-symbol-next next))))
  258. ((image-extant? next)
  259. next)))
  260. ; Follow next, which is another disguised pointer. We drop the value of
  261. ; imports. The old value will still be in the image, but it's only a
  262. ; pointer-sized byte vector.
  263. (define (write-shared shared)
  264. (let ((header (stob-header shared))
  265. (next (next-extant-shared (link->value (shared-binding-next shared)))))
  266. (write-descriptor header)
  267. (write-descriptors (address-after-header shared)
  268. (- (header-length-in-cells header) 2))
  269. (write-descriptor (if (vm-eq? (shared-binding-is-import? shared)
  270. true)
  271. unassigned-marker
  272. (image-descriptor (shared-binding-ref shared))))
  273. (write-descriptor (value->link (image-descriptor next)))))
  274. (define (next-extant-shared shared)
  275. (do ((next shared (link->value (shared-binding-next next))))
  276. ((image-extant? next)
  277. next)))
  278. ; More disguised pointers.
  279. (define (table-writer next)
  280. (lambda (table)
  281. (write-descriptor (stob-header table))
  282. (do ((i 0 (+ i 1)))
  283. ((= i (vm-vector-length table)))
  284. (write-descriptor
  285. (value->link (image-descriptor
  286. (next (link->value (vm-vector-ref table i)))))))))
  287. (define write-symbol-table (table-writer next-extant-symbol))
  288. (define write-shared-table (table-writer next-extant-shared))
  289. ;----------------
  290. ; Undumpable records
  291. ;
  292. ; Record types may be marked as `undumpable', in which case they are replaced
  293. ; in images by the value of their first slot. Any that are found are put in a
  294. ; vector provided by our caller for that purpose. They are eventually reported
  295. ; back to the user.
  296. (define (undumpable? x)
  297. (and (gc-record? x)
  298. (let ((type (record-ref x 0)))
  299. (and (gc-record? type)
  300. (= false (record-ref type 1))))))
  301. (define (gc-record? x)
  302. (and (stob? x)
  303. (let ((header (stob-header x)))
  304. (if (stob? header)
  305. (record? header)
  306. (record? x)))))
  307. (define (undumpable-alias record)
  308. (record-ref record 1))
  309. ; We add undumpable records to a vector provided by the caller.
  310. (define (note-undumpable! thing)
  311. (if (and (< *undumpable-count*
  312. (vm-vector-length *undumpable-records*))
  313. (not (vector-memq? thing *undumpable-records*)))
  314. (begin
  315. (vm-vector-set! *undumpable-records*
  316. *undumpable-count*
  317. thing)
  318. (set! *undumpable-count* (+ 1 *undumpable-count*)))))
  319. (define (vector-memq? thing vector)
  320. (let ((len (vm-vector-length vector)))
  321. (let loop ((i 0))
  322. (cond ((= i len)
  323. #f)
  324. ((vm-eq? (vm-vector-ref vector i) thing)
  325. #t)
  326. (else
  327. (loop (+ i 1)))))))
  328. ;----------------------------------------------------------------
  329. ; More abstraction breaking, this time for finding records whose type has
  330. ; a resumer method.
  331. (define (resumer-record? stob)
  332. (and (record? stob)
  333. (let ((type (record-type stob)))
  334. (and (record? type)
  335. (stob? (record-type-resumer type))))))
  336. ; A record's type is at offset 0 and a type's resumer is at offset 1.
  337. (define (record-type record)
  338. (record-ref record 0))
  339. (define (record-type-resumer record-type)
  340. (record-ref record-type 1))
  341. ;----------------------------------------------------------------
  342. ; Used to detect weak pointers.
  343. (define weak-pointer-header
  344. (make-header (enum stob weak-pointer)
  345. (cells->bytes (- weak-pointer-size 1))))