comp-prim.scm 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983
  1. ; -*- Mode: Scheme; Syntax: Scheme; Package: Scheme; -*-
  2. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  3. ; Authors: Richard Kelsey, Jonathan Rees,
  4. ; Martin Gasbichler, Marcus Crestani, Mike Sperber, Robert Ransom
  5. ; Compiling primitive procedures and calls to them.
  6. ; (primitive-procedure name) => a procedure
  7. (define-compilator 'primitive-procedure syntax-type
  8. (lambda (node depth frame cont)
  9. (let ((name (cadr (node-form node))))
  10. (deliver-value
  11. (sequentially
  12. (stack-indirect-instruction
  13. (template-offset frame depth)
  14. (literal->index frame (primop-closed-template name)))
  15. (instruction (enum op push))
  16. (instruction (enum op false)) ; no environment
  17. (instruction (enum op make-stored-object) 2 (enum stob closure)))
  18. cont))))
  19. (define (primop-closed-template name)
  20. (let ((data (primop-closed (get-primop name))))
  21. (receive (maybe-nargs proc)
  22. (if (pair? data)
  23. (values (car data) (cdr data))
  24. (values #f data))
  25. (let ((frame (make-frame #f ; no parent frame
  26. name ; name of primop
  27. (or maybe-nargs 0)
  28. ; nargs (needed if template used)
  29. maybe-nargs ; need template if nargs
  30. #f ; no env
  31. #f))) ; no closure
  32. (segment->template (proc frame) frame)))))
  33. ; --------------------
  34. ; Direct primitives.
  35. ; The simplest kind of primitive has fixed arity, corresponds to some
  36. ; single VM instruction, and takes its arguments in the usual way (all
  37. ; on the stack).
  38. (define (direct-compilator type opcode)
  39. (lambda (node depth frame cont)
  40. (let ((args (cdr (node-form node))))
  41. (sequentially (if (null? args)
  42. empty-segment
  43. (push-all-but-last args depth frame node))
  44. (deliver-value (instruction opcode) cont)))))
  45. (define (direct-closed-compilator opcode)
  46. (lambda (frame)
  47. (let ((arg-specs (vector-ref opcode-arg-specs opcode)))
  48. (sequentially (if (pair? arg-specs)
  49. (sequentially
  50. (lambda-protocol (car arg-specs) #f #f #f)
  51. (instruction (enum op pop)))
  52. (lambda-protocol 0 #f #f #f))
  53. (instruction opcode)
  54. (instruction (enum op return))))))
  55. (define (nargs->domain nargs)
  56. (do ((nargs nargs (- nargs 1))
  57. (l '() (cons value-type l)))
  58. ((= nargs 0) (make-some-values-type l))))
  59. (define (get-primop-type id arg-count)
  60. (or (any (lambda (foo)
  61. (if (if (pair? (car foo))
  62. (memq id (car foo))
  63. (eq? id (car foo)))
  64. (cadr foo)
  65. #f))
  66. primop-types)
  67. (procedure-type (nargs->domain arg-count)
  68. value-type
  69. #t)))
  70. ; Types for various primops.
  71. (define primop-types
  72. `((with-continuation
  73. ,(proc (escape-type (proc () any-values-type #f))
  74. any-arguments-type))
  75. (eq?
  76. ,(proc (value-type value-type) boolean-type))
  77. ((number? integer? rational? real? complex? char? eof-object? port?)
  78. ,(proc (value-type) boolean-type))
  79. (exact?
  80. ,(proc (number-type) boolean-type))
  81. (exact->inexact
  82. ,(proc (number-type) inexact-type))
  83. (inexact->exact
  84. ,(proc (number-type) exact-type))
  85. ((exp log sin cos tan asin acos sqrt)
  86. ,(proc (number-type) number-type))
  87. ((floor)
  88. ,(proc (real-type) integer-type))
  89. ((real-part imag-part angle magnitude)
  90. ,(proc (complex-type) real-type))
  91. ((numerator denominator)
  92. ,(proc (rational-type) integer-type))
  93. ((make-polar make-rectangular)
  94. ,(proc (real-type real-type) complex-type))
  95. ((quotient remainder)
  96. ,(proc (integer-type integer-type) integer-type))
  97. ((bitwise-not)
  98. ,(proc (exact-integer-type) exact-integer-type))
  99. ((arithmetic-shift)
  100. ,(proc (exact-integer-type exact-integer-type)
  101. exact-integer-type))
  102. (open-channel
  103. ;; Can return #f
  104. ,(proc (string-type value-type exact-integer-type boolean-type) value-type))
  105. (cons
  106. ,(proc (value-type value-type) pair-type))
  107. (intern
  108. ,(proc (string-type) symbol-type))
  109. (make-weak-pointer
  110. ,(proc (value-type) value-type))))
  111. ; Can't do I/O until the meta-types interface exports input-port-type and
  112. ; output-port-type.
  113. ; Define all the primitives that correspond to opcodes in the obvious way.
  114. (do ((opcode 0 (+ opcode 1)))
  115. ((= opcode op-count))
  116. (let ((arg-specs (vector-ref opcode-arg-specs opcode))
  117. (name (enumerand->name opcode op)))
  118. (cond ((memq name '(call-external-value call-external-value-2
  119. return-from-interrupt return
  120. binary-comparison-reduce2)))
  121. ((null? arg-specs)
  122. (let ((type (proc () value-type)))
  123. (define-compiler-primitive name type
  124. (direct-compilator type opcode)
  125. (direct-closed-compilator opcode))))
  126. ((not (number? (car arg-specs))))
  127. ((memq name '(+ * - / = < > <= >=
  128. bitwise-ior bitwise-xor bitwise-and
  129. make-string closed-apply
  130. encode-char/us-ascii)))
  131. (else
  132. (let ((type (get-primop-type name (car arg-specs))))
  133. (define-compiler-primitive name type
  134. (direct-compilator type opcode)
  135. (direct-closed-compilator opcode)))))))
  136. ; --------------------
  137. ; Simple primitives are executed using a fixed instruction or
  138. ; instruction sequence.
  139. (define (define-simple-primitive name type segment)
  140. (let ((winner? (fixed-arity-procedure-type? type)))
  141. (let ((nargs (if winner?
  142. (procedure-type-arity type)
  143. (assertion-violation 'define-simple-primitive
  144. "n-ary simple primitive?!" name type))))
  145. (define-compiler-primitive name type
  146. (simple-compilator segment)
  147. (simple-closed-compilator nargs segment)))))
  148. (define (simple-compilator segment)
  149. (lambda (node depth frame cont)
  150. (let ((args (cdr (node-form node))))
  151. (sequentially (if (null? args)
  152. empty-segment
  153. (push-all-but-last args depth frame node))
  154. (deliver-value segment cont)))))
  155. (define (simple-closed-compilator nargs segment)
  156. (lambda (frame)
  157. (sequentially (lambda-protocol nargs #f #f #f)
  158. (if (< 0 nargs)
  159. (instruction (enum op pop))
  160. empty-segment)
  161. segment
  162. (instruction (enum op return)))))
  163. (define (define-stob-predicate name stob-name)
  164. (define-simple-primitive name
  165. (proc (value-type) boolean-type)
  166. (instruction (enum op stored-object-has-type?)
  167. (name->enumerand stob-name stob))))
  168. (define-stob-predicate 'byte-vector? 'byte-vector)
  169. (define-stob-predicate 'double? 'double)
  170. (define-stob-predicate 'string? 'string)
  171. ; Making doubles
  172. (let ((:double (sexp->type ':double #t)))
  173. (define-compiler-primitive 'make-double (proc () :double)
  174. (lambda (node depth frame cont)
  175. (deliver-value
  176. (instruction (enum op make-double))
  177. cont))
  178. (cons 0
  179. (lambda (frame)
  180. (sequentially (lambda-protocol 0 #t #f #f)
  181. (instruction (enum op stack-indirect)
  182. (template-offset frame 1) ; template
  183. (literal->index frame 0))
  184. (instruction (enum op push))
  185. (instruction (enum op return)))))))
  186. ; Define primitives for record-like stored objects (e.g. pairs).
  187. (define (define-data-struct-primitives name predicate maker . slots)
  188. (let* ((def-prim (lambda (name type op . stuff)
  189. (define-simple-primitive name type
  190. (apply instruction (cons op stuff)))))
  191. (type-byte (name->enumerand name stob))
  192. (type (sexp->type (symbol-append ': name) #t)))
  193. (define-stob-predicate predicate name)
  194. (if maker
  195. (def-prim maker
  196. (procedure-type (nargs->domain (length slots)) type #t)
  197. (enum op make-stored-object)
  198. (length slots)
  199. type-byte))
  200. (do ((i 0 (+ i 1))
  201. (slots slots (cdr slots)))
  202. ((null? slots))
  203. (let ((slot (car slots)))
  204. (if (car slot)
  205. (def-prim (car slot)
  206. (proc (type) value-type)
  207. (enum op stored-object-ref) type-byte i))
  208. (if (not (null? (cdr slot)))
  209. (begin
  210. (if (not (eq? (cadr slot)
  211. 'cell-set!))
  212. (def-prim (cadr slot)
  213. (proc (type value-type) unspecific-type)
  214. (enum op stored-object-set!) type-byte i 0))
  215. (if (car slot)
  216. (def-prim (symbol-append 'provisional- (car slot))
  217. (proc (type) value-type)
  218. (enum op stored-object-logging-ref) type-byte i))
  219. (def-prim (symbol-append 'provisional- (cadr slot))
  220. (proc (type value-type) unspecific-type)
  221. (enum op stored-object-set!) type-byte i 1)))))))
  222. (for-each (lambda (stuff)
  223. (apply define-data-struct-primitives stuff))
  224. stob-data)
  225. ; CELL-SET! is special because we want to capture names for the debugging data.
  226. ; Other than using NAMED-CONT when it can for compiling the value this is the
  227. ; same as all the other accessors.
  228. (let ((inst (instruction (enum op stored-object-set!)
  229. (enum stob cell)
  230. 0 ; index
  231. 0))) ; not provisional
  232. (define-compiler-primitive 'cell-set!
  233. (proc ((sexp->type ':cell #t) value-type) unspecific-type)
  234. (lambda (node depth frame cont)
  235. (let ((args (cdr (node-form node))))
  236. (cond ((name-node? (car args))
  237. (sequentially
  238. (push-argument node 0 depth frame)
  239. (compile (cadr args)
  240. (+ depth 1)
  241. frame
  242. (named-cont (node-form (car args))))
  243. (deliver-value inst cont)))
  244. (else
  245. (sequentially (push-all-but-last args depth frame node)
  246. (deliver-value inst cont))))))
  247. (simple-closed-compilator 2 inst)))
  248. ; Define primitives for vector-like stored objects.
  249. (define (define-vector-primitives name element-type)
  250. (let* ((type-byte (name->enumerand name stob))
  251. (def-prim (lambda (name type op . more)
  252. (define-simple-primitive name type
  253. (apply instruction op type-byte more))))
  254. (type (sexp->type (symbol-append ': name) #t)))
  255. (define-stob-predicate (symbol-append name '?) name)
  256. (if (not (eq? name 'vector)) ; 2nd arg to make-vector is optional
  257. (def-prim (symbol-append 'make- name)
  258. (proc (exact-integer-type element-type) type)
  259. (enum op make-vector-object)))
  260. (def-prim (symbol-append name '- 'length)
  261. (proc (type) exact-integer-type)
  262. (enum op stored-object-length))
  263. (def-prim (symbol-append name '- 'ref)
  264. (proc (type exact-integer-type) element-type)
  265. (enum op stored-object-indexed-ref)
  266. 0) ; do not log in the proposal
  267. (def-prim (symbol-append name '- 'set!)
  268. (proc (type exact-integer-type element-type) unspecific-type)
  269. (enum op stored-object-indexed-set!)
  270. 0))) ; do not log in the proposal
  271. (for-each (lambda (name)
  272. (define-vector-primitives name value-type))
  273. '(vector record continuation extended-number template))
  274. (define-syntax define-more-vector-primitives
  275. (syntax-rules ()
  276. ((define-vector-primitives
  277. (ref ref-op)
  278. (set set-op)
  279. vector-type elt-type (more ...))
  280. (begin
  281. (define-simple-primitive 'ref
  282. (proc (vector-type exact-integer-type) elt-type)
  283. (instruction (enum op ref-op) more ...))
  284. (define-simple-primitive 'set
  285. (proc (vector-type exact-integer-type elt-type) unspecific-type)
  286. (instruction (enum op set-op) more ...))))))
  287. ; Vector ref and set! that use the current proposal's logs.
  288. (define-more-vector-primitives
  289. (provisional-vector-ref stored-object-indexed-ref)
  290. (provisional-vector-set! stored-object-indexed-set!)
  291. vector-type
  292. value-type
  293. ((enum stob vector) 1))
  294. (define-more-vector-primitives
  295. (provisional-byte-vector-ref byte-vector-logging-ref)
  296. (provisional-byte-vector-set! byte-vector-logging-set!)
  297. value-type
  298. exact-integer-type
  299. ())
  300. ; Checked-record-ref and friends.
  301. (let ((record-type (sexp->type ':record #t)))
  302. (define-simple-primitive 'checked-record-ref
  303. (proc (record-type value-type exact-integer-type) value-type)
  304. (instruction (enum op checked-record-ref) 0))
  305. (define-simple-primitive 'provisional-checked-record-ref
  306. (proc (record-type value-type exact-integer-type) value-type)
  307. (instruction (enum op checked-record-ref) 1))
  308. (define-simple-primitive 'checked-record-set!
  309. (proc (record-type value-type exact-integer-type value-type)
  310. unspecific-type)
  311. (instruction (enum op checked-record-set!) 0))
  312. (define-simple-primitive 'provisional-checked-record-set!
  313. (proc (record-type value-type exact-integer-type value-type)
  314. unspecific-type)
  315. (instruction (enum op checked-record-set!) 1)))
  316. (let ((copy-type (proc (value-type exact-integer-type
  317. value-type exact-integer-type
  318. exact-integer-type)
  319. unspecific-type)))
  320. (define-simple-primitive 'copy-bytes! copy-type
  321. (instruction (enum op copy-bytes!) 0))
  322. (define-simple-primitive 'attempt-copy-bytes! copy-type
  323. (instruction (enum op copy-bytes!) 1)))
  324. ; SIGNAL-CONDITION is the same as TRAP.
  325. (define-simple-primitive 'signal-condition (proc (value-type) unspecific-type)
  326. (instruction (enum op trap)))
  327. ; (primitive-catch (lambda (cont) ...))
  328. (define-compiler-primitive 'primitive-catch
  329. (proc ((proc (escape-type) any-values-type #f)) any-values-type)
  330. ;; (primitive-catch (lambda (cont) ...))
  331. (lambda (node depth frame cont)
  332. (let* ((exp (node-form node))
  333. (args (cdr exp)))
  334. (receive (before depth label after)
  335. (maybe-push-continuation depth frame cont (car args))
  336. (depth-check! frame (+ depth 1))
  337. (sequentially before
  338. (instruction (enum op current-cont))
  339. (instruction (enum op push))
  340. (compile (car args)
  341. (+ depth 1)
  342. frame
  343. (fall-through-cont node 1))
  344. (call-instruction 1 (+ depth 1) label) ; one argument
  345. after))))
  346. (lambda (frame)
  347. (sequentially (lambda-protocol 1 #f #f #f)
  348. (instruction (enum op current-cont))
  349. (instruction (enum op push))
  350. (instruction (enum op stack-ref) 1)
  351. (call-instruction 1 (+ (frame-size frame) 1) #f)))) ; one argument, no return label
  352. ; (call-with-values producer consumer)
  353. ; Optimization 1 (not done):
  354. ; If consumer is a lambda then generate it in-line with its own protocol as
  355. ; the return protocol for the producer. Once you have the values on the stack
  356. ; it can be treated as a redex.
  357. ;
  358. ; Optimization 2 (not done):
  359. ; If both the consumer and producer are lambdas then do as above except
  360. ; that the producer gets a special multiple-values continuation. There
  361. ; could be a VALUES opcode that moved its arguments down to the appropriate
  362. ; point and then jumped, or the jump could be a separate instruction.
  363. ; The jump target would have a protocol to allow tail calls within the
  364. ; producer as well.
  365. ;
  366. ; The closed-compiled version gets the arguments on the stack in the wrong
  367. ; order for what it wants to do. It does:
  368. ; *val* stack
  369. ; Start ? consumer producer ...
  370. ; (stack-ref+push 1) producer producer consumer producer ...
  371. ; (false) #f producer consumer producer ...
  372. ; (stack-set! 2) #f producer consumer #f ...
  373. ; (pop) producer consumer #f ...
  374. ; to reverse the order.
  375. (define-compiler-primitive 'call-with-values
  376. (proc ((proc () any-values-type #f)
  377. any-procedure-type)
  378. any-values-type)
  379. (lambda (node depth frame cont)
  380. (let ((args (cdr (node-form node))))
  381. (receive (ignore-before ignore-depth c-label c-after)
  382. (maybe-push-continuation depth frame cont (cadr args))
  383. (receive (p-before p-depth p-label p-after)
  384. (push-continuation-no-protocol (+ depth 1)
  385. frame
  386. (car args)
  387. (fall-through-cont node 1))
  388. (sequentially (push-argument node 1 depth frame)
  389. p-before
  390. (compile (car args)
  391. p-depth
  392. frame
  393. (fall-through-cont node 1))
  394. (instruction-using-label (enum op call)
  395. p-label
  396. 0)
  397. p-after
  398. (cwv-continuation-protocol c-label)
  399. c-after)))))
  400. (lambda (frame)
  401. (receive (before depth label after)
  402. (push-continuation-no-protocol 2 frame #f (plain-fall-through-cont))
  403. (sequentially (lambda-protocol 2 #f #f #f)
  404. (instruction (enum op stack-ref+push) 1)
  405. (instruction (enum op false))
  406. (instruction (enum op stack-set!) 2)
  407. (instruction (enum op pop))
  408. before
  409. (using-optional-label (enum op call) label 0)
  410. after
  411. (cwv-continuation-protocol #f)))))
  412. ; Is NODE a lambda with a null variable list.
  413. (define (thunk-node? node)
  414. (and (or (lambda-node? node)
  415. (flat-lambda-node? node))
  416. (null? (cadr (node-form node)))))
  417. ; Works for both normal and flat lambdas.
  418. (define (thunk-body node)
  419. (last (node-form node)))
  420. ; Return a non-flat version of the possibly-flat lambda NODE's form.
  421. (define (unflatten-form node)
  422. (let ((form (node-form node)))
  423. (if (flat-lambda-node? node)
  424. `(lambda ,(cadr form) ,(cadddr form))
  425. form)))
  426. ; --------------------
  427. ; Variable-arity primitives
  428. (define (define-n-ary-compiler-primitive name result-type min-nargs
  429. compilator closed)
  430. (define-compiler-primitive name
  431. (if result-type
  432. (procedure-type any-arguments-type result-type #f)
  433. #f)
  434. (if compilator
  435. (n-ary-primitive-compilator name min-nargs compilator)
  436. compile-unknown-call)
  437. closed))
  438. (define (n-ary-primitive-compilator name min-nargs compilator)
  439. (lambda (node depth frame cont)
  440. (let ((exp (node-form node)))
  441. (if (>= (length (cdr exp)) min-nargs)
  442. (compilator node depth frame cont)
  443. (begin (warning 'n-ary-primitive-compilator
  444. "too few arguments to primitive"
  445. (schemify node))
  446. (compile-unknown-call node depth frame cont))))))
  447. ; APPLY wants the arguments on the stack, with the final list on top, and the
  448. ; procedure in *VAL*.
  449. (define-compiler-primitive 'apply
  450. (proc (any-procedure-type &rest value-type) any-values-type)
  451. (n-ary-primitive-compilator 'apply 2
  452. (lambda (node depth frame cont)
  453. (let* ((exp (node-form node)) ; (apply proc arg1 arg2 arg3 rest)
  454. (proc+args+rest (cdr exp))
  455. (rest+args ; (rest arg3 arg2 arg1)
  456. (reverse (cdr proc+args+rest)))
  457. (args+rest+proc ; (arg1 arg2 arg3 rest proc)
  458. (reverse (cons (car proc+args+rest) rest+args)))
  459. (stack-nargs (length (cdr rest+args))))
  460. (receive (before depth label after)
  461. (maybe-push-continuation depth frame cont node)
  462. (sequentially before
  463. (push-all-but-last args+rest+proc depth frame node)
  464. ;; Operand is number of non-final arguments
  465. (using-optional-label (enum op apply)
  466. label
  467. (high-byte stack-nargs)
  468. (low-byte stack-nargs))
  469. after)))))
  470. (lambda (frame)
  471. (sequentially (nary-primitive-protocol 2)
  472. (instruction (enum op closed-apply)))))
  473. ; (values value1 value2 ...)
  474. ;
  475. ; Okay, this is the second half of the deal.
  476. ; - if tail-recursive, then just push the arguments followed by the opcode
  477. ; - if ignore-values continuation, then evaluate the arguments without
  478. ; doing any pushes in between
  479. ; - if fall-through, then there had better be only one value
  480. ; - that's it for now, given that there is no special CALL-WITH-VALUES
  481. ; continuation
  482. (define-n-ary-compiler-primitive 'values #f 0
  483. (lambda (node depth frame cont)
  484. (let* ((args (cdr (node-form node)))
  485. (nargs (length args)))
  486. (cond ((= 1 nargs) ; +++ (we miss some errors this way)
  487. (compile (car args)
  488. depth
  489. frame
  490. cont))
  491. ((return-cont? cont)
  492. (depth-check! frame (+ depth nargs))
  493. (sequentially (push-arguments node depth frame)
  494. (instruction (enum op values)
  495. (high-byte nargs)
  496. (low-byte nargs))))
  497. ((ignore-values-cont? cont)
  498. (evaluate-arguments-for-effect args node depth frame))
  499. ((fall-through-cont? cont)
  500. (generate-trap depth
  501. frame
  502. cont
  503. (if (= nargs 0)
  504. "returning no arguments where one is expected"
  505. (string-append "returning "
  506. (number->string nargs)
  507. " arguments where one is expected"))
  508. (schemify node)))
  509. (else
  510. (assertion-violation 'values
  511. "unknown compiler continuation for VALUES" cont)))))
  512. (lambda (frame)
  513. (sequentially (nary-primitive-protocol 0)
  514. (instruction (enum op closed-values)))))
  515. (define (evaluate-arguments-for-effect args node depth frame)
  516. (do ((args args (cdr args))
  517. (i 1 (+ i 1))
  518. (code empty-segment
  519. (sequentially code
  520. (compile (car args)
  521. depth
  522. frame
  523. (fall-through-cont node i)))))
  524. ((null? args)
  525. code)))
  526. ; (call-external-value external-routine arg ...)
  527. (define-n-ary-compiler-primitive 'call-external-value value-type 1
  528. #f ;Could be done
  529. (lambda (frame)
  530. (sequentially (nary-primitive-protocol 1)
  531. (instruction (enum op call-external-value))
  532. (instruction (enum op return)))))
  533. (define-n-ary-compiler-primitive 'call-external-value-2 value-type 1
  534. #f ;Could be done
  535. (lambda (frame)
  536. (sequentially (nary-primitive-protocol 1)
  537. (instruction (enum op call-external-value-2))
  538. (instruction (enum op return)))))
  539. (let ((n-ary-constructor
  540. (lambda (name type type-byte)
  541. (define-n-ary-compiler-primitive name type 0
  542. (lambda (node depth frame cont)
  543. (let ((args (cdr (node-form node))))
  544. (sequentially (if (null? args)
  545. empty-segment
  546. (push-all-but-last args depth frame node))
  547. (deliver-value
  548. (instruction (enum op make-stored-object)
  549. (length args)
  550. type-byte)
  551. cont))))
  552. (lambda (frame)
  553. (sequentially
  554. (nary-primitive-protocol 0)
  555. (instruction (enum op closed-make-stored-object) type-byte)
  556. (instruction (enum op return))))))))
  557. (n-ary-constructor 'vector vector-type (enum stob vector))
  558. (n-ary-constructor 'record #f (enum stob record)))
  559. ; READ-BYTE, PEEK-BYTE and WRITE-BYTE
  560. (let ((define-byte/char-io
  561. (lambda (id opcode type)
  562. (define-compiler-primitive id
  563. type
  564. (lambda (node depth frame cont)
  565. (if (node-ref node 'type-error)
  566. (compile-unknown-call node depth frame cont)
  567. (let ((args (cdr (node-form node))))
  568. (if (null? args)
  569. (deliver-value (instruction opcode 1) cont)
  570. (sequentially
  571. (push-all-but-last args depth frame node)
  572. (deliver-value (instruction opcode 0) cont))))))
  573. (lambda (frame)
  574. (make-dispatch-protocol
  575. ; Zero arguments
  576. (sequentially (instruction opcode 1)
  577. (instruction (enum op return)))
  578. ; One argument
  579. (sequentially (instruction (enum op pop))
  580. (instruction opcode 0)
  581. (instruction (enum op return)))
  582. empty-segment
  583. empty-segment))))))
  584. (define-byte/char-io 'read-byte
  585. (enum op read-byte)
  586. (proc (&opt value-type) value-type))
  587. (define-byte/char-io 'peek-byte
  588. (enum op peek-byte)
  589. (proc (&opt value-type) value-type))
  590. (define-byte/char-io 'read-char
  591. (enum op read-char)
  592. (proc (&opt value-type) value-type))
  593. (define-byte/char-io 'peek-char
  594. (enum op peek-char)
  595. (proc (&opt value-type) value-type)))
  596. (let ((define-byte/char-io
  597. (lambda (id opcode type)
  598. (define-compiler-primitive id
  599. type
  600. (lambda (node depth frame cont)
  601. (if (node-ref node 'type-error)
  602. (compile-unknown-call node depth frame cont)
  603. (let ((args (cdr (node-form node))))
  604. (sequentially
  605. (push-all-but-last args depth frame node)
  606. (if (null? (cdr args))
  607. (deliver-value (instruction opcode 1) cont)
  608. (sequentially
  609. (deliver-value (instruction opcode 0) cont)))))))
  610. (lambda (frame)
  611. (make-dispatch-protocol
  612. empty-segment
  613. ; One argument
  614. (sequentially (instruction (enum op pop))
  615. (instruction opcode 1)
  616. (instruction (enum op return)))
  617. ; Two arguments
  618. (sequentially (instruction (enum op pop))
  619. (instruction opcode 0)
  620. (instruction (enum op return)))
  621. empty-segment))))))
  622. (define-byte/char-io 'write-byte
  623. (enum op write-byte)
  624. (proc (integer-type &opt value-type) unspecific-type))
  625. (define-byte/char-io 'write-char
  626. (enum op write-char)
  627. (proc (char-type &opt value-type) unspecific-type)))
  628. ; Timings in 0.47 to figure out how to handle the optional ports.
  629. ;
  630. ; reading 10**6 characters (no buffer underflow)
  631. ; empty loop time: 3.44 seconds
  632. ; read-char time: 3.68 seconds ; special primitive, exceptions
  633. ; xread-char time: 9.04 seconds ; special primitive, no exceptions
  634. ; xxread-char time: 14.05 seconds ; no special primitive
  635. ; Currently, looping through a 10**6 character file takes 1.51 seconds or
  636. ; 2.50 seconds if you count the number of characters.
  637. ;----------------
  638. ; Variable-arity arithmetic primitives.
  639. ; +, *, bitwise-... take any number of arguments.
  640. (let ((define+*
  641. (lambda (id opcode identity type)
  642. (define-compiler-primitive id
  643. (proc (&rest type) type)
  644. (lambda (node depth frame cont)
  645. (if (node-ref node 'type-error)
  646. (compile-unknown-call node depth frame cont)
  647. (let ((args (cdr (node-form node))))
  648. (cond ((null? args)
  649. (deliver-value
  650. (stack-indirect-instruction
  651. (template-offset frame depth)
  652. (literal->index frame identity))
  653. cont))
  654. ((null? (cdr args))
  655. (call-on-arg-and-id opcode identity (car args)
  656. node depth frame cont))
  657. (else
  658. (call-on-args opcode args node depth frame cont))))))
  659. (lambda (frame)
  660. (make-dispatch-protocol
  661. ; No arguments
  662. (sequentially (integer-literal-instruction identity)
  663. (instruction (enum op return)))
  664. ; One argument
  665. (sequentially (integer-literal-instruction identity)
  666. (instruction opcode)
  667. (instruction (enum op return)))
  668. ; Two arguments
  669. (sequentially
  670. (instruction (enum op pop))
  671. (instruction opcode)
  672. (instruction (enum op return)))
  673. ; More than two arguments
  674. (sequentially
  675. (instruction (enum op pop)) ; pop off nargs
  676. (instruction (enum op binary-reduce1))
  677. (instruction opcode)
  678. (instruction (enum op binary-reduce2))
  679. (instruction (enum op return)))))))))
  680. (define+* '+ (enum op +) 0 number-type)
  681. (define+* '* (enum op *) 1 number-type)
  682. (define+* 'bitwise-ior (enum op bitwise-ior) 0 exact-integer-type)
  683. (define+* 'bitwise-xor (enum op bitwise-xor) 0 exact-integer-type)
  684. (define+* 'bitwise-and (enum op bitwise-and) -1 exact-integer-type))
  685. ; = and < and so forth take two or more arguments.
  686. (let ((define=<
  687. (lambda (id opcode type)
  688. (define-compiler-primitive id
  689. (proc (type type &rest type) boolean-type)
  690. (lambda (node depth frame cont)
  691. (if (node-ref node 'type-error)
  692. (compile-unknown-call node depth frame cont)
  693. (let ((args (cdr (node-form node))))
  694. (if (= (length args) 2)
  695. (call-on-args opcode args node depth frame cont)
  696. (compile-unknown-call node depth frame cont)))))
  697. (lambda (frame)
  698. (make-dispatch-protocol
  699. empty-segment
  700. empty-segment
  701. ; Two arguments
  702. (sequentially (instruction (enum op pop)) ; get first argument
  703. (instruction opcode)
  704. (instruction (enum op return)))
  705. ; More than two arguments
  706. (sequentially (instruction (enum op pop))
  707. (instruction (enum op binary-reduce1))
  708. (instruction opcode)
  709. (instruction (enum op binary-comparison-reduce2))
  710. (instruction (enum op return)))))))))
  711. (define=< '= (enum op =) real-type)
  712. (define=< '< (enum op <) real-type)
  713. (define=< '> (enum op >) real-type)
  714. (define=< '<= (enum op <=) real-type)
  715. (define=< '>= (enum op >=) real-type)
  716. (define=< 'char<? (enum op char<?) char-type)
  717. (define=< 'char=? (enum op char=?) char-type)
  718. (define=< 'string=? (enum op string=?) string-type))
  719. ; Returns code to apply OPCODE to IDENTITY and ARGUMENT.
  720. (define (call-on-arg-and-id opcode identity argument node depth frame cont)
  721. (sequentially (stack-indirect-instruction (template-offset frame depth)
  722. (literal->index frame identity))
  723. (instruction (enum op push))
  724. (compile argument (+ depth 1) frame (fall-through-cont node 1))
  725. (deliver-value (instruction opcode) cont)))
  726. ; Returns code to reduce ARGS using OPCODE.
  727. (define (call-on-args opcode args node depth frame cont)
  728. (let ((start (sequentially
  729. (push-all-but-last (list (car args)
  730. (cadr args))
  731. depth
  732. frame
  733. node)
  734. (instruction opcode))))
  735. (let loop ((args (cddr args)) (i 3) (code start))
  736. (if (null? args)
  737. (deliver-value code cont)
  738. (loop (cdr args)
  739. (+ i 1)
  740. (sequentially code
  741. (push-and-compile (car args)
  742. (+ depth 1)
  743. frame
  744. (fall-through-cont node i))
  745. (instruction opcode)))))))
  746. (define (push-and-compile node depth frame cont)
  747. (or (maybe-compile-with-push node depth frame #t) ; +++
  748. (sequentially push-instruction
  749. (compile node depth frame cont))))
  750. (define op/unspecific (get-operator 'unspecific))
  751. (define op/literal (get-operator 'literal))
  752. ; -, and / take one or two arguments.
  753. (let ((define-one-or-two
  754. (lambda (id opcode default-arg)
  755. (define-compiler-primitive id
  756. (proc (number-type &opt number-type) number-type)
  757. (lambda (node depth frame cont)
  758. (if (node-ref node 'type-error)
  759. (compile-unknown-call node depth frame cont)
  760. (let* ((args (cdr (node-form node)))
  761. (args (if (null? (cdr args))
  762. (list (make-node op/literal default-arg)
  763. (car args))
  764. args)))
  765. (sequentially
  766. (push-all-but-last args depth frame node)
  767. (deliver-value (instruction opcode) cont)))))
  768. (lambda (frame)
  769. (make-dispatch-protocol
  770. empty-segment
  771. ; One argument
  772. (sequentially (integer-literal-instruction default-arg)
  773. (instruction (enum op push))
  774. (instruction (enum op stack-ref) 1)
  775. (instruction opcode)
  776. (instruction (enum op return)))
  777. ; Two arguments
  778. (sequentially (instruction (enum op pop))
  779. (instruction opcode)
  780. (instruction (enum op return)))
  781. empty-segment))))))
  782. (define-one-or-two '- (enum op -) 0)
  783. (define-one-or-two '/ (enum op /) 1))
  784. ; ATAN also takes one or two arguments, but the meanings are disjoint.
  785. (define-compiler-primitive 'atan
  786. (proc (number-type &opt number-type) number-type)
  787. (lambda (node depth frame cont)
  788. (if (node-ref node 'type-error)
  789. (compile-unknown-call node depth frame cont)
  790. (let* ((args (cdr (node-form node)))
  791. (opcode (if (null? (cdr args))
  792. (enum op atan1)
  793. (enum op atan2))))
  794. (sequentially
  795. (push-all-but-last args depth frame node)
  796. (deliver-value (instruction opcode) cont)))))
  797. (lambda (frame)
  798. (make-dispatch-protocol
  799. empty-segment
  800. ; One argument
  801. (sequentially (instruction (enum op pop))
  802. (instruction (enum op atan1))
  803. (instruction (enum op return)))
  804. ; Two arguments
  805. (sequentially (instruction (enum op pop))
  806. (instruction (enum op atan2))
  807. (instruction (enum op return)))
  808. empty-segment)))
  809. ; make-vector and make-string take one or two arguments.
  810. (let ((define-one-or-two
  811. (lambda (id op-segment default-arg default-arg-segment type)
  812. (define-compiler-primitive id
  813. type
  814. (lambda (node depth frame cont)
  815. (if (node-ref node 'type-error)
  816. (compile-unknown-call node depth frame cont)
  817. (let* ((args (cdr (node-form node)))
  818. (args (if (null? (cdr args))
  819. (list (car args) default-arg)
  820. args)))
  821. (sequentially
  822. (push-all-but-last args depth frame node)
  823. (deliver-value op-segment cont)))))
  824. (lambda (frame)
  825. (make-dispatch-protocol
  826. empty-segment
  827. ; One argument
  828. (sequentially default-arg-segment
  829. op-segment
  830. (instruction (enum op return)))
  831. ; Two arguments
  832. (sequentially (instruction (enum op pop))
  833. op-segment
  834. (instruction (enum op return)))
  835. empty-segment))))))
  836. (define-one-or-two 'make-vector
  837. (instruction (enum op make-vector-object) (enum stob vector))
  838. (make-node op/unspecific '(unspecific))
  839. (instruction (enum op unspecific))
  840. (proc (number-type &opt value-type) vector-type))
  841. (define-one-or-two 'make-string
  842. (instruction (enum op make-string))
  843. (make-node op/literal #\?)
  844. (sequentially (integer-literal-instruction (char->ascii #\?))
  845. (instruction (enum op scalar-value->char)))
  846. (proc (number-type &opt char-type) string-type)))
  847. ; Text encoding/decoding
  848. ; These return multiple values, which is why this is more work.
  849. (let ((define-encode/decode
  850. (lambda (name type arg-count retval-count
  851. regular bang)
  852. (let ((depth-inc (max (- arg-count 1) retval-count)))
  853. (define-compiler-primitive name type
  854. (lambda (node depth frame cont)
  855. (depth-check! frame (+ depth depth-inc))
  856. (let ((args (cdr (node-form node))))
  857. (cond
  858. ((return-cont? cont)
  859. (sequentially (push-all-but-last args depth frame node)
  860. (instruction regular)))
  861. ((ignore-values-cont? cont)
  862. (sequentially (push-all-but-last args depth frame node)
  863. (instruction bang)))
  864. ((fall-through-cont? cont)
  865. (generate-trap depth
  866. frame
  867. cont
  868. (string-append "returning "
  869. (number->string retval-count)
  870. " arguments where one is expected")
  871. (schemify node)))
  872. (else
  873. (assertion-violation 'define-encode/decode
  874. "unknown compiler continuation" (enumerand->name regular op) cont)))))
  875. (direct-closed-compilator regular))))))
  876. (define-encode/decode 'char->utf
  877. (proc (exact-integer-type char-type value-type exact-integer-type exact-integer-type)
  878. (make-some-values-type (list boolean-type value-type)))
  879. 5 2
  880. (enum op char->utf) (enum op char->utf!))
  881. (define-encode/decode 'utf->char
  882. (proc (exact-integer-type value-type exact-integer-type exact-integer-type)
  883. (make-some-values-type (list value-type value-type)))
  884. 4 2
  885. (enum op utf->char) (enum op utf->char!)))