write-image.scm 14 KB

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