flatten.scm 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber
  3. ; Transmogrify code to produce flat lexical environments.
  4. ;
  5. ; This takes two passes. The first finds the SET! variables so that cells can
  6. ; be added for them. The second pass adds a list of free variables to each
  7. ; non-call-position LAMBDA node. We don't need the free list for LET's.
  8. (set-optimizer! 'flat-environments
  9. (lambda (forms package)
  10. (map (lambda (form)
  11. (flatten-form (force-node form)))
  12. forms)))
  13. (define (flatten-form node)
  14. (mark-set-variables! node) ; we need to introduce cells for SET! variables
  15. (if (define-node? node)
  16. (let ((form (node-form node)))
  17. (make-similar-node node
  18. `(define ,(cadr form)
  19. ,(flatten-node (caddr form)
  20. (install-new-set!)))))
  21. (flatten-node node (install-new-set!))))
  22. ; Main dispatch
  23. ; This returns a new node and a list of free lexical variables.
  24. (define (flatten-node node free)
  25. ((operator-table-ref flatteners (node-operator-id node))
  26. node
  27. free))
  28. ; Particular operators
  29. (define flatteners
  30. (make-operator-table
  31. (lambda (node free)
  32. (make-similar-node node
  33. (cons (car (node-form node))
  34. (flatten-list (cdr (node-form node))
  35. free))))))
  36. (define (define-flattener name proc)
  37. (operator-define! flatteners name #f proc))
  38. (define (flatten-list nodes free)
  39. (map (lambda (node)
  40. (flatten-node node free))
  41. nodes))
  42. (define (no-free-vars node free)
  43. node)
  44. (define-flattener 'literal no-free-vars)
  45. (define-flattener 'quote no-free-vars)
  46. (define-flattener 'primitive-procedure no-free-vars)
  47. ; LAMBDA's get changed to FLAT-LAMBDA's if the lexical environment is
  48. ; non-empty.
  49. ; (FLAT-LAMBDA -formals- -free-vars- -body-)
  50. (define-flattener 'lambda
  51. (lambda (node free)
  52. (flatten-lambda node caddr free #t)))
  53. (define-flattener 'flat-lambda
  54. (lambda (node free)
  55. (flatten-lambda node cadddr free #t)))
  56. (define (flatten-lambda node get-body free closure?)
  57. (let ((exp (node-form node))
  58. (my-free (install-new-set!)))
  59. (let* ((formals (cadr exp))
  60. (body (convert-lambda-body formals (get-body exp) my-free)))
  61. (install-set! free)
  62. (set-union! free my-free)
  63. (if closure?
  64. (make-node operator/flat-lambda
  65. (list 'flat-lambda
  66. formals
  67. (set->list my-free)
  68. body))
  69. (make-node operator/lambda
  70. (list 'lambda
  71. formals
  72. body))))))
  73. ; Flatten the body and make cells for any SET! variables.
  74. (define (convert-lambda-body formals body free)
  75. (let* ((var-nodes (normalize-formals formals))
  76. (body (flatten-node body free)))
  77. (set-difference! free var-nodes)
  78. (add-cells body var-nodes)))
  79. (define (add-cells exp vars)
  80. (do ((vars vars (cdr vars))
  81. (cells '() (if (assigned? (car vars))
  82. (cons (make-make-cell (car vars)) cells)
  83. cells)))
  84. ((null? vars)
  85. (if (null? cells)
  86. exp
  87. (make-node operator/begin
  88. `(begin
  89. ,@(reverse cells)
  90. ,exp))))))
  91. ; Lexical nodes are free and may have cells.
  92. (define-flattener 'name
  93. (lambda (node free)
  94. (if (node-ref node 'binding)
  95. node
  96. (begin
  97. (set-add-element! free node)
  98. (if (assigned? node)
  99. (make-cell-ref node)
  100. node)))))
  101. (define-flattener 'set!
  102. (lambda (node free)
  103. (let* ((exp (node-form node))
  104. (var (cadr exp))
  105. (value (flatten-node (caddr exp) free)))
  106. (if (assigned? var)
  107. (begin
  108. (set-add-element! free var)
  109. (make-cell-set! var value))
  110. (make-similar-node node
  111. (list 'set! var value))))))
  112. (define-flattener 'call
  113. (lambda (node free)
  114. (let ((proc (car (node-form node)))
  115. (args (cdr (node-form node))))
  116. (make-similar-node node
  117. (cons (cond ((and (lambda-node? proc)
  118. (not (n-ary? (cadr (node-form proc)))))
  119. (flatten-lambda proc caddr free #f))
  120. ((and (flat-lambda-node? proc)
  121. (not (n-ary? (cadr (node-form proc)))))
  122. (flatten-lambda proc cadddr free #f))
  123. (else
  124. (flatten-node proc free)))
  125. (flatten-list args free))))))
  126. (define-flattener 'loophole
  127. (lambda (node free)
  128. (let ((form (node-form node)))
  129. (make-similar-node node
  130. (list (car form)
  131. (cadr form)
  132. (flatten-node (caddr form) free))))))
  133. ; Use LET & SET! for LETRECs that have non-LAMBDA values.
  134. (define-flattener 'letrec*
  135. (lambda (node free)
  136. (flatten-letrec node caddr free flatten-impure-letrec*)))
  137. (define-flattener 'letrec
  138. (lambda (node free)
  139. (flatten-letrec node caddr free flatten-impure-letrec)))
  140. (define-flattener 'pure-letrec
  141. (lambda (node free)
  142. (flatten-letrec node cadddr free flatten-impure-letrec)))
  143. (define (flatten-letrec node get-body free flatten-impure)
  144. (let ((form (node-form node)))
  145. (let ((vars (map car (cadr form)))
  146. (vals (map cadr (cadr form)))
  147. (body (get-body form)))
  148. (cond ((null? vars)
  149. (flatten-node body free)) ;+++
  150. ((and (every (lambda (node)
  151. (or (lambda-node? node)
  152. (flat-lambda-node? node)))
  153. vals)
  154. (not (any assigned? vars)))
  155. (flatten-pure-letrec vars vals body free)) ;+++
  156. (else
  157. (flatten-impure vars vals body free))))))
  158. (define (flatten-pure-letrec vars vals body free)
  159. (let* ((vals-free (install-new-set!))
  160. (vals (flatten-list vals vals-free)))
  161. (set-difference! vals-free vars)
  162. (install-set! free)
  163. (let ((body (flatten-node body free)))
  164. (set-difference! free vars)
  165. (set-union! free vals-free)
  166. (make-node operator/pure-letrec
  167. `(pure-letrec ,(map list vars vals)
  168. ,(set->list vals-free)
  169. ,body)))))
  170. (define (flatten-impure-letrec vars vals body free)
  171. (for-each (lambda (var)
  172. (node-set! var 'assigned 'maybe))
  173. vars)
  174. (let ((vals (flatten-list vals free))
  175. (temps (map (lambda (var)
  176. (make-node operator/name var))
  177. vars))
  178. (body (flatten-node body free)))
  179. (set-difference! free vars)
  180. (make-node
  181. operator/call
  182. (cons
  183. (make-node operator/lambda
  184. `(lambda ,vars
  185. ,(make-node
  186. operator/call
  187. (cons
  188. (make-node operator/lambda
  189. `(lambda ,temps
  190. ,(make-node operator/begin
  191. `(begin ,@(map make-cell-set!
  192. vars
  193. temps)
  194. ,body))))
  195. vals))))
  196. (map (lambda (ignore)
  197. (make-unassigned-cell))
  198. vars)))))
  199. (define (flatten-impure-letrec* vars vals body free)
  200. (for-each (lambda (var)
  201. (node-set! var 'assigned 'maybe))
  202. vars)
  203. (let ((vals (flatten-list vals free))
  204. (body (flatten-node body free)))
  205. (set-difference! free vars)
  206. (make-node
  207. operator/call
  208. (cons
  209. (make-node operator/lambda
  210. `(lambda ,vars
  211. ,(make-node operator/begin
  212. `(begin ,@(map make-cell-set!
  213. vars
  214. vals)
  215. ,body))))
  216. (map (lambda (ignore)
  217. (make-unassigned-cell))
  218. vars)))))
  219. ; Pick out the lexical variables from the list of free variables in the
  220. ; LAP form.
  221. (define-flattener 'lap
  222. (lambda (node free)
  223. (for-each (lambda (var)
  224. (if (not (node-ref var 'binding))
  225. (set-add-element! free var)))
  226. (caddr (node-form node)))
  227. node))
  228. ;----------------
  229. ; Is name-node NODE SET! anywhere?
  230. (define (assigned? node)
  231. (node-ref node 'assigned))
  232. ; Gather the info needed by ASSIGNED?.
  233. (define (mark-set-variables! node)
  234. ((operator-table-ref mark-sets (node-operator-id node))
  235. node))
  236. ; Particular operators
  237. (define mark-sets
  238. (make-operator-table
  239. (lambda (node)
  240. (for-each mark-set-variables! (cdr (node-form node))))))
  241. (define (define-set-marker name proc)
  242. (operator-define! mark-sets name #f proc))
  243. (define (no-sets node) #f)
  244. (define-set-marker 'literal no-sets)
  245. (define-set-marker 'quote no-sets)
  246. (define-set-marker 'name no-sets)
  247. (define-set-marker 'primitive-procedure no-sets)
  248. (define-set-marker 'lap no-sets)
  249. (define-set-marker 'lambda
  250. (lambda (node)
  251. (mark-set-variables! (caddr (node-form node)))))
  252. (define-set-marker 'flat-lambda
  253. (lambda (node)
  254. (mark-set-variables! (cadddr (node-form node)))))
  255. (define-set-marker 'set!
  256. (lambda (node)
  257. (let* ((exp (node-form node))
  258. (var (cadr exp)))
  259. (if (not (node-ref var 'binding))
  260. (node-set! var 'assigned #t))
  261. (mark-set-variables! (caddr exp)))))
  262. (define-set-marker 'loophole
  263. (lambda (node)
  264. (mark-set-variables! (caddr (node-form node)))))
  265. (define-set-marker 'call
  266. (lambda (node)
  267. (for-each mark-set-variables! (node-form node))))
  268. (define-set-marker 'letrec
  269. (lambda (node)
  270. (mark-letrec-sets node caddr)))
  271. (define-set-marker 'letrec*
  272. (lambda (node)
  273. (mark-letrec-sets node caddr)))
  274. (define-set-marker 'pure-letrec
  275. (lambda (node)
  276. (mark-letrec-sets node cadddr)))
  277. (define (mark-letrec-sets node get-body)
  278. (let ((form (node-form node)))
  279. (for-each (lambda (spec)
  280. (mark-set-variables! (cadr spec)))
  281. (cadr form))
  282. (mark-set-variables! (get-body form))))
  283. ;----------------
  284. ; Cell manipulation calls.
  285. (define (make-make-cell var)
  286. (make-node operator/set!
  287. (list 'set!
  288. var
  289. (make-primop-call (make-cell-primop) var))))
  290. (define (make-unassigned-cell)
  291. (make-primop-call (make-cell-primop)
  292. (make-node (get-operator 'unassigned)
  293. '(unassigned))))
  294. ; LETREC-bound cells need an additional check.
  295. (define (make-cell-ref var)
  296. (if (eq? 'maybe (node-ref var 'assigned))
  297. (make-primop-call (unassigned-check-primop)
  298. (really-make-cell-ref var))
  299. (really-make-cell-ref var)))
  300. (define (really-make-cell-ref var)
  301. (make-primop-call (cell-ref-primop) var))
  302. (define (make-cell-set! var value)
  303. (make-primop-call (cell-set!-primop) var value))
  304. (define (make-primop-call primop . args)
  305. (make-node operator/call
  306. (cons (make-node operator/literal
  307. primop)
  308. args)))
  309. ; We get loaded before these are defined, so we have to delay the lookups.
  310. (define-syntax define-primop
  311. (syntax-rules ()
  312. ((define-primop name id temp)
  313. (begin
  314. (define temp #f)
  315. (define (name)
  316. (or temp
  317. (begin
  318. (set! temp (get-primop 'id))
  319. temp)))))))
  320. (define-primop make-cell-primop make-cell temp0)
  321. (define-primop cell-ref-primop cell-ref temp1)
  322. (define-primop cell-set!-primop cell-set! temp2)
  323. (define-primop unassigned-check-primop unassigned-check temp3)
  324. ;----------------
  325. ; Set operations on lists.
  326. ;
  327. ; These use side effects to make union and difference O(n). Name nodes are
  328. ; marked with the set they are in. These marks are only valid for one set
  329. ; at any given time.
  330. (define (install-new-set!)
  331. (list 'set))
  332. (define (install-set! set)
  333. (for-each (lambda (var)
  334. (node-set! var 'set-owner set))
  335. (cdr set)))
  336. (define set->list cdr)
  337. (define (set-add-element! set var)
  338. (if (not (eq? set (node-ref var 'set-owner)))
  339. (begin
  340. (node-set! var 'set-owner set)
  341. (set-cdr! set (cons var (cdr set))))))
  342. (define (set-union! set other-set)
  343. (for-each (lambda (var)
  344. (set-add-element! set var))
  345. (set->list other-set)))
  346. (define (set-difference! set vars)
  347. (for-each clear-var-set! vars)
  348. (set-cdr! set (clean-var-list (cdr set))))
  349. (define (clean-var-list list)
  350. (cond ((null? list)
  351. list)
  352. ((node-ref (car list) 'set-owner)
  353. (cons (car list)
  354. (clean-var-list (cdr list))))
  355. (else
  356. (clean-var-list (cdr list)))))
  357. (define (clear-var-set! var)
  358. (node-set! var 'set-owner #f))