reflect.scm 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885
  1. ;;; WebAssembly reflection
  2. ;;; Copyright (C) 2023, 2024 David Thompson <dave@spritely.institute>
  3. ;;; Copyright (C) 2023 Igalia, S.L.
  4. ;;;
  5. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  6. ;;; you may not use this file except in compliance with the License.
  7. ;;; You may obtain a copy of the License at
  8. ;;;
  9. ;;; http://www.apache.org/licenses/LICENSE-2.0
  10. ;;;
  11. ;;; Unless required by applicable law or agreed to in writing, software
  12. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  13. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ;;; See the License for the specific language governing permissions and
  15. ;;; limitations under the License.
  16. ;;; Commentary:
  17. ;;;
  18. ;;; Reflection for Hoot-compiled WASM modules.
  19. ;;;
  20. ;;; Code:
  21. (define-module (hoot reflect)
  22. #:use-module (hoot compile)
  23. #:use-module (hoot config)
  24. #:use-module (hoot promises)
  25. #:use-module (hoot scheduler)
  26. #:use-module (ice-9 match)
  27. #:use-module (ice-9 textual-ports)
  28. #:use-module (ice-9 binary-ports)
  29. #:use-module (ice-9 exceptions)
  30. #:use-module (rnrs bytevectors)
  31. #:use-module (srfi srfi-9)
  32. #:use-module (srfi srfi-9 gnu)
  33. #:use-module (wasm canonical-types)
  34. #:use-module (wasm parse)
  35. #:use-module (wasm types)
  36. #:use-module (wasm vm)
  37. #:export (hoot-object?
  38. hoot-complex?
  39. hoot-complex-real
  40. hoot-complex-imag
  41. hoot-fraction?
  42. hoot-fraction-num
  43. hoot-fraction-denom
  44. hoot-pair?
  45. mutable-hoot-pair?
  46. hoot-pair-car
  47. hoot-pair-cdr
  48. hoot-vector?
  49. mutable-hoot-vector?
  50. hoot-vector-length
  51. hoot-vector-ref
  52. hoot-bytevector?
  53. mutable-hoot-bytevector?
  54. hoot-bytevector-length
  55. hoot-bytevector-ref
  56. hoot-bitvector?
  57. mutable-hoot-bitvector?
  58. hoot-bitvector-length
  59. hoot-bitvector-ref
  60. hoot-symbol?
  61. hoot-symbol-name
  62. hoot-keyword?
  63. hoot-keyword-name
  64. mutable-hoot-string?
  65. mutable-hoot-string->string
  66. hoot-procedure?
  67. hoot-variable?
  68. hoot-atomic-box?
  69. hoot-hash-table?
  70. hoot-weak-table?
  71. hoot-fluid?
  72. hoot-dynamic-state?
  73. hoot-syntax?
  74. hoot-port?
  75. hoot-struct?
  76. hoot-print
  77. hoot-module?
  78. hoot-module-reflector
  79. hoot-module-instance
  80. reflector?
  81. reflector-instance
  82. reflector-abi
  83. call-with-fake-clock
  84. hoot-instantiate
  85. hoot-apply
  86. hoot-apply-async
  87. hoot-load
  88. compile-call
  89. compile-value))
  90. (define (s64? x)
  91. (and (exact-integer? x) (< (- (ash -1 63) 1) x (ash 1 63))))
  92. (define (u64? x)
  93. (and (exact-integer? x) (< -1 x (- (ash 1 64) 1))))
  94. (define-record-type <reflector>
  95. (make-reflector instance abi)
  96. reflector?
  97. (instance reflector-instance)
  98. (abi reflector-abi))
  99. (set-record-type-printer! <reflector>
  100. (lambda (r port)
  101. (format port "#<reflector instance: ~a>"
  102. (reflector-instance r))))
  103. (define-record-type <hoot-module>
  104. (make-hoot-module reflector instance)
  105. hoot-module?
  106. (reflector hoot-module-reflector)
  107. (instance hoot-module-instance))
  108. (define-record-type <hoot-complex>
  109. (make-hoot-complex reflector obj real imag)
  110. hoot-complex?
  111. (reflector hoot-complex-reflector)
  112. (obj hoot-complex-obj)
  113. (real hoot-complex-real)
  114. (imag hoot-complex-imag))
  115. (define-record-type <hoot-fraction>
  116. (make-hoot-fraction reflector obj num denom)
  117. hoot-fraction?
  118. (reflector hoot-fraction-reflector)
  119. (obj hoot-fraction-obj)
  120. (num hoot-fraction-num)
  121. (denom hoot-fraction-denom))
  122. (define-record-type <hoot-pair>
  123. (make-hoot-pair reflector obj)
  124. hoot-pair?
  125. (reflector hoot-pair-reflector)
  126. (obj hoot-pair-obj))
  127. (define-record-type <mutable-hoot-pair>
  128. (make-mutable-hoot-pair reflector obj)
  129. mutable-hoot-pair?
  130. (reflector mutable-hoot-pair-reflector)
  131. (obj mutable-hoot-pair-obj))
  132. (define-record-type <hoot-vector>
  133. (make-hoot-vector reflector obj)
  134. hoot-vector?
  135. (reflector hoot-vector-reflector)
  136. (obj hoot-vector-obj))
  137. (define-record-type <mutable-hoot-vector>
  138. (make-mutable-hoot-vector reflector obj)
  139. mutable-hoot-vector?
  140. (reflector mutable-hoot-vector-reflector)
  141. (obj mutable-hoot-vector-obj))
  142. (define-record-type <hoot-bytevector>
  143. (make-hoot-bytevector reflector obj)
  144. hoot-bytevector?
  145. (reflector hoot-bytevector-reflector)
  146. (obj hoot-bytevector-obj))
  147. (define-record-type <mutable-hoot-bytevector>
  148. (make-mutable-hoot-bytevector reflector obj)
  149. mutable-hoot-bytevector?
  150. (reflector mutable-hoot-bytevector-reflector)
  151. (obj mutable-hoot-bytevector-obj))
  152. (define-record-type <hoot-bitvector>
  153. (make-hoot-bitvector reflector obj)
  154. hoot-bitvector?
  155. (reflector hoot-bitvector-reflector)
  156. (obj hoot-bitvector-obj))
  157. (define-record-type <mutable-hoot-bitvector>
  158. (make-mutable-hoot-bitvector reflector obj)
  159. mutable-hoot-bitvector?
  160. (reflector mutable-hoot-bitvector-reflector)
  161. (obj mutable-hoot-bitvector-obj))
  162. (define-record-type <mutable-hoot-string>
  163. (make-mutable-hoot-string reflector obj)
  164. mutable-hoot-string?
  165. (reflector mutable-hoot-string-reflector)
  166. (obj mutable-hoot-string-obj))
  167. (define-record-type <hoot-symbol>
  168. (make-hoot-symbol reflector obj)
  169. hoot-symbol?
  170. (reflector hoot-symbol-reflector)
  171. (obj hoot-symbol-obj))
  172. (define-record-type <hoot-keyword>
  173. (make-hoot-keyword reflector obj)
  174. hoot-keyword?
  175. (reflector hoot-keyword-reflector)
  176. (obj hoot-keyword-obj))
  177. (define-record-type <hoot-variable>
  178. (make-hoot-variable reflector obj)
  179. hoot-variable?
  180. (reflector hoot-variable-reflector)
  181. (obj hoot-variable-obj))
  182. (define-record-type <hoot-atomic-box>
  183. (make-hoot-atomic-box reflector obj)
  184. hoot-atomic-box?
  185. (reflector hoot-atomic-box-reflector)
  186. (obj hoot-atomic-box-obj))
  187. (define-record-type <hoot-hash-table>
  188. (make-hoot-hash-table reflector obj)
  189. hoot-hash-table?
  190. (reflector hoot-hash-table-reflector)
  191. (obj hoot-hash-table-obj))
  192. (define-record-type <hoot-weak-table>
  193. (make-hoot-weak-table reflector obj)
  194. hoot-weak-table?
  195. (reflector hoot-weak-table-reflector)
  196. (obj hoot-weak-table-obj))
  197. (define-record-type <hoot-fluid>
  198. (make-hoot-fluid reflector obj)
  199. hoot-fluid?
  200. (reflector hoot-fluid-reflector)
  201. (obj hoot-fluid-obj))
  202. (define-record-type <hoot-dynamic-state>
  203. (make-hoot-dynamic-state reflector obj)
  204. hoot-dynamic-state?
  205. (reflector hoot-dynamic-state-reflector)
  206. (obj hoot-dynamic-state-obj))
  207. (define-record-type <hoot-syntax>
  208. (make-hoot-syntax reflector obj)
  209. hoot-syntax?
  210. (reflector hoot-syntax-reflector)
  211. (obj hoot-syntax-obj))
  212. (define-record-type <hoot-port>
  213. (make-hoot-port reflector obj)
  214. hoot-port?
  215. (reflector hoot-port-reflector)
  216. (obj hoot-port-obj))
  217. (define-record-type <hoot-struct>
  218. (make-hoot-struct reflector obj)
  219. hoot-struct?
  220. (reflector hoot-struct-reflector)
  221. (obj hoot-struct-obj))
  222. ;; The Hoot procedure type is defined using Guile's low-level struct
  223. ;; API so that we can use applicable structs, allowing Hoot procedures
  224. ;; to be called as if they were native ones.
  225. (define <hoot-procedure>
  226. (make-struct/no-tail <applicable-struct-vtable> 'pwpwpw))
  227. (define (hoot-procedure? obj)
  228. (and (struct? obj) (eq? (struct-vtable obj) <hoot-procedure>)))
  229. (define (make-hoot-procedure reflector obj)
  230. (define (hoot-apply . args)
  231. (hoot-call reflector obj args))
  232. (make-struct/no-tail <hoot-procedure> hoot-apply reflector obj))
  233. (define (hoot-object? obj)
  234. (or (hoot-complex? obj)
  235. (hoot-fraction? obj)
  236. (hoot-pair? obj)
  237. (mutable-hoot-pair? obj)
  238. (hoot-vector? obj)
  239. (mutable-hoot-vector? obj)
  240. (hoot-bytevector? obj)
  241. (mutable-hoot-bytevector? obj)
  242. (hoot-bitvector? obj)
  243. (mutable-hoot-bitvector? obj)
  244. (mutable-hoot-string? obj)
  245. (hoot-procedure? obj)
  246. (hoot-symbol? obj)
  247. (hoot-keyword? obj)
  248. (hoot-variable? obj)
  249. (hoot-atomic-box? obj)
  250. (hoot-hash-table? obj)
  251. (hoot-weak-table? obj)
  252. (hoot-fluid? obj)
  253. (hoot-dynamic-state? obj)
  254. (hoot-syntax? obj)
  255. (hoot-port? obj)
  256. (hoot-struct? obj)))
  257. (define-syntax-rule (~ reflector name args ...)
  258. ((wasm-instance-export-ref (reflector-instance reflector) name) args ...))
  259. (define (hoot-pair-car pair)
  260. (match pair
  261. ((or ($ <hoot-pair> reflector obj)
  262. ($ <mutable-hoot-pair> reflector obj))
  263. (wasm->guile reflector (~ reflector "car" obj)))))
  264. (define (hoot-pair-cdr pair)
  265. (match pair
  266. ((or ($ <hoot-pair> reflector obj)
  267. ($ <mutable-hoot-pair> reflector obj))
  268. (wasm->guile reflector (~ reflector "cdr" obj)))))
  269. (define (hoot-vector-length vec)
  270. (match vec
  271. ((or ($ <hoot-vector> reflector obj)
  272. ($ <mutable-hoot-vector> reflector obj))
  273. (~ reflector "vector_length" obj))))
  274. (define (hoot-vector-ref vec idx)
  275. (match vec
  276. ((or ($ <hoot-vector> reflector obj)
  277. ($ <mutable-hoot-vector> reflector obj))
  278. (wasm->guile reflector (~ reflector "vector_ref" obj idx)))))
  279. (define (hoot-bytevector-length bv)
  280. (match bv
  281. ((or ($ <hoot-bytevector> reflector obj)
  282. ($ <mutable-hoot-bytevector> reflector obj))
  283. (~ reflector "bytevector_length" obj))))
  284. (define (hoot-bytevector-ref bv idx)
  285. (match bv
  286. ((or ($ <hoot-bytevector> reflector obj)
  287. ($ <mutable-hoot-bytevector> reflector obj))
  288. (~ reflector "bytevector_ref" obj idx))))
  289. (define (hoot-bitvector-length bv)
  290. (match bv
  291. ((or ($ <hoot-bitvector> reflector obj)
  292. ($ <mutable-hoot-bitvector> reflector obj))
  293. (~ reflector "bitvector_length" obj))))
  294. (define (hoot-bitvector-ref bv idx)
  295. (match bv
  296. ((or ($ <hoot-bitvector> reflector obj)
  297. ($ <mutable-hoot-bitvector> reflector obj))
  298. (~ reflector "bitvector_ref" obj idx))))
  299. (define (hoot-symbol-name sym)
  300. (match sym
  301. (($ <hoot-symbol> reflector obj)
  302. (~ reflector "symbol_name" obj))))
  303. (define (hoot-keyword-name kw)
  304. (match kw
  305. (($ <hoot-keyword> reflector obj)
  306. (~ reflector "keyword_name" obj))))
  307. (define (mutable-hoot-string->string str)
  308. (match str
  309. (($ <mutable-hoot-string> reflector obj)
  310. (~ reflector "string_value" obj))))
  311. ;; UH OH: This doesn't detect cycles!
  312. (define (hoot-print obj port)
  313. (match obj
  314. ((or #t #f () #nil (? number?) (? eof-object?)
  315. (? unspecified?) (? char?) (? string?))
  316. (write obj port))
  317. ((? hoot-complex?)
  318. (let ((real (hoot-complex-real obj))
  319. (imag (hoot-complex-imag obj)))
  320. (hoot-print real port)
  321. (when (and (>= imag 0.0) (not (nan? imag)) (not (inf? imag)))
  322. (display "+" port))
  323. (hoot-print imag port)
  324. (display "i" port)))
  325. ((? hoot-fraction?)
  326. (hoot-print (hoot-fraction-num obj) port)
  327. (display "/" port)
  328. (hoot-print (hoot-fraction-denom obj) port))
  329. ((or (? hoot-pair?) (? mutable-hoot-pair?))
  330. (display "(" port)
  331. (hoot-print (hoot-pair-car obj) port)
  332. (let loop ((cdr (hoot-pair-cdr obj)))
  333. (match cdr
  334. (() #t)
  335. ((or (? hoot-pair?) (? mutable-hoot-pair?))
  336. (display " " port)
  337. (hoot-print (hoot-pair-car cdr) port)
  338. (loop (hoot-pair-cdr cdr)))
  339. (obj
  340. (display " . " port)
  341. (hoot-print obj port))))
  342. (display ")" port))
  343. ((or (? hoot-vector?) (? mutable-hoot-vector?))
  344. (let ((k (hoot-vector-length obj)))
  345. (display "#(" port)
  346. (unless (= k 0)
  347. (do ((i 0 (+ i 1)))
  348. ((= i (- k 1)))
  349. (hoot-print (hoot-vector-ref obj i) port)
  350. (display " " port))
  351. (hoot-print (hoot-vector-ref obj (- k 1)) port))
  352. (display ")" port)))
  353. ((or (? hoot-bytevector?) (? mutable-hoot-bytevector?))
  354. (let ((k (hoot-bytevector-length obj)))
  355. (display "#vu8(" port)
  356. (unless (= k 0)
  357. (do ((i 0 (+ i 1)))
  358. ((= i (- k 1)))
  359. (display (hoot-bytevector-ref obj i) port)
  360. (display " " port))
  361. (display (hoot-bytevector-ref obj (- k 1)) port))
  362. (display ")" port)))
  363. ((or (? hoot-bitvector?)
  364. (? mutable-hoot-bitvector?))
  365. (let ((k (hoot-bitvector-length obj)))
  366. (display "#*" port)
  367. (do ((i 0 (+ i 1)))
  368. ((= i k))
  369. (display (hoot-bitvector-ref obj i) port))))
  370. ((? mutable-hoot-string?)
  371. (write (mutable-hoot-string->string obj) port))
  372. ((? hoot-symbol?)
  373. (display (hoot-symbol-name obj) port))
  374. ((? hoot-keyword?)
  375. (format port "#:~a" (hoot-keyword-name obj)))
  376. ((? hoot-procedure?) (display "#<procedure>" port))
  377. ((? hoot-variable?) (display "#<variable>" port))
  378. ((? hoot-atomic-box?) (display "#<atomic-box>" port))
  379. ((? hoot-hash-table?) (display "#<hash-table>" port))
  380. ((? hoot-weak-table?) (display "#<weak-table>" port))
  381. ((? hoot-fluid?) (display "#<fluid>" port))
  382. ((? hoot-dynamic-state?) (display "#<dynamic-state>" port))
  383. ((? hoot-syntax?) (display "#<syntax>" port))
  384. ((? hoot-port?) (display "#<port>" port))
  385. ((? hoot-struct?) (display "#<struct>" port))))
  386. (define (hoot-print-record obj port)
  387. (display "#<hoot " port)
  388. (hoot-print obj port)
  389. (display ">" port))
  390. (for-each (lambda (rtd) (set-record-type-printer! rtd hoot-print-record))
  391. (list <hoot-complex>
  392. <hoot-fraction>
  393. <hoot-pair>
  394. <mutable-hoot-pair>
  395. <hoot-vector>
  396. <mutable-hoot-vector>
  397. <hoot-bytevector>
  398. <mutable-hoot-bytevector>
  399. <hoot-bitvector>
  400. <mutable-hoot-bitvector>
  401. <mutable-hoot-string>
  402. <hoot-procedure>
  403. <hoot-symbol>
  404. <hoot-keyword>
  405. <hoot-variable>
  406. <hoot-atomic-box>
  407. <hoot-hash-table>
  408. <hoot-weak-table>
  409. <hoot-fluid>
  410. <hoot-dynamic-state>
  411. <hoot-syntax>
  412. <hoot-port>
  413. <hoot-struct>))
  414. (define (wasm->guile reflector x)
  415. (match (~ reflector "describe" x)
  416. ("fixnum" (~ reflector "fixnum_value" x))
  417. ("char" (integer->char (~ reflector "char_value" x)))
  418. ("string" (~ reflector "string_value" x))
  419. ("mutable-string" (make-mutable-hoot-string reflector x))
  420. ("true" #t)
  421. ("false" #f)
  422. ("eof" (eof-object))
  423. ("nil" #nil)
  424. ("null" '())
  425. ("unspecified" *unspecified*)
  426. ("flonum" (~ reflector "flonum_value" x))
  427. ("bignum" (~ reflector "bignum_value" x))
  428. ("complex"
  429. (make-hoot-complex reflector x
  430. (~ reflector "complex_real" x)
  431. (~ reflector "complex_imag" x)))
  432. ("fraction"
  433. (make-hoot-fraction reflector x
  434. (wasm->guile reflector (~ reflector "fraction_num" x))
  435. (wasm->guile reflector (~ reflector "fraction_denom" x))))
  436. ("symbol" (make-hoot-symbol reflector x))
  437. ("keyword" (make-hoot-keyword reflector x))
  438. ("pair" (make-hoot-pair reflector x))
  439. ("mutable-pair" (make-mutable-hoot-pair reflector x))
  440. ("vector" (make-hoot-vector reflector x))
  441. ("mutable-vector" (make-mutable-hoot-vector reflector x))
  442. ("bytevector" (make-hoot-bytevector reflector x))
  443. ("mutable-bytevector" (make-mutable-hoot-bytevector reflector x))
  444. ("bitvector" (make-hoot-bitvector reflector x))
  445. ("mutable-bitvector" (make-mutable-hoot-bitvector reflector x))
  446. ("procedure" (make-hoot-procedure reflector x))
  447. ("variable" (make-hoot-variable reflector x))
  448. ("atomic-box" (make-hoot-atomic-box reflector x))
  449. ("hash-table" (make-hoot-hash-table reflector x))
  450. ("weak-table" (make-hoot-weak-table reflector x))
  451. ("fluid" (make-hoot-fluid reflector x))
  452. ("dynamic-state" (make-hoot-dynamic-state reflector x))
  453. ("syntax" (make-hoot-syntax reflector x))
  454. ("port" (make-hoot-port reflector x))
  455. ("struct" (make-hoot-struct reflector x))
  456. ("extern-ref" (~ reflector "extern_value" x))))
  457. (define (guile->wasm reflector x)
  458. (match x
  459. ((and (? number?) (? inexact?)) (~ reflector "scm_from_f64" x))
  460. ((? exact-integer?)
  461. (if (<= (~ reflector "scm_most_negative_fixnum")
  462. x
  463. (~ reflector "scm_most_positive_fixnum"))
  464. (~ reflector "scm_from_fixnum" x)
  465. (~ reflector "scm_from_bignum" x)))
  466. ((and (? number?) (? exact?)) (~ reflector "scm_from_fraction" (numerator x) (denominator x)))
  467. ((? complex?) (~ reflector "scm_from_complex" (real-part x) (imag-part x)))
  468. (#t (~ reflector "scm_true"))
  469. (#f (~ reflector "scm_false"))
  470. (#nil (~ reflector "scm_nil"))
  471. (() (~ reflector "scm_null"))
  472. ((? unspecified?) (~ reflector "scm_unspecified"))
  473. ((? eof-object?) (~ reflector "scm_eof"))
  474. ((? char?) (~ reflector "scm_from_char" (char->integer x)))
  475. ((? string?) (~ reflector "scm_from_string" x))
  476. ((or ($ <hoot-complex> _ obj)
  477. ($ <hoot-fraction> _ obj)
  478. ($ <hoot-pair> _ obj)
  479. ($ <mutable-hoot-pair> _ obj)
  480. ($ <hoot-vector> _ obj)
  481. ($ <mutable-hoot-vector> _ obj)
  482. ($ <hoot-bytevector> _ obj)
  483. ($ <mutable-hoot-bytevector> _ obj)
  484. ($ <hoot-bitvector> _ obj)
  485. ($ <mutable-hoot-bitvector> _ obj)
  486. ($ <mutable-hoot-string> _ obj)
  487. ($ <hoot-procedure> _ _ obj)
  488. ($ <hoot-symbol> _ obj)
  489. ($ <hoot-keyword> _ obj)
  490. ($ <hoot-variable> _ obj)
  491. ($ <hoot-atomic-box> _ obj)
  492. ($ <hoot-hash-table> _ obj)
  493. ($ <hoot-weak-table> _ obj)
  494. ($ <hoot-fluid> _ obj)
  495. ($ <hoot-dynamic-state> _ obj)
  496. ($ <hoot-syntax> _ obj)
  497. ($ <hoot-port> _ obj)
  498. ($ <hoot-struct> _ obj))
  499. obj)
  500. (_ (~ reflector "scm_from_extern" x))))
  501. (define wasm-array-vector (@@ (wasm vm) wasm-array-vector))
  502. (define make-wasm-array (@@ (wasm vm) make-wasm-array))
  503. (define wasm-array-set! (@@ (wasm vm) wasm-array-set!))
  504. (define $wtf8 (canonicalize-type! (make-array-type #t 'i8)))
  505. (define (wtf8->string wtf8)
  506. (let* ((vec (wasm-array-vector wtf8))
  507. (bv (make-bytevector (vector-length vec))))
  508. (do ((i 0 (+ i 1)))
  509. ((= i (vector-length vec)))
  510. (bytevector-u8-set! bv i (vector-ref vec i)))
  511. (utf8->string bv)))
  512. (define (string->wtf8 str)
  513. (let* ((bv (string->utf8 str))
  514. (array (make-wasm-array $wtf8 (bytevector-length bv) 0)))
  515. (do ((i 0 (+ i 1)))
  516. ((= i (bytevector-length bv)))
  517. (wasm-array-set! array i (bytevector-u8-ref bv i)))
  518. array))
  519. (define (logsub a b)
  520. (logand a (lognot b)))
  521. (define (rsh a b)
  522. (ash a (- b)))
  523. (define-record-type <clock>
  524. (make-clock jiffies-per-second current-jiffy current-second)
  525. clock?
  526. (jiffies-per-second clock-jiffies-per-second)
  527. (current-jiffy %clock-current-jiffy)
  528. (current-second %clock-current-second))
  529. (define (clock-current-jiffy clock)
  530. ((%clock-current-jiffy clock)))
  531. (define (clock-current-second clock)
  532. ((%clock-current-second clock)))
  533. (define real-clock
  534. (make-clock internal-time-units-per-second
  535. get-internal-real-time
  536. current-time))
  537. (define current-clock (make-parameter real-clock))
  538. (define (call-with-fake-clock jiffies-per-second current-jiffy current-second thunk)
  539. (let ((fake (make-clock jiffies-per-second current-jiffy current-second)))
  540. (parameterize ((current-clock fake))
  541. (thunk))))
  542. (define current-scheduler (make-parameter #f))
  543. (define-syntax-rule (assert-scheduler x)
  544. (if (scheduler? x)
  545. x
  546. (raise-exception
  547. (make-exception-with-message "not in async context"))))
  548. (define (async-invoke thunk)
  549. (scheduler-run! (assert-scheduler (current-scheduler)) thunk))
  550. (define (async-invoke-later thunk delay)
  551. (scheduler-delay! (assert-scheduler (current-scheduler)) thunk delay))
  552. (define %runtime-imports
  553. `(("rt" .
  554. (("bignum_from_string" . ,string->number)
  555. ("bignum_from_i32" . ,identity)
  556. ("bignum_from_i64" . ,identity)
  557. ("bignum_from_u64" . ,identity)
  558. ("bignum_to_f64" . ,exact->inexact)
  559. ("bignum_is_i64" . ,s64?)
  560. ("bignum_is_u64" . ,u64?)
  561. ("bignum_get_i64" . ,identity)
  562. ("bignum_add" . ,+)
  563. ("bignum_sub" . ,-)
  564. ("bignum_mul" . ,*)
  565. ("bignum_lsh" . ,ash)
  566. ("bignum_rsh" . ,rsh)
  567. ("bignum_quo" . ,quotient)
  568. ("bignum_rem" . ,remainder)
  569. ("bignum_mod" . ,modulo)
  570. ("bignum_gcd" . ,gcd)
  571. ("bignum_logand" . ,logand)
  572. ("bignum_logior" . ,logior)
  573. ("bignum_logxor" . ,logxor)
  574. ("bignum_logsub" . ,logsub)
  575. ("bignum_lt" . ,<)
  576. ("bignum_le" . ,<=)
  577. ("bignum_eq" . ,=)
  578. ("f64_is_nan" . ,nan?)
  579. ("f64_is_infinite" . ,inf?)
  580. ("flonum_to_string" . ,number->string)
  581. ("string_upcase" . ,string-upcase)
  582. ("string_downcase" . ,string-downcase)
  583. ("make_weak_map" . ,make-weak-key-hash-table)
  584. ("weak_map_get" . ,hashq-ref)
  585. ("weak_map_set" . ,hashq-set!)
  586. ("weak_map_delete" . ,hashq-remove!)
  587. ("fsqrt" . ,sqrt)
  588. ("fsin" . ,sin)
  589. ("fcos" . ,cos)
  590. ("ftan" . ,tan)
  591. ("fasin" . ,asin)
  592. ("facos" . ,acos)
  593. ("fatan" . ,atan)
  594. ("fatan2" . ,atan)
  595. ("flog" . ,log)
  596. ("fexp" . ,exp)
  597. ("jiffies_per_second" . ,(lambda ()
  598. (clock-jiffies-per-second (current-clock))))
  599. ("current_jiffy" . ,(lambda ()
  600. (clock-current-jiffy (current-clock))))
  601. ("current_second" . ,(lambda ()
  602. (exact->inexact
  603. (clock-current-second (current-clock)))))
  604. ("async_invoke" . ,async-invoke)
  605. ("async_invoke_later" . ,async-invoke-later)
  606. ("promise_on_completed" . ,on)
  607. ("promise_complete" . ,(lambda (callback val) (callback val)))
  608. ("wtf8_to_string" . ,wtf8->string)
  609. ("string_to_wtf8" . ,string->wtf8)
  610. ("die" . ,(lambda (key . args)
  611. (apply throw (string->symbol key) args)))))
  612. ("io" .
  613. (("write_stdout" . ,(lambda (str)
  614. (put-string (current-output-port) str)
  615. (force-output (current-output-port))))
  616. ("write_stderr" . ,(lambda (str)
  617. (put-string (current-error-port) str)
  618. (force-output (current-error-port))))
  619. ("read_stdin" . ,(lambda () ""))
  620. ("file_exists" . ,file-exists?)
  621. ("open_input_file" . ,(lambda (filename)
  622. (list (open-input-file filename)
  623. (make-bytevector 1024))))
  624. ("open_output_file" . ,(lambda (filename)
  625. (list (open-output-file filename)
  626. (make-bytevector 1024))))
  627. ("close_file" . ,(match-lambda
  628. ((port _) (close-port port))))
  629. ("read_file" . ,(lambda (handle count)
  630. (match handle
  631. ((port bv)
  632. (match (get-bytevector-n! port bv 0 count)
  633. ((? eof-object?) 0)
  634. (n n))))))
  635. ("write_file" . ,(lambda (handle count)
  636. (match handle
  637. ((port bv)
  638. (put-bytevector port bv 0 count)
  639. count))))
  640. ("seek_file" . ,(lambda (handle offset whence)
  641. (match handle
  642. ((port _)
  643. (seek port offset whence)))))
  644. ("file_random_access" . ,(lambda (handle) #t))
  645. ("file_buffer_size" . ,(match-lambda
  646. ((_ bv) (bytevector-length bv))))
  647. ("file_buffer_ref" . ,(lambda (handle i)
  648. (match handle
  649. ((_ bv) (bytevector-u8-ref bv i)))))
  650. ("file_buffer_set" . ,(lambda (handle i x)
  651. (match handle
  652. ((_ bv) (bytevector-u8-set! bv i x)))))
  653. ("delete_file" . ,delete-file)))))
  654. (define (make-abi-imports instance)
  655. `(("abi" . ,(map (lambda (name)
  656. (cons name (wasm-instance-export-ref instance name)))
  657. (wasm-instance-export-names instance)))))
  658. (define* (hoot-instantiate scheme-wasm #:optional (imports '())
  659. (reflector (force reflect-wasm)))
  660. (define (debug-str str)
  661. (format #t "debug: ~a\n" str))
  662. (define (debug-str-i32 str x)
  663. (format #t "debug: ~a: ~s\n" str x))
  664. (define (debug-str-scm str x)
  665. (format #t "debug: ~a: ~s\n" str (wasm->guile reflector x)))
  666. (define debug-imports
  667. `(("debug" .
  668. (("debug_str" . ,debug-str)
  669. ("debug_str_i32" . ,debug-str-i32)
  670. ("debug_str_scm" . ,debug-str-scm)))))
  671. (define (procedure->extern obj)
  672. (wasm->guile reflector obj))
  673. (define ffi-imports
  674. `(("ffi" .
  675. (("procedure_to_extern" . ,procedure->extern)))))
  676. (define (instantiate wasm abi-imports)
  677. (instantiate-wasm (validate-wasm wasm)
  678. #:imports (append imports
  679. abi-imports
  680. debug-imports
  681. ffi-imports)))
  682. ;; You can either pass an existing reflector and import its ABI, or
  683. ;; pass a parsed reflection WASM module and create a new reflector.
  684. (if (reflector? reflector)
  685. (let* ((imports (append %runtime-imports (reflector-abi reflector)))
  686. (instance (instantiate scheme-wasm imports)))
  687. (make-hoot-module reflector instance))
  688. (let* ((instance (instantiate scheme-wasm %runtime-imports))
  689. (abi (make-abi-imports instance))
  690. (imports (append %runtime-imports abi)))
  691. (set! reflector (make-reflector (instantiate reflector imports) abi))
  692. (make-hoot-module reflector instance))))
  693. (define (hoot-call reflector f args)
  694. (let ((argv (~ reflector "make_vector"
  695. (+ (length args) 1)
  696. (~ reflector "scm_false"))))
  697. (~ reflector "vector_set" argv 0 f)
  698. (let loop ((args args) (i 1))
  699. (match args
  700. (() #t)
  701. ((arg . rest)
  702. (~ reflector "vector_set" argv i (guile->wasm reflector arg))
  703. (loop rest (+ i 1)))))
  704. (let* ((results (~ reflector "call" f argv))
  705. (n-results (~ reflector "vector_length" results)))
  706. (apply values
  707. (let loop ((i 0))
  708. (if (= i n-results)
  709. '()
  710. (let ((result (~ reflector "vector_ref" results i)))
  711. (cons (wasm->guile reflector result)
  712. (loop (+ i 1))))))))))
  713. (define (hoot-apply proc . args)
  714. (match proc
  715. (($ <hoot-procedure> _ reflector obj)
  716. (hoot-call reflector obj args))))
  717. (define (hoot-call-async reflector f args)
  718. (let ((scheduler (make-scheduler (%clock-current-jiffy (current-clock)))))
  719. ;; Simple event loop that ticks the scheduler until either the
  720. ;; promise is resolved/rejected or there are no tasks in the
  721. ;; scheduler.
  722. (define (await promise)
  723. (define done? #f)
  724. (define results #f)
  725. (on promise
  726. (lambda vals
  727. (set! done? #t)
  728. (set! results vals))
  729. (match-lambda*
  730. (((? exception? err))
  731. (raise-exception err))
  732. (irritants
  733. (raise-exception
  734. (make-exception (make-exception-with-message "rejected promise")
  735. (make-exception-with-irritants irritants))))))
  736. (let lp ()
  737. (cond
  738. (done?
  739. (apply values results))
  740. ((scheduler-empty? scheduler)
  741. (raise-exception
  742. (make-exception-with-message "awaited promise unresolved")))
  743. (else
  744. (scheduler-tick! scheduler)
  745. (lp)))))
  746. (parameterize ((current-scheduler scheduler))
  747. (await
  748. (make-promise
  749. (lambda (resolve reject)
  750. (hoot-call reflector f
  751. (cons* (lambda (val)
  752. (resolve (wasm->guile reflector val)))
  753. (lambda (err)
  754. (reject (wasm->guile reflector err)))
  755. args))))))))
  756. (define (hoot-apply-async proc . args)
  757. (match proc
  758. (($ <hoot-procedure> _ reflector obj)
  759. (hoot-call-async reflector obj args))))
  760. (define (hoot-load module)
  761. (match module
  762. (($ <hoot-module> reflector instance)
  763. (let* (($load (wasm-instance-export-ref instance "$load")))
  764. ((wasm->guile reflector (wasm-global-ref $load)))))))
  765. (define reflect-wasm
  766. (delay
  767. (call-with-input-file (in-vicinity %reflect-wasm-dir "reflect.wasm")
  768. parse-wasm)))
  769. (define* (compile-value exp #:key
  770. (imports %default-program-imports)
  771. (wasm-imports '())
  772. (load-path '()))
  773. (hoot-load
  774. (hoot-instantiate (compile exp
  775. #:imports imports
  776. #:extend-load-library
  777. (library-load-path-extension load-path))
  778. wasm-imports
  779. (force reflect-wasm))))
  780. (define* (compile-call proc-exp
  781. #:key
  782. (imports %default-program-imports)
  783. (wasm-imports '())
  784. (load-path '())
  785. #:rest rest)
  786. (let* ((extend (library-load-path-extension load-path))
  787. (proc-module (hoot-instantiate (compile proc-exp
  788. #:imports imports
  789. #:extend-load-library extend)
  790. wasm-imports
  791. (force reflect-wasm)))
  792. (proc (hoot-load proc-module))
  793. (reflector (hoot-module-reflector proc-module))
  794. ;; Filter kwargs from argument expressions.
  795. (arg-exps (let loop ((rest rest))
  796. (match rest
  797. (() '())
  798. (((? keyword?) _ . rest)
  799. (loop rest))
  800. ((x . rest)
  801. (cons x (loop rest))))))
  802. (args (map (lambda (exp)
  803. (hoot-load
  804. (hoot-instantiate (compile exp
  805. #:imports imports
  806. #:extend-load-library extend
  807. #:import-abi? #t
  808. #:export-abi? #f)
  809. wasm-imports
  810. reflector)))
  811. arg-exps)))
  812. (apply proc args)))