assem.scm 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Mike Sperber
  3. ; Byte-code assembler (Richard's version)
  4. ;
  5. ; This assembler can assemble the output of the disassembler (as long as you
  6. ; add the identifier and the list of free names).
  7. ;
  8. ; (lap <identifier> (<free name> ...) <insts>*)
  9. ; <inst> ::= (<op-code> . <operands>) |
  10. ; <label> |
  11. ; (global <identifier>) |
  12. ; (set-global! <identifier>) |
  13. ; (local <identifer>) | ; currently out of order
  14. ; (set-local! <identifier>) | ; currently out of order
  15. ; (literal <anything>) | (literal (quote <anything>))
  16. ; <operand> ::= <number> | <label> | <stob-name> |
  17. ; (lap <spec> <insts>*) ; only where a template is expected, currently out of order
  18. ; <label> ::= <symbol> | <integer>
  19. ; (<free name> ...) is a list of all names used in GLOBAL and SET-GLOBAL!
  20. ; instructions. These names are required.
  21. ;
  22. ; QUOTE is optional for literals, unless the value is itself quoted.
  23. ;
  24. ; The assembler uses opcode-arg-specs to check the number and type of arguments
  25. ; to the opcodes.
  26. ; This code barely works for the current VM design, because it doesn't
  27. ; really track the stack depth---it should. Among other things,
  28. ; template literals are probably almost always broken.
  29. (define-compilator 'lap syntax-type
  30. (lambda (node depth frame cont)
  31. (let* ((exp (node-form node))
  32. (bindings (map (lambda (name-node)
  33. (cons (node-form name-node)
  34. (node-ref name-node 'binding)))
  35. (caddr exp)))
  36. (insts (cdddr exp)))
  37. (if (or (null? insts)
  38. (not (eq? 'protocol (caar insts))))
  39. (assertion-violation 'lap "missing protocol instruction"))
  40. (call-with-values
  41. (lambda () (assemble-protocol (cdar insts)))
  42. (lambda (protocol template? env? closure? body-depth)
  43. (let* ((id (cadr exp))
  44. (template (compile-lap id
  45. protocol
  46. (cdr insts)
  47. bindings
  48. body-depth
  49. (make-frame frame id body-depth template? env? closure?))))
  50. (fixup-template-refs! template)
  51. (deliver-value
  52. (sequentially
  53. (stack-indirect-instruction (template-offset frame depth)
  54. (literal->index frame template))
  55. (instruction (enum op push))
  56. (instruction (enum op false))
  57. (instruction (enum op make-stored-object) 2 (enum stob closure)))
  58. cont)))))))
  59. ;----------------
  60. ; To allow for circular templates, templates can be referred to by name
  61. ; (the <identifier> in <spec> above). This code fixes up the references
  62. ; after assembly is otherwise complete.
  63. ;
  64. (define (fixup-template-refs! template)
  65. (let ((templates '()))
  66. ;; find all named templates
  67. (let find ((template template))
  68. (if (symbol? (template-info template))
  69. (set! templates (cons (cons (template-info template) template)
  70. templates)))
  71. (do ((i 0 (+ i 1)))
  72. ((>= i (template-length template)))
  73. (if (template? (template-ref template i))
  74. (find (template-ref template i)))))
  75. ;; replace all template markers with the appropriate template
  76. (let replace ((template template))
  77. (do ((i 0 (+ i 1)))
  78. ((>= i (template-length template)))
  79. (let ((x (template-ref template i)))
  80. (cond ((template? x)
  81. (replace x))
  82. ((not (template-marker? x)))
  83. ((assq (template-marker-name x) templates)
  84. => (lambda (t)
  85. (template-set! template i (cdr t))))
  86. (else
  87. (assertion-violation 'fixup-template-refs!
  88. "no template of this name available"
  89. (template-marker-name x)))))))))
  90. ; Marking where a template should be inserted.
  91. (define template-marker (cons #f #f))
  92. (define (make-template-marker name)
  93. (cons template-marker name))
  94. (define (template-marker? x)
  95. (and (pair? x)
  96. (eq? (car x) template-marker)))
  97. (define template-marker-name cdr)
  98. ;----------------
  99. (define (compile-lap id header insts bindings depth frame)
  100. (segment->template (sequentially
  101. header
  102. (really-compile-lap insts bindings depth frame))
  103. frame))
  104. ; Assemble each instruction, keeping track of which ones use labels.
  105. ; STUFF is a list of lists of the form (<inst> <offset> . <preceding-insts>)
  106. ; which indicates that <inst> uses a label, that it begins at <offset>, and is
  107. ; preceded by <preceding-insts>.
  108. (define (really-compile-lap insts bindings depth frame)
  109. (let loop ((insts insts) (segments '()) (stuff '()) (offset 0) (labels '()))
  110. (cond ((null? insts)
  111. (fixup-lap-labels segments stuff labels depth frame))
  112. ((pair? (car insts))
  113. (call-with-values
  114. (lambda ()
  115. (assemble-instruction (car insts) bindings depth frame))
  116. (lambda (segment label-use?)
  117. (let ((new-offset (+ offset (segment-size segment))))
  118. (if label-use?
  119. (loop (cdr insts)
  120. '()
  121. `((,(car insts) ,offset . ,segments) . ,stuff)
  122. new-offset
  123. labels)
  124. (loop (cdr insts)
  125. (cons segment segments)
  126. stuff
  127. new-offset
  128. labels))))))
  129. ((or (symbol? (car insts))
  130. (integer? (car insts)))
  131. (loop (cdr insts) segments stuff offset
  132. (cons (cons (car insts) offset) labels)))
  133. (else
  134. (assertion-violation 'compile-lap "bad LAP instruction" (car insts))))))
  135. ; Reassemble the instruction at the beginning of each STUFF list to resolve
  136. ; the label reference and glue everything together using SEQUENTIALLY. The
  137. ; label code assumes that the machine calculates the label from the end of
  138. ; the instruction.
  139. (define (fixup-lap-labels segments stuff labels depth frame)
  140. (let loop ((stuff stuff) (segment (apply sequentially (reverse segments))))
  141. (if (null? stuff)
  142. segment
  143. (let* ((data (car stuff))
  144. (inst (car data))
  145. (offset (cadr data))
  146. (segments (cddr data)))
  147. (loop (cdr stuff)
  148. (sequentially (apply sequentially (reverse segments))
  149. (reassemble-instruction inst offset labels depth frame)
  150. segment))))))
  151. ; This returns two values, the assembled instruction and a flag indicating
  152. ; whether or not the instruction used a label.
  153. (define (assemble-instruction inst bindings depth frame)
  154. (really-assemble-instruction inst bindings (lambda (label) (values 0 0))
  155. depth frame))
  156. ; Same as the above, except that labels are resolved and no flag is returned.
  157. (define (reassemble-instruction inst offset labels depth frame)
  158. (call-with-values
  159. (lambda ()
  160. (really-assemble-instruction inst #f (resolve-label offset labels) depth frame))
  161. (lambda (inst ignore)
  162. inst)))
  163. ; Return the high and low bytes of the distance between OFFSET and LABEL,
  164. ; using the known label offsets in LABELS.
  165. (define (resolve-label offset labels)
  166. (lambda (label)
  167. (cond ((assoc label labels)
  168. => (lambda (p)
  169. (let ((delta (- (cdr p) offset)))
  170. (values (quotient delta byte-limit)
  171. (remainder delta byte-limit)))))
  172. (else
  173. (assertion-violation 'resolve-label "LAP label is not defined" label)))))
  174. ;----------------
  175. ; Actually do some assembly. A few opcodes need special handling; most just
  176. ; use the argument specifications from the architecture.
  177. (define (really-assemble-instruction inst bindings labels depth frame)
  178. (let ((opname (car inst))
  179. (args (cdr inst)))
  180. (cond ((assemble-special-op opname args bindings depth frame)
  181. => (lambda (inst)
  182. (values inst #f)))
  183. ((name->enumerand opname op)
  184. => (lambda (opcode)
  185. (assemble-general-instruction opcode inst bindings labels depth frame)))
  186. (else
  187. (assertion-violation 'really-assemble-instruction
  188. "unknown LAP instruction" inst)))))
  189. ; The optional ' is optionally stripped off the argument to LITERAL.
  190. (define (assemble-special-op opname args bindings depth frame)
  191. (case opname
  192. ((literal)
  193. (let* ((arg (car args))
  194. (obj (if (and (pair? arg)
  195. (eq? (car arg) 'quote))
  196. (cadr arg)
  197. arg)))
  198. (cond
  199. ((small-integer? obj)
  200. (integer-literal-instruction obj))
  201. (else
  202. (stack-indirect-instruction
  203. (template-offset frame depth)
  204. (literal->index frame obj))))))
  205. ((global)
  206. (lap-global #f (car args) bindings frame depth))
  207. ((set-global!)
  208. (lap-global #t (car args) bindings frame depth))
  209. ; ((local)
  210. ; (if (null? (cdr args))
  211. ; (lap-local (car args) bindings)
  212. ; #f))
  213. ; ((set-local!)
  214. ; (if (null? (cdr args))
  215. ; (lap-set-local! (car args) bindings)
  216. ; #f))
  217. (else
  218. #f)))
  219. (define (small-integer? obj)
  220. (and (integer? obj)
  221. (exact? obj)
  222. (<= 0 (+ obj 128))
  223. (< (+ obj 128) byte-limit)))
  224. ; Lookup NAME in BINDINGS to the location.
  225. (define (lap-global assign? name bindings frame depth)
  226. (let ((binding (assq bindings name)))
  227. (if (not binding)
  228. (assertion-violation 'lap-global "LAP variable is not in free list" name)
  229. (let ((binding (cdr binding)))
  230. (cond ((and (binding? binding)
  231. (pair? (binding-place binding)))
  232. (assertion-violation 'lap-global "LAP variable is not global" name))
  233. (assign?
  234. (let ((offset (template-offset frame depth))
  235. (index (binding->index frame
  236. binding
  237. name
  238. usual-variable-type)))
  239. (instruction (enum op set-global!)
  240. (high-byte offset)
  241. (low-byte offset)
  242. (high-byte index)
  243. (low-byte index))))
  244. (else
  245. (let ((offset (template-offset frame depth))
  246. (index (binding->index frame binding name value-type)))
  247. (instruction (enum op global)
  248. (high-byte offset)
  249. (low-byte offset)
  250. (high-byte index)
  251. (low-byte index)))))))))
  252. ; This is for an old version (< 0.53); noone seems to use it currently.
  253. ; This needs a rewrite for the current architecture.
  254. ;; Lookup NAME in BINDINGS and pick out the appropriate local op.
  255. ;
  256. ;(define (lap-local name bindings)
  257. ; (let ((binding (lookup bindings name)))
  258. ; (if (and (binding? binding)
  259. ; (pair? (binding-place binding)))
  260. ; (let* ((level+over (binding-place binding))
  261. ; (back (- (environment-level bindings)
  262. ; (car level+over)))
  263. ; (over (cdr level+over)))
  264. ; (case back
  265. ; ((0) (instruction (enum op local0) over))
  266. ; ((1) (instruction (enum op local1) over))
  267. ; ((2) (instruction (enum op local2) over))
  268. ; (else (instruction (enum op local) back over))))
  269. ; (assertion-violation 'lap-local "LAP local variable is not locally bound" name))))
  270. ;
  271. ;; Same thing, except that there is only one opcode.
  272. ;
  273. ;(define (lap-set-local! name bindings)
  274. ; (let ((binding (lookup bindings name)))
  275. ; (if (and (binding? binding)
  276. ; (pair? (binding-place binding)))
  277. ; (let* ((level+over (binding-place binding))
  278. ; (back (- (environment-level bindings)
  279. ; (car level+over)))
  280. ; (over (cdr level+over)))
  281. ; (instruction (enum op set-local!)
  282. ; back
  283. ; (quotient over byte-limit)
  284. ; (remainder over byte-limit)))
  285. ; (assertion-violation 'lap-set-locasl! "LAP local variable is not locally bound" name))))
  286. ; Assembling protocols.
  287. (define (assemble-protocol args)
  288. (if (integer? (car args))
  289. (let ((count (car args)))
  290. (call-with-values
  291. (lambda ()
  292. (if (and (not (null? (cdr args)))
  293. (eq? '+ (cadr args)))
  294. (values #t (cddr args))
  295. (values #f (cdr args))))
  296. (lambda (nary? rest)
  297. (if (and (not (null? rest))
  298. (or (not (pair? (car rest)))
  299. (not (eq? 'push (caar rest)))))
  300. (assertion-violation 'assemble-protocol "unknown assembly protocol" args))
  301. (let ((push-env?
  302. (and (not (null? rest))
  303. (memq 'env (cdar rest))))
  304. (push-template?
  305. (and (not (null? rest))
  306. (memq 'template (cdar rest))))
  307. (push-closure?
  308. (and (not (null? rest))
  309. (memq 'closure (cdar rest)))))
  310. (let ((extras (+ (if push-template? 1 0)
  311. (if push-env? 1 0)
  312. (if push-closure? 1 0))))
  313. (if nary?
  314. (values (nary-lambda-protocol count push-template? push-env? push-closure?)
  315. push-template? push-env? push-closure?
  316. (+ 1 count extras))
  317. (values (lambda-protocol count push-template? push-env? push-closure?)
  318. push-template? push-env? push-closure?
  319. (+ count extras))))))))
  320. (case (car args)
  321. ((args+nargs)
  322. (values 0 ; doesn't matter
  323. (cons args+nargs-protocol (cdr args))))
  324. ((nary-dispatch)
  325. (values 0 ; doesn't matter
  326. (cons nary-dispatch-protocol
  327. (parse-nary-dispatch (cdr args)))))
  328. ((big-stack)
  329. (assertion-violation 'assemble-protocol "can't assemble big-stack protocol"))
  330. (else
  331. (assertion-violation 'assemble-protocol "unknown assembly protocol" args)))))
  332. ; This is fairly bogus, because it uses the targets as addresses instead
  333. ; of treating them as labels. Fixing this is too much work, seeing as
  334. ; no one is likely to use it.
  335. (define (parse-nary-dispatch targets)
  336. (let ((results (vector 0 0 0 0)))
  337. (warning 'parse-nary-dispatch
  338. "LAP compiler treats nary-dispatch targets as addresses, not as labels.")
  339. (for-each (lambda (target)
  340. (if (and (pair? target)
  341. (pair? (cdr target))
  342. (pair? (cddr target))
  343. (or (eq? (car target) '>2)
  344. (and (integer? (car target))
  345. (<= 0 (car target) 2)))
  346. (eq? (cadr target) '=>)
  347. (integer? (caddr target)))
  348. (vector-set! results
  349. (if (eq? (car target) '>2)
  350. 3
  351. (car target))
  352. (caddr target))
  353. (assertion-violation 'parse-nary-dispatch
  354. "bad nary-dispatch label in LAP" target)))
  355. targets)
  356. (vector->list results)))
  357. ;----------------
  358. ; This returns two values, the assembled instruction and a flag indicating
  359. ; whether or not the instruction used a label.
  360. (define (assemble-general-instruction opcode inst bindings labels depth frame)
  361. (let ((specs (vector-ref opcode-arg-specs opcode))
  362. (args (cdr inst))
  363. (finish (lambda (ops label-use?)
  364. (values (apply instruction opcode (reverse ops))
  365. label-use?))))
  366. (let loop ((specs specs) (args args) (ops '()) (label-use? #f))
  367. (if (null? specs)
  368. (finish ops label-use?)
  369. (case (car specs)
  370. ((offset)
  371. (let ((label (check-lap-arg args 'label inst)))
  372. (call-with-values
  373. (lambda () (labels label))
  374. (lambda (high low)
  375. (loop (cdr specs) (cdr args) `(,low ,high . ,ops) #t)))))
  376. ((stob)
  377. (let ((byte (check-lap-arg args 'stob inst)))
  378. (loop (cdr specs) (cdr args) (cons byte ops) label-use?)))
  379. ((byte nargs stack-index index)
  380. (let ((byte (check-lap-arg args 'int inst)))
  381. (loop (cdr specs) (cdr args) (cons byte ops) label-use?)))
  382. ((two-bytes two-byte-nargs two-byte-stack-index two-byte-index)
  383. (let ((number (check-lap-arg args 'int inst)))
  384. (loop (cdr specs) (cdr args)
  385. `(,(remainder number byte-limit)
  386. ,(quotient number byte-limit)
  387. . ,ops)
  388. label-use?)))
  389. ((junk)
  390. (loop (cdr specs) args (cons 0 ops) label-use?))
  391. (else
  392. (if (or (eq? (car specs) '+)
  393. (integer? (car specs)))
  394. (finish ops label-use?)
  395. (assertion-violation
  396. 'assemble-general-instruction
  397. "LAP internal error, unknown opcode argument specification"
  398. (car specs)))))))))
  399. ; Check that the car of ARGS is an argument of the appropriate type and
  400. ; return it.
  401. (define (check-lap-arg args type inst)
  402. (if (null? args)
  403. (assertion-violation 'check-lap-arg "not enough arguments in LAP instruction" inst))
  404. (let ((arg (car args)))
  405. (case type
  406. ((int)
  407. (if (integer? arg)
  408. arg
  409. (assertion-violation 'check-lap-arg "numeric operand expected in LAP instruction" inst)))
  410. ((stob)
  411. (cond ((name->enumerand arg stob))
  412. (else
  413. (assertion-violation 'check-lap-arg "unknown STOB argument in LAP instruction" inst))))
  414. ((label)
  415. (cond ((symbol? arg)
  416. arg)
  417. ((and (pair? arg)
  418. (eq? (car arg) '=>))
  419. (cadr arg))
  420. (else
  421. (assertion-violation 'check-lap-arg "bad label in LAP instruction" inst))))
  422. (else
  423. (assertion-violation 'check-lap-arg
  424. "LAP internal error, unknown LAP argument specifier" type)))))