reify.scm 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber
  3. ; Structure reification.
  4. (define *least* #f)
  5. (define (reify-structures some)
  6. (let* ((count 0)
  7. (least 1000000)
  8. (greatest -1000000)
  9. (locs (make-table))
  10. (loser (reify-structures-1 some
  11. (lambda (loc)
  12. (let ((id (location-id loc)))
  13. (if (not (table-ref locs id))
  14. (begin
  15. (if (< id least)
  16. (set! *least* loc))
  17. (set! least (min least id))
  18. (set! greatest (max greatest id))
  19. (set! count (+ count 1))
  20. (table-set! locs id loc)))
  21. id))))
  22. (size (+ (- greatest least) 1)))
  23. (write `(least ,least size ,size count ,count)) (newline)
  24. (values loser
  25. (let ((v (make-vector size #f)))
  26. (table-walk (lambda (id loc)
  27. (vector-set! v (- id least) loc))
  28. locs)
  29. v)
  30. least)))
  31. ; This is pretty gross. We really want some kind of object dumper
  32. ; instead.
  33. (define *objects* '()) ;List of (object . creation-form)
  34. (define *object-count* 0)
  35. (define *initializations* '())
  36. (define *deal-with-location* (lambda (loc) loc))
  37. (define *package-table* #f) ;Entries are package-info structures
  38. ; REIFY-STRUCTURES returns a form that evaluates to a procedure that
  39. ; returns an alist of (name . structure). deal-with-location is a
  40. ; procedure that maps locations to labels for them (e.g. integers).
  41. ; The procedure takes one argument, a procedure that will be applied
  42. ; to the labels at startup time to re-obtain the corresponding
  43. ; locations.
  44. (define (reify-structures-1 alist deal-with-location)
  45. (flush-state)
  46. (set! *deal-with-location* deal-with-location)
  47. (display "Reifying") (force-output (current-output-port))
  48. (let* ((result-form (reify-object alist))
  49. (init-exprs (map (lambda (init) (init)) (reverse *initializations*)))
  50. (shebang
  51. `(lambda (get-location)
  52. (let ((the-objects (make-vector ,*object-count* #f)))
  53. ;; silly code to avoid oversize template
  54. (begin ,@(map (lambda (exprs) `(let ((foo (lambda (x) ,@exprs))) (foo 'foo)))
  55. (split-into-sublists init-exprs 100)))
  56. (let ((structs ,result-form))
  57. (set! the-objects #f) ;SO IT CAN BE GC'D
  58. (set! get-location #f)
  59. structs)))))
  60. (newline)
  61. (if *reify-debug* (*reify-debug* shebang))
  62. (flush-state)
  63. (set! *deal-with-location* (lambda (loc) loc))
  64. shebang))
  65. (define (list-split l n)
  66. (let loop ((n n)
  67. (l l)
  68. (rev-result '()))
  69. (if (or (zero? n) (null? l))
  70. (values (reverse rev-result) l)
  71. (loop (- n 1)
  72. (cdr l)
  73. (cons (car l) rev-result)))))
  74. (define (split-into-sublists l n)
  75. (let loop ((l l)
  76. (rev-result '()))
  77. (if (null? l)
  78. (reverse rev-result)
  79. (call-with-values
  80. (lambda () (list-split l n))
  81. (lambda (head rest)
  82. (loop rest
  83. (cons head rev-result)))))))
  84. (define (flush-state)
  85. (set! *objects* '())
  86. (set! *object-count* 0)
  87. (set! *initializations* '())
  88. (set! *package-table* (make-table package-uid)))
  89. ; Return an expression that will evaluate to thing.
  90. (define (reify-object thing)
  91. (cond ((structure? thing)
  92. (let ((p-form (reify-package (structure-package thing))))
  93. (process-one-object
  94. thing
  95. (lambda ()
  96. `(make-structure
  97. ,p-form
  98. ,(interface-expression thing)
  99. ',(structure-name thing)))
  100. (lambda ()
  101. (process-exports thing p-form)
  102. (write-char #\. (current-output-port))
  103. (force-output (current-output-port))))))
  104. ((null? thing) ''())
  105. ((pair? thing)
  106. (if (list? thing)
  107. `(list ,@(map reify-object thing))
  108. `(cons ,(reify-object (car thing))
  109. ,(reify-object (cdr thing)))))
  110. ((symbol? thing)
  111. `',thing)
  112. ((transform? thing)
  113. (process-transform thing))
  114. ((operator? thing)
  115. `(operator ',(operator-name thing)
  116. ',(type->sexp (operator-type thing) #t)))
  117. ((primop? thing)
  118. `(primop ',(primop-name thing)))
  119. ;; ((interface? thing) ...)
  120. (else (assertion-violation 'reify-object "don't know how to reify this" thing))))
  121. (define (reify-package thing)
  122. (process-one-object thing
  123. (lambda ()
  124. (let ((bindings (package-info-bindings (package-info thing))))
  125. `(package
  126. ;; Each binding is a pair (name . loc)
  127. ',(list->vector (map car bindings)) ;names
  128. ',(list->vector (map cdr bindings)) ;location ids
  129. get-location
  130. ,(package-uid thing))))
  131. (lambda ()
  132. (table-set! *package-table*
  133. thing
  134. (make-package-info)))))
  135. ; General utility for uniquifying objects.
  136. (define (process-one-object obj make-creation-form when-new)
  137. (let ((probe (assq obj *objects*)))
  138. (if probe
  139. (cdr probe)
  140. (let* ((index *object-count*)
  141. (form `(vector-ref the-objects ,index)))
  142. (set! *object-count* (+ *object-count* 1))
  143. (set! *objects*
  144. (cons (cons obj form) *objects*))
  145. (add-initialization!
  146. (lambda ()
  147. `(vector-set! the-objects ,index ,(make-creation-form))))
  148. (when-new)
  149. form))))
  150. (define (add-initialization! thunk)
  151. (set! *initializations*
  152. (cons thunk *initializations*)))
  153. ; Add initializers that will create a structure's exported bindings.
  154. (define (process-exports struct p-form)
  155. (let* ((package (structure-package struct))
  156. (info (package-info package)))
  157. (for-each-export (lambda (name want-type binding)
  158. (if (not (process-one-binding name package info p-form))
  159. (warning 'process-exports "undefined export" name package)))
  160. struct)))
  161. ; Packages...
  162. (define package-info-type
  163. (make-record-type 'reify-info
  164. '(bindings ;List of (name static-info location)
  165. table))) ;Caches (assq? name bindings)
  166. (define (package-info package)
  167. (table-ref *package-table* package))
  168. (define make-package-info
  169. (let ((make (record-constructor package-info-type
  170. '(bindings table))))
  171. (lambda ()
  172. (make '()
  173. (make-name-table)))))
  174. (define package-info-bindings (record-accessor package-info-type 'bindings))
  175. (define package-info-table (record-accessor package-info-type 'table))
  176. (define set-package-info-bindings!
  177. (record-modifier package-info-type 'bindings))
  178. (define (process-one-binding name package info p-form) ; => #t iff bound
  179. (let ((table (package-info-table info)))
  180. (if (table-ref table name)
  181. #t
  182. (let ((binding (package-lookup package name)))
  183. (table-set! (package-info-table info) name #t)
  184. (if (binding? binding)
  185. (begin (really-process-one-binding name info binding p-form)
  186. #t)
  187. #f)))))
  188. (define (really-process-one-binding name info binding p-form)
  189. (let ((static (binding-static binding))
  190. (loc (*deal-with-location* (binding-place binding))))
  191. (set-package-info-bindings!
  192. info
  193. (cons (cons name loc)
  194. (package-info-bindings info)))
  195. (if static
  196. (add-package-define! p-form name (reify-object static)))))
  197. (define (add-package-define! p-form name s-form)
  198. (add-initialization!
  199. (lambda ()
  200. `(package-define-static! ,p-form
  201. ',name
  202. ,s-form))))
  203. (define (process-transform transform)
  204. (let ((name (transform-id transform))
  205. (env (transform-env transform)))
  206. (let ((env-form
  207. (if (package? env)
  208. (reify-package env)
  209. (reify-object env))))
  210. (process-one-object
  211. transform
  212. (let ((source (transform-source transform))
  213. (kind (transform-kind transform)))
  214. (lambda ()
  215. `(transform ',kind
  216. ,source ;transformer
  217. ,env-form
  218. ',(type->sexp (transform-type transform) #t) ;type
  219. #f ;',source -- omitted to save space...
  220. ',name)))
  221. (if (package? env)
  222. (lambda ()
  223. (let ((info (package-info env)))
  224. (for-each (lambda (name)
  225. (process-one-binding name env info env-form))
  226. (or (transform-aux-names transform) ; () must be true
  227. (begin
  228. (warning 'process-transform
  229. "reified macro's auxiliary bindings are unknown"
  230. name)
  231. '())))))
  232. (lambda () #f))))))
  233. (define (interface-expression struct)
  234. (let ((names '())
  235. (types '()))
  236. (for-each-export (lambda (name type binding)
  237. (set! names (cons name names))
  238. (set! types (cons (if (eq? type undeclared-type)
  239. ':undeclared
  240. (type->sexp type #t))
  241. types)))
  242. struct)
  243. `(simple-interface ',(list->vector names) ',(list->vector types))))
  244. (define *reify-debug* ;#f
  245. (let ((fn "build/reify-debug.tmp"))
  246. (lambda (x) (call-with-output-file fn
  247. (lambda (port)
  248. (display "Writing linker debug file ")
  249. (display fn) (force-output (current-output-port))
  250. (write x port)
  251. (newline))))))