reflect.scm 36 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027
  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 finalization)
  25. #:use-module (hoot promises)
  26. #:use-module (hoot scheduler)
  27. #:use-module (ice-9 match)
  28. #:use-module (ice-9 textual-ports)
  29. #:use-module (ice-9 binary-ports)
  30. #:use-module (ice-9 exceptions)
  31. #:use-module (ice-9 regex)
  32. #:use-module (ice-9 weak-vector)
  33. #:use-module (rnrs bytevectors)
  34. #:use-module (srfi srfi-9)
  35. #:use-module (srfi srfi-9 gnu)
  36. #:use-module (wasm canonical-types)
  37. #:use-module (wasm parse)
  38. #:use-module (wasm types)
  39. #:use-module (wasm vm)
  40. #:export (hoot-object?
  41. hoot-complex?
  42. hoot-complex-real
  43. hoot-complex-imag
  44. hoot-fraction?
  45. hoot-fraction-num
  46. hoot-fraction-denom
  47. hoot-pair?
  48. mutable-hoot-pair?
  49. hoot-pair-car
  50. hoot-pair-cdr
  51. hoot-vector?
  52. mutable-hoot-vector?
  53. hoot-vector-length
  54. hoot-vector-ref
  55. hoot-bytevector?
  56. mutable-hoot-bytevector?
  57. hoot-bytevector-length
  58. hoot-bytevector-ref
  59. hoot-bitvector?
  60. mutable-hoot-bitvector?
  61. hoot-bitvector-length
  62. hoot-bitvector-ref
  63. hoot-symbol?
  64. hoot-symbol-name
  65. hoot-keyword?
  66. hoot-keyword-name
  67. mutable-hoot-string?
  68. mutable-hoot-string->string
  69. hoot-procedure?
  70. hoot-variable?
  71. hoot-atomic-box?
  72. hoot-hash-table?
  73. hoot-weak-table?
  74. hoot-fluid?
  75. hoot-dynamic-state?
  76. hoot-syntax?
  77. hoot-syntax-transformer?
  78. hoot-port?
  79. hoot-struct?
  80. hoot-print
  81. hoot-module?
  82. hoot-module-reflector
  83. hoot-module-instance
  84. reflector?
  85. reflector-instance
  86. reflector-abi
  87. call-with-fake-clock
  88. hoot-instantiate
  89. hoot-apply
  90. hoot-apply-async
  91. hoot-load
  92. compile-call
  93. compile-value))
  94. (define (s64? x)
  95. (and (exact-integer? x) (< (- (ash -1 63) 1) x (ash 1 63))))
  96. (define (u64? x)
  97. (and (exact-integer? x) (< -1 x (- (ash 1 64) 1))))
  98. (define-record-type <reflector>
  99. (make-reflector instance abi)
  100. reflector?
  101. (instance reflector-instance)
  102. (abi reflector-abi))
  103. (set-record-type-printer! <reflector>
  104. (lambda (r port)
  105. (format port "#<reflector instance: ~a>"
  106. (reflector-instance r))))
  107. (define-record-type <hoot-module>
  108. (make-hoot-module reflector instance)
  109. hoot-module?
  110. (reflector hoot-module-reflector)
  111. (instance hoot-module-instance))
  112. (define-record-type <hoot-complex>
  113. (make-hoot-complex reflector obj real imag)
  114. hoot-complex?
  115. (reflector hoot-complex-reflector)
  116. (obj hoot-complex-obj)
  117. (real hoot-complex-real)
  118. (imag hoot-complex-imag))
  119. (define-record-type <hoot-fraction>
  120. (make-hoot-fraction reflector obj num denom)
  121. hoot-fraction?
  122. (reflector hoot-fraction-reflector)
  123. (obj hoot-fraction-obj)
  124. (num hoot-fraction-num)
  125. (denom hoot-fraction-denom))
  126. (define-record-type <hoot-pair>
  127. (make-hoot-pair reflector obj)
  128. hoot-pair?
  129. (reflector hoot-pair-reflector)
  130. (obj hoot-pair-obj))
  131. (define-record-type <mutable-hoot-pair>
  132. (make-mutable-hoot-pair reflector obj)
  133. mutable-hoot-pair?
  134. (reflector mutable-hoot-pair-reflector)
  135. (obj mutable-hoot-pair-obj))
  136. (define-record-type <hoot-vector>
  137. (make-hoot-vector reflector obj)
  138. hoot-vector?
  139. (reflector hoot-vector-reflector)
  140. (obj hoot-vector-obj))
  141. (define-record-type <mutable-hoot-vector>
  142. (make-mutable-hoot-vector reflector obj)
  143. mutable-hoot-vector?
  144. (reflector mutable-hoot-vector-reflector)
  145. (obj mutable-hoot-vector-obj))
  146. (define-record-type <hoot-bytevector>
  147. (make-hoot-bytevector reflector obj)
  148. hoot-bytevector?
  149. (reflector hoot-bytevector-reflector)
  150. (obj hoot-bytevector-obj))
  151. (define-record-type <mutable-hoot-bytevector>
  152. (make-mutable-hoot-bytevector reflector obj)
  153. mutable-hoot-bytevector?
  154. (reflector mutable-hoot-bytevector-reflector)
  155. (obj mutable-hoot-bytevector-obj))
  156. (define-record-type <hoot-bitvector>
  157. (make-hoot-bitvector reflector obj)
  158. hoot-bitvector?
  159. (reflector hoot-bitvector-reflector)
  160. (obj hoot-bitvector-obj))
  161. (define-record-type <mutable-hoot-bitvector>
  162. (make-mutable-hoot-bitvector reflector obj)
  163. mutable-hoot-bitvector?
  164. (reflector mutable-hoot-bitvector-reflector)
  165. (obj mutable-hoot-bitvector-obj))
  166. (define-record-type <mutable-hoot-string>
  167. (make-mutable-hoot-string reflector obj)
  168. mutable-hoot-string?
  169. (reflector mutable-hoot-string-reflector)
  170. (obj mutable-hoot-string-obj))
  171. (define-record-type <hoot-symbol>
  172. (make-hoot-symbol reflector obj)
  173. hoot-symbol?
  174. (reflector hoot-symbol-reflector)
  175. (obj hoot-symbol-obj))
  176. (define-record-type <hoot-keyword>
  177. (make-hoot-keyword reflector obj)
  178. hoot-keyword?
  179. (reflector hoot-keyword-reflector)
  180. (obj hoot-keyword-obj))
  181. (define-record-type <hoot-variable>
  182. (make-hoot-variable reflector obj)
  183. hoot-variable?
  184. (reflector hoot-variable-reflector)
  185. (obj hoot-variable-obj))
  186. (define-record-type <hoot-atomic-box>
  187. (make-hoot-atomic-box reflector obj)
  188. hoot-atomic-box?
  189. (reflector hoot-atomic-box-reflector)
  190. (obj hoot-atomic-box-obj))
  191. (define-record-type <hoot-hash-table>
  192. (make-hoot-hash-table reflector obj)
  193. hoot-hash-table?
  194. (reflector hoot-hash-table-reflector)
  195. (obj hoot-hash-table-obj))
  196. (define-record-type <hoot-weak-table>
  197. (make-hoot-weak-table reflector obj)
  198. hoot-weak-table?
  199. (reflector hoot-weak-table-reflector)
  200. (obj hoot-weak-table-obj))
  201. (define-record-type <hoot-fluid>
  202. (make-hoot-fluid reflector obj)
  203. hoot-fluid?
  204. (reflector hoot-fluid-reflector)
  205. (obj hoot-fluid-obj))
  206. (define-record-type <hoot-dynamic-state>
  207. (make-hoot-dynamic-state reflector obj)
  208. hoot-dynamic-state?
  209. (reflector hoot-dynamic-state-reflector)
  210. (obj hoot-dynamic-state-obj))
  211. (define-record-type <hoot-syntax>
  212. (make-hoot-syntax reflector obj)
  213. hoot-syntax?
  214. (reflector hoot-syntax-reflector)
  215. (obj hoot-syntax-obj))
  216. (define-record-type <hoot-syntax-transformer>
  217. (make-hoot-syntax-transformer reflector obj)
  218. hoot-syntax-transformer?
  219. (reflector hoot-syntax-transformer-reflector)
  220. (obj hoot-syntax-transformer-obj))
  221. (define-record-type <hoot-port>
  222. (make-hoot-port reflector obj)
  223. hoot-port?
  224. (reflector hoot-port-reflector)
  225. (obj hoot-port-obj))
  226. (define-record-type <hoot-struct>
  227. (make-hoot-struct reflector obj)
  228. hoot-struct?
  229. (reflector hoot-struct-reflector)
  230. (obj hoot-struct-obj))
  231. ;; The Hoot procedure type is defined using Guile's low-level struct
  232. ;; API so that we can use applicable structs, allowing Hoot procedures
  233. ;; to be called as if they were native ones.
  234. (define <hoot-procedure>
  235. (make-struct/no-tail <applicable-struct-vtable> 'pwpwpw))
  236. (define (hoot-procedure? obj)
  237. (and (struct? obj) (eq? (struct-vtable obj) <hoot-procedure>)))
  238. (define (make-hoot-procedure reflector obj)
  239. (define (hoot-apply . args)
  240. (hoot-call reflector obj args))
  241. (make-struct/no-tail <hoot-procedure> hoot-apply reflector obj))
  242. (define (hoot-object? obj)
  243. (or (hoot-complex? obj)
  244. (hoot-fraction? obj)
  245. (hoot-pair? obj)
  246. (mutable-hoot-pair? obj)
  247. (hoot-vector? obj)
  248. (mutable-hoot-vector? obj)
  249. (hoot-bytevector? obj)
  250. (mutable-hoot-bytevector? obj)
  251. (hoot-bitvector? obj)
  252. (mutable-hoot-bitvector? obj)
  253. (mutable-hoot-string? obj)
  254. (hoot-procedure? obj)
  255. (hoot-symbol? obj)
  256. (hoot-keyword? obj)
  257. (hoot-variable? obj)
  258. (hoot-atomic-box? obj)
  259. (hoot-hash-table? obj)
  260. (hoot-weak-table? obj)
  261. (hoot-fluid? obj)
  262. (hoot-dynamic-state? obj)
  263. (hoot-syntax? obj)
  264. (hoot-syntax-transformer? obj)
  265. (hoot-port? obj)
  266. (hoot-struct? obj)))
  267. (define-syntax-rule (~ reflector name args ...)
  268. ((wasm-instance-export-ref (reflector-instance reflector) name) args ...))
  269. (define (hoot-pair-car pair)
  270. (match pair
  271. ((or ($ <hoot-pair> reflector obj)
  272. ($ <mutable-hoot-pair> reflector obj))
  273. (wasm->guile reflector (~ reflector "car" obj)))))
  274. (define (hoot-pair-cdr pair)
  275. (match pair
  276. ((or ($ <hoot-pair> reflector obj)
  277. ($ <mutable-hoot-pair> reflector obj))
  278. (wasm->guile reflector (~ reflector "cdr" obj)))))
  279. (define (hoot-vector-length vec)
  280. (match vec
  281. ((or ($ <hoot-vector> reflector obj)
  282. ($ <mutable-hoot-vector> reflector obj))
  283. (~ reflector "vector_length" obj))))
  284. (define (hoot-vector-ref vec idx)
  285. (match vec
  286. ((or ($ <hoot-vector> reflector obj)
  287. ($ <mutable-hoot-vector> reflector obj))
  288. (wasm->guile reflector (~ reflector "vector_ref" obj idx)))))
  289. (define (hoot-bytevector-length bv)
  290. (match bv
  291. ((or ($ <hoot-bytevector> reflector obj)
  292. ($ <mutable-hoot-bytevector> reflector obj))
  293. (~ reflector "bytevector_length" obj))))
  294. (define (hoot-bytevector-ref bv idx)
  295. (match bv
  296. ((or ($ <hoot-bytevector> reflector obj)
  297. ($ <mutable-hoot-bytevector> reflector obj))
  298. (~ reflector "bytevector_ref" obj idx))))
  299. (define (hoot-bitvector-length bv)
  300. (match bv
  301. ((or ($ <hoot-bitvector> reflector obj)
  302. ($ <mutable-hoot-bitvector> reflector obj))
  303. (~ reflector "bitvector_length" obj))))
  304. (define (hoot-bitvector-ref bv idx)
  305. (match bv
  306. ((or ($ <hoot-bitvector> reflector obj)
  307. ($ <mutable-hoot-bitvector> reflector obj))
  308. (~ reflector "bitvector_ref" obj idx))))
  309. (define (hoot-symbol-name sym)
  310. (match sym
  311. (($ <hoot-symbol> reflector obj)
  312. (~ reflector "symbol_name" obj))))
  313. (define (hoot-keyword-name kw)
  314. (match kw
  315. (($ <hoot-keyword> reflector obj)
  316. (~ reflector "keyword_name" obj))))
  317. (define (mutable-hoot-string->string str)
  318. (match str
  319. (($ <mutable-hoot-string> reflector obj)
  320. (~ reflector "string_value" obj))))
  321. ;; UH OH: This doesn't detect cycles!
  322. (define (hoot-print obj port)
  323. (match obj
  324. ((or #t #f () #nil (? number?) (? eof-object?)
  325. (? unspecified?) (? char?) (? string?))
  326. (write obj port))
  327. ((? hoot-complex?)
  328. (let ((real (hoot-complex-real obj))
  329. (imag (hoot-complex-imag obj)))
  330. (hoot-print real port)
  331. (when (and (>= imag 0.0) (not (nan? imag)) (not (inf? imag)))
  332. (display "+" port))
  333. (hoot-print imag port)
  334. (display "i" port)))
  335. ((? hoot-fraction?)
  336. (hoot-print (hoot-fraction-num obj) port)
  337. (display "/" port)
  338. (hoot-print (hoot-fraction-denom obj) port))
  339. ((or (? hoot-pair?) (? mutable-hoot-pair?))
  340. (display "(" port)
  341. (hoot-print (hoot-pair-car obj) port)
  342. (let loop ((cdr (hoot-pair-cdr obj)))
  343. (match cdr
  344. (() #t)
  345. ((or (? hoot-pair?) (? mutable-hoot-pair?))
  346. (display " " port)
  347. (hoot-print (hoot-pair-car cdr) port)
  348. (loop (hoot-pair-cdr cdr)))
  349. (obj
  350. (display " . " port)
  351. (hoot-print obj port))))
  352. (display ")" port))
  353. ((or (? hoot-vector?) (? mutable-hoot-vector?))
  354. (let ((k (hoot-vector-length obj)))
  355. (display "#(" port)
  356. (unless (= k 0)
  357. (do ((i 0 (+ i 1)))
  358. ((= i (- k 1)))
  359. (hoot-print (hoot-vector-ref obj i) port)
  360. (display " " port))
  361. (hoot-print (hoot-vector-ref obj (- k 1)) port))
  362. (display ")" port)))
  363. ((or (? hoot-bytevector?) (? mutable-hoot-bytevector?))
  364. (let ((k (hoot-bytevector-length obj)))
  365. (display "#vu8(" port)
  366. (unless (= k 0)
  367. (do ((i 0 (+ i 1)))
  368. ((= i (- k 1)))
  369. (display (hoot-bytevector-ref obj i) port)
  370. (display " " port))
  371. (display (hoot-bytevector-ref obj (- k 1)) port))
  372. (display ")" port)))
  373. ((or (? hoot-bitvector?)
  374. (? mutable-hoot-bitvector?))
  375. (let ((k (hoot-bitvector-length obj)))
  376. (display "#*" port)
  377. (do ((i 0 (+ i 1)))
  378. ((= i k))
  379. (display (hoot-bitvector-ref obj i) port))))
  380. ((? mutable-hoot-string?)
  381. (write (mutable-hoot-string->string obj) port))
  382. ((? hoot-symbol?)
  383. (display (hoot-symbol-name obj) port))
  384. ((? hoot-keyword?)
  385. (format port "#:~a" (hoot-keyword-name obj)))
  386. ((? hoot-procedure?) (display "#<procedure>" port))
  387. ((? hoot-variable?) (display "#<variable>" port))
  388. ((? hoot-atomic-box?) (display "#<atomic-box>" port))
  389. ((? hoot-hash-table?) (display "#<hash-table>" port))
  390. ((? hoot-weak-table?) (display "#<weak-table>" port))
  391. ((? hoot-fluid?) (display "#<fluid>" port))
  392. ((? hoot-dynamic-state?) (display "#<dynamic-state>" port))
  393. ((? hoot-syntax?) (display "#<syntax>" port))
  394. ((? hoot-syntax-transformer?) (display "#<syntax-transformer>" port))
  395. ((? hoot-port?) (display "#<port>" port))
  396. ((? hoot-struct?) (display "#<struct>" port))))
  397. (define (hoot-print-record obj port)
  398. (display "#<hoot " port)
  399. (hoot-print obj port)
  400. (display ">" port))
  401. (for-each (lambda (rtd) (set-record-type-printer! rtd hoot-print-record))
  402. (list <hoot-complex>
  403. <hoot-fraction>
  404. <hoot-pair>
  405. <mutable-hoot-pair>
  406. <hoot-vector>
  407. <mutable-hoot-vector>
  408. <hoot-bytevector>
  409. <mutable-hoot-bytevector>
  410. <hoot-bitvector>
  411. <mutable-hoot-bitvector>
  412. <mutable-hoot-string>
  413. <hoot-procedure>
  414. <hoot-symbol>
  415. <hoot-keyword>
  416. <hoot-variable>
  417. <hoot-atomic-box>
  418. <hoot-hash-table>
  419. <hoot-weak-table>
  420. <hoot-fluid>
  421. <hoot-dynamic-state>
  422. <hoot-syntax>
  423. <hoot-syntax-transformer>
  424. <hoot-port>
  425. <hoot-struct>))
  426. (define (wasm->guile reflector x)
  427. (match (~ reflector "describe" x)
  428. ("fixnum" (~ reflector "fixnum_value" x))
  429. ("char" (integer->char (~ reflector "char_value" x)))
  430. ("string" (~ reflector "string_value" x))
  431. ("mutable-string" (make-mutable-hoot-string reflector x))
  432. ("true" #t)
  433. ("false" #f)
  434. ("eof" (eof-object))
  435. ("nil" #nil)
  436. ("null" '())
  437. ("unspecified" *unspecified*)
  438. ("flonum" (~ reflector "flonum_value" x))
  439. ("bignum" (~ reflector "bignum_value" x))
  440. ("complex"
  441. (make-hoot-complex reflector x
  442. (~ reflector "complex_real" x)
  443. (~ reflector "complex_imag" x)))
  444. ("fraction"
  445. (make-hoot-fraction reflector x
  446. (wasm->guile reflector (~ reflector "fraction_num" x))
  447. (wasm->guile reflector (~ reflector "fraction_denom" x))))
  448. ("symbol" (make-hoot-symbol reflector x))
  449. ("keyword" (make-hoot-keyword reflector x))
  450. ("pair" (make-hoot-pair reflector x))
  451. ("mutable-pair" (make-mutable-hoot-pair reflector x))
  452. ("vector" (make-hoot-vector reflector x))
  453. ("mutable-vector" (make-mutable-hoot-vector reflector x))
  454. ("bytevector" (make-hoot-bytevector reflector x))
  455. ("mutable-bytevector" (make-mutable-hoot-bytevector reflector x))
  456. ("bitvector" (make-hoot-bitvector reflector x))
  457. ("mutable-bitvector" (make-mutable-hoot-bitvector reflector x))
  458. ("procedure" (make-hoot-procedure reflector x))
  459. ("variable" (make-hoot-variable reflector x))
  460. ("atomic-box" (make-hoot-atomic-box reflector x))
  461. ("hash-table" (make-hoot-hash-table reflector x))
  462. ("weak-table" (make-hoot-weak-table reflector x))
  463. ("fluid" (make-hoot-fluid reflector x))
  464. ("dynamic-state" (make-hoot-dynamic-state reflector x))
  465. ("syntax" (make-hoot-syntax reflector x))
  466. ("syntax-transformer" (make-hoot-syntax-transformer reflector x))
  467. ("port" (make-hoot-port reflector x))
  468. ("struct" (make-hoot-struct reflector x))
  469. ("extern-ref" (~ reflector "extern_value" x))
  470. ("func-ref" (~ reflector "func_value" x))))
  471. (define (guile->wasm reflector x)
  472. (match x
  473. ((and (? number?) (? inexact?)) (~ reflector "scm_from_f64" x))
  474. ((? exact-integer?)
  475. (if (<= (~ reflector "scm_most_negative_fixnum")
  476. x
  477. (~ reflector "scm_most_positive_fixnum"))
  478. (~ reflector "scm_from_fixnum" x)
  479. (~ reflector "scm_from_bignum" x)))
  480. ((and (? number?) (? exact?)) (~ reflector "scm_from_fraction" (numerator x) (denominator x)))
  481. ((? complex?) (~ reflector "scm_from_complex" (real-part x) (imag-part x)))
  482. (#t (~ reflector "scm_true"))
  483. (#f (~ reflector "scm_false"))
  484. (() (if (eq? x #nil)
  485. (~ reflector "scm_nil")
  486. (~ reflector "scm_null")))
  487. ((? unspecified?) (~ reflector "scm_unspecified"))
  488. ((? eof-object?) (~ reflector "scm_eof"))
  489. ((? char?) (~ reflector "scm_from_char" (char->integer x)))
  490. ((? string?) (~ reflector "scm_from_string" x))
  491. ((or ($ <hoot-complex> _ obj)
  492. ($ <hoot-fraction> _ obj)
  493. ($ <hoot-pair> _ obj)
  494. ($ <mutable-hoot-pair> _ obj)
  495. ($ <hoot-vector> _ obj)
  496. ($ <mutable-hoot-vector> _ obj)
  497. ($ <hoot-bytevector> _ obj)
  498. ($ <mutable-hoot-bytevector> _ obj)
  499. ($ <hoot-bitvector> _ obj)
  500. ($ <mutable-hoot-bitvector> _ obj)
  501. ($ <mutable-hoot-string> _ obj)
  502. ($ <hoot-procedure> _ _ obj)
  503. ($ <hoot-symbol> _ obj)
  504. ($ <hoot-keyword> _ obj)
  505. ($ <hoot-variable> _ obj)
  506. ($ <hoot-atomic-box> _ obj)
  507. ($ <hoot-hash-table> _ obj)
  508. ($ <hoot-weak-table> _ obj)
  509. ($ <hoot-fluid> _ obj)
  510. ($ <hoot-dynamic-state> _ obj)
  511. ($ <hoot-syntax> _ obj)
  512. ($ <hoot-syntax-transformer> _ obj)
  513. ($ <hoot-port> _ obj)
  514. ($ <hoot-struct> _ obj))
  515. obj)
  516. (_ (~ reflector "scm_from_extern" x))))
  517. (define $wtf8 (canonicalize-type! (make-array-type #t 'i8)))
  518. (define (wtf8->string wtf8)
  519. (let* ((k (wasm-array-length wtf8))
  520. (bv (make-bytevector k)))
  521. (do ((i 0 (+ i 1)))
  522. ((= i k))
  523. (bytevector-u8-set! bv i (wasm-array-ref-unsigned wtf8 i)))
  524. (utf8->string bv)))
  525. (define (string->wtf8 str)
  526. (let* ((bv (string->utf8 str))
  527. (k (bytevector-length bv))
  528. (array (make-wasm-array $wtf8 k 0)))
  529. (do ((i 0 (+ i 1)))
  530. ((= i k))
  531. (wasm-array-set! array i (bytevector-u8-ref bv i)))
  532. array))
  533. (define (rsh a b)
  534. (ash a (- b)))
  535. (define (bignum->i64 x)
  536. (max (min x (1- (ash 1 63))) (ash -1 63)))
  537. (define (u64->bignum x)
  538. (logand x #xffffFFFFffffFFFF))
  539. (define-record-type <clock>
  540. (make-clock jiffies-per-second current-jiffy current-second)
  541. clock?
  542. (jiffies-per-second clock-jiffies-per-second)
  543. (current-jiffy %clock-current-jiffy)
  544. (current-second %clock-current-second))
  545. (define (clock-current-jiffy clock)
  546. ((%clock-current-jiffy clock)))
  547. (define (clock-current-second clock)
  548. ((%clock-current-second clock)))
  549. (define real-clock
  550. (make-clock internal-time-units-per-second
  551. get-internal-real-time
  552. current-time))
  553. (define current-clock (make-parameter real-clock))
  554. (define (call-with-fake-clock jiffies-per-second current-jiffy current-second thunk)
  555. (let ((fake (make-clock jiffies-per-second current-jiffy current-second)))
  556. (parameterize ((current-clock fake))
  557. (thunk))))
  558. (define current-scheduler (make-parameter #f))
  559. (define-syntax-rule (assert-scheduler x)
  560. (if (scheduler? x)
  561. x
  562. (raise-exception
  563. (make-exception-with-message "not in async context"))))
  564. (define (async-invoke thunk)
  565. (scheduler-run! (assert-scheduler (current-scheduler)) thunk))
  566. (define (async-invoke-later thunk delay)
  567. (scheduler-delay! (assert-scheduler (current-scheduler)) thunk delay))
  568. (define (make-regexp* pattern flags)
  569. (let ((flags (map (match-lambda
  570. (#\i regexp/icase)
  571. (#\m regexp/newline))
  572. (string->list flags))))
  573. (apply make-regexp pattern flags)))
  574. (define (async-read port)
  575. (make-promise
  576. (lambda (resolve reject)
  577. (scheduler-run! (assert-scheduler (current-scheduler))
  578. (lambda ()
  579. (match (get-bytevector-some port)
  580. ((? eof-object?)
  581. (resolve #vu8()))
  582. (bv (resolve bv))))))))
  583. (define (async-write port bv)
  584. (make-promise
  585. (lambda (resolve reject)
  586. (scheduler-run! (assert-scheduler (current-scheduler))
  587. (lambda ()
  588. (put-bytevector port bv)
  589. (force-output port)
  590. (resolve #t))))))
  591. (define (async-close port)
  592. (make-promise
  593. (lambda (resolve reject)
  594. (scheduler-run! (assert-scheduler (current-scheduler))
  595. (lambda ()
  596. (close port)
  597. (resolve #t))))))
  598. (define %runtime-imports
  599. `(("rt" .
  600. (("bignum_from_string" . ,string->number)
  601. ("bignum_from_i32" . ,identity)
  602. ("bignum_from_i64" . ,identity)
  603. ("bignum_from_u64" . ,u64->bignum)
  604. ("bignum_to_f64" . ,exact->inexact)
  605. ("bignum_is_i64" . ,s64?)
  606. ("bignum_is_u64" . ,u64?)
  607. ("bignum_get_i64" . ,bignum->i64)
  608. ("bignum_add" . ,+)
  609. ("bignum_sub" . ,-)
  610. ("bignum_mul" . ,*)
  611. ("bignum_lsh" . ,ash)
  612. ("bignum_rsh" . ,rsh)
  613. ("bignum_quo" . ,quotient)
  614. ("bignum_rem" . ,remainder)
  615. ("bignum_mod" . ,modulo)
  616. ("bignum_gcd" . ,gcd)
  617. ("bignum_logand" . ,logand)
  618. ("bignum_logior" . ,logior)
  619. ("bignum_logxor" . ,logxor)
  620. ("bignum_lt" . ,<)
  621. ("bignum_le" . ,<=)
  622. ("bignum_eq" . ,=)
  623. ("flonum_to_string" . ,number->string)
  624. ("string_upcase" . ,string-upcase)
  625. ("string_downcase" . ,string-downcase)
  626. ("make_weak_ref" . ,weak-vector)
  627. ("weak_ref_deref" . ,(lambda (ref fail)
  628. (or (weak-vector-ref ref 0) fail)))
  629. ("make_weak_map" . ,make-weak-key-hash-table)
  630. ("weak_map_get" . ,hashq-ref)
  631. ("weak_map_set" . ,hashq-set!)
  632. ("weak_map_delete" . ,hashq-remove!)
  633. ("fsqrt" . ,sqrt)
  634. ("fsin" . ,sin)
  635. ("fcos" . ,cos)
  636. ("ftan" . ,tan)
  637. ("fasin" . ,asin)
  638. ("facos" . ,acos)
  639. ("fatan" . ,atan)
  640. ("fatan2" . ,atan)
  641. ("flog" . ,log)
  642. ("fexp" . ,exp)
  643. ("jiffies_per_second" . ,(lambda ()
  644. (clock-jiffies-per-second (current-clock))))
  645. ("current_jiffy" . ,(lambda ()
  646. (clock-current-jiffy (current-clock))))
  647. ("current_second" . ,(lambda ()
  648. (exact->inexact
  649. (clock-current-second (current-clock)))))
  650. ("async_invoke" . ,async-invoke)
  651. ("async_invoke_later" . ,async-invoke-later)
  652. ("promise_on_completed" . ,on)
  653. ("promise_complete" . ,(lambda (callback val) (callback val)))
  654. ("wtf8_to_string" . ,wtf8->string)
  655. ("string_to_wtf8" . ,string->wtf8)
  656. ("make_regexp" . ,make-regexp*)
  657. ("regexp_exec" . ,regexp-exec)
  658. ("regexp_match_string" . ,match:string)
  659. ("regexp_match_start" . ,match:start)
  660. ("regexp_match_end" . ,match:end)
  661. ("regexp_match_count" . ,match:count)
  662. ("regexp_match_substring" . ,match:substring)
  663. ("die" . ,(lambda (key . args)
  664. (apply throw (string->symbol key) args)))
  665. ("quit" . ,(lambda (status) (error "Hoot exited with status" status)))
  666. ("stream_make_chunk" . ,(lambda (len) (make-bytevector len)))
  667. ("stream_chunk_length" . ,(lambda (bv) (bytevector-length bv)))
  668. ("stream_chunk_ref" . ,(lambda (bv idx) (bytevector-u8-ref bv idx)))
  669. ("stream_chunk_set" . ,(lambda (bv idx val) (bytevector-u8-set! bv idx val)))
  670. ("stream_get_reader" . ,(lambda (port) port))
  671. ("stream_read" . ,async-read)
  672. ("stream_result_chunk" . ,(lambda (ret) ret))
  673. ("stream_result_done" . ,(lambda (ret) (if (zero? (bytevector-length ret)) 1 0)))
  674. ("stream_get_writer" . ,(lambda (port) port))
  675. ("stream_write" . ,async-write)
  676. ("stream_close_writer" . ,async-close)))
  677. ("io" .
  678. (("write_stdout" . ,(lambda (str)
  679. (put-string (current-output-port) str)
  680. (force-output (current-output-port))))
  681. ("write_stderr" . ,(lambda (str)
  682. (put-string (current-error-port) str)
  683. (force-output (current-error-port))))
  684. ("read_stdin" . ,(lambda ()
  685. (match (get-line (current-input-port))
  686. ((? eof-object?) "")
  687. (line (string-append line "\n")))))
  688. ("file_exists" . ,file-exists?)
  689. ("open_input_file" . ,(lambda (filename)
  690. (list (open-input-file filename)
  691. (make-bytevector 1024))))
  692. ("open_output_file" . ,(lambda (filename)
  693. (list (open-output-file filename)
  694. (make-bytevector 1024))))
  695. ("close_file" . ,(match-lambda
  696. ((port _) (close-port port))))
  697. ("read_file" . ,(lambda (handle count)
  698. (match handle
  699. ((port bv)
  700. (match (get-bytevector-n! port bv 0 count)
  701. ((? eof-object?) 0)
  702. (n n))))))
  703. ("write_file" . ,(lambda (handle count)
  704. (match handle
  705. ((port bv)
  706. (put-bytevector port bv 0 count)
  707. count))))
  708. ("seek_file" . ,(lambda (handle offset whence)
  709. (match handle
  710. ((port _)
  711. (seek port offset whence)))))
  712. ("file_random_access" . ,(lambda (handle) #t))
  713. ("file_buffer_size" . ,(match-lambda
  714. ((_ bv) (bytevector-length bv))))
  715. ("file_buffer_ref" . ,(lambda (handle i)
  716. (match handle
  717. ((_ bv) (bytevector-u8-ref bv i)))))
  718. ("file_buffer_set" . ,(lambda (handle i x)
  719. (match handle
  720. ((_ bv) (bytevector-u8-set! bv i x)))))
  721. ("delete_file" . ,delete-file)
  722. ("stream_stdin" . ,(lambda () (current-input-port)))
  723. ("stream_stdout" . ,(lambda () (current-output-port)))
  724. ("stream_stderr" . ,(lambda () (current-error-port)))))))
  725. (define (make-abi-imports instance)
  726. `(("abi" . ,(map (lambda (name)
  727. (cons name (wasm-instance-export-ref instance name)))
  728. (wasm-instance-export-names instance)))))
  729. (define *all-instances* (make-weak-key-hash-table))
  730. (define (all-instances)
  731. (hash-map->list (lambda (k v) k) *all-instances*))
  732. (define (code-origin code)
  733. ;; O(n) and not cached, as there is a cycle between instances and
  734. ;; their funcs, and Guile doesn't currently have ephemeron tables.
  735. (let check-instances ((instances (all-instances)))
  736. (match instances
  737. (() (values #f #f))
  738. ((instance . instances)
  739. (let ((get-code (wasm-instance-export-ref instance "%instance-code")))
  740. (if get-code
  741. (let check-funcs ((i 0))
  742. (match (get-code i)
  743. ((? wasm-null?) (check-instances instances))
  744. (func (if (equal? func code)
  745. (values instance i)
  746. (check-funcs (1+ i))))))
  747. (values #f #f)))))))
  748. (define (code-meta code getter not-found)
  749. ;; O(n) and not cached, as there is a cycle between instances and
  750. ;; their funcs, and Guile doesn't currently have ephemeron tables.
  751. (call-with-values (lambda () (code-origin code))
  752. (lambda (instance idx)
  753. (if instance
  754. (match (wasm-instance-export-ref instance getter)
  755. (#f (not-found))
  756. (getter (getter idx)))
  757. (not-found)))))
  758. (define (code-name code)
  759. (code-meta code "%instance-code-name" (lambda () #f)))
  760. (define (code-source code)
  761. (code-meta code "%instance-code-source" (lambda () (values #f 0 0))))
  762. (define *finalization-registries* (make-weak-key-hash-table))
  763. (define (poll-finalization-registries!)
  764. (hash-for-each (lambda (registry _)
  765. (poll-finalization-registry! registry))
  766. *finalization-registries*))
  767. (define* (hoot-instantiate scheme-wasm #:optional (imports '())
  768. (reflector (force reflect-wasm)))
  769. (define (debug-str str)
  770. (format #t "debug: ~a\n" str))
  771. (define (debug-str-i32 str x)
  772. (format #t "debug: ~a: ~s\n" str x))
  773. (define (debug-str-scm str x)
  774. (format #t "debug: ~a: ~s\n" str (wasm->guile reflector x)))
  775. (define debug-imports
  776. `(("debug" .
  777. (("debug_str" . ,debug-str)
  778. ("debug_str_i32" . ,debug-str-i32)
  779. ("debug_str_scm" . ,debug-str-scm)
  780. ("code_name" . ,code-name)
  781. ("code_source" . ,code-source)))))
  782. (define (procedure->extern obj)
  783. (wasm->guile reflector obj))
  784. (define ffi-imports
  785. `(("ffi" .
  786. (("procedure_to_extern" . ,procedure->extern)))))
  787. (define (make-finalization-registry* proc)
  788. (let ((registry (make-finalization-registry proc)))
  789. (hashq-set! *finalization-registries* registry #t)
  790. registry))
  791. (define* (finalization-registry-register!* registry obj held-value
  792. #:optional unregister-token)
  793. (finalization-registry-register! registry obj
  794. (wasm->guile reflector held-value)
  795. unregister-token))
  796. (define finalization-imports
  797. `(("finalization" .
  798. (("make_finalization_registry" . ,make-finalization-registry)
  799. ("finalization_registry_register" . ,finalization-registry-register!*)
  800. ("finalization_registry_register_with_token" . ,finalization-registry-register!*)
  801. ("finalization_registry_unregister" . ,finalization-registry-unregister!)))))
  802. (define (instantiate wasm abi-imports)
  803. (instantiate-wasm (validate-wasm wasm)
  804. #:imports (append imports
  805. abi-imports
  806. debug-imports
  807. ffi-imports
  808. finalization-imports)))
  809. (define (instantiate-module)
  810. ;; You can either pass an existing reflector and import its ABI, or
  811. ;; pass a parsed reflection WASM module and create a new reflector.
  812. (if (reflector? reflector)
  813. (let ((imports (append %runtime-imports (reflector-abi reflector))))
  814. (make-hoot-module reflector (instantiate scheme-wasm imports)))
  815. (let* ((instance (instantiate scheme-wasm %runtime-imports))
  816. (abi (make-abi-imports instance))
  817. (imports (append %runtime-imports abi)))
  818. (set! reflector (make-reflector (instantiate reflector imports) abi))
  819. (make-hoot-module reflector instance))))
  820. (let ((module (instantiate-module)))
  821. (hashq-set! *all-instances* (hoot-module-instance module) #t)
  822. module))
  823. (define (hoot-call reflector f args)
  824. (let ((argv (~ reflector "make_vector"
  825. (+ (length args) 1)
  826. (~ reflector "scm_false"))))
  827. (~ reflector "vector_set" argv 0 f)
  828. (let loop ((args args) (i 1))
  829. (match args
  830. (() #t)
  831. ((arg . rest)
  832. (~ reflector "vector_set" argv i (guile->wasm reflector arg))
  833. (loop rest (+ i 1)))))
  834. (let* ((results (~ reflector "call" f argv))
  835. (n-results (~ reflector "vector_length" results)))
  836. (apply values
  837. (let loop ((i 0))
  838. (if (= i n-results)
  839. '()
  840. (let ((result (~ reflector "vector_ref" results i)))
  841. (cons (wasm->guile reflector result)
  842. (loop (+ i 1))))))))))
  843. (define (hoot-apply proc . args)
  844. (match proc
  845. (($ <hoot-procedure> _ reflector obj)
  846. (hoot-call reflector obj args))))
  847. (define (hoot-call-async reflector f args)
  848. (let ((scheduler (make-scheduler (%clock-current-jiffy (current-clock)))))
  849. ;; Simple event loop that ticks the scheduler and polls all of the
  850. ;; live finalization registries until either the promise is
  851. ;; resolved/rejected or there are no tasks in the scheduler.
  852. (define (await promise)
  853. (define done? #f)
  854. (define results #f)
  855. (on promise
  856. (lambda vals
  857. (set! done? #t)
  858. (set! results vals))
  859. (match-lambda*
  860. (((? exception? err))
  861. (raise-exception err))
  862. (irritants
  863. (raise-exception
  864. (make-exception (make-exception-with-message "rejected promise")
  865. (make-exception-with-irritants irritants))))))
  866. (let lp ()
  867. (cond
  868. (done?
  869. (apply values results))
  870. ((scheduler-empty? scheduler)
  871. (raise-exception
  872. (make-exception-with-message "awaited promise unresolved")))
  873. (else
  874. (scheduler-tick! scheduler)
  875. (poll-finalization-registries!)
  876. (lp)))))
  877. (parameterize ((current-scheduler scheduler))
  878. (await
  879. (make-promise
  880. (lambda (resolve reject)
  881. (hoot-call reflector f
  882. (cons* (lambda (val)
  883. (resolve (wasm->guile reflector val)))
  884. (lambda (err)
  885. (reject (wasm->guile reflector err)))
  886. args))))))))
  887. (define (hoot-apply-async proc . args)
  888. (match proc
  889. (($ <hoot-procedure> _ reflector obj)
  890. (hoot-call-async reflector obj args))))
  891. (define (hoot-load module)
  892. (match module
  893. (($ <hoot-module> reflector instance)
  894. (let* (($load (wasm-instance-export-ref instance "$load")))
  895. ((wasm->guile reflector (wasm-global-ref $load)))))))
  896. (define reflect-wasm
  897. (delay
  898. (call-with-input-file (in-vicinity %reflect-wasm-dir "reflect.wasm")
  899. parse-wasm)))
  900. (define* (compile-value exp #:key
  901. (imports %default-program-imports)
  902. (wasm-imports '())
  903. (load-path '()))
  904. (hoot-load
  905. (hoot-instantiate (compile exp
  906. #:imports imports
  907. #:extend-load-library
  908. (library-load-path-extension load-path))
  909. wasm-imports
  910. (force reflect-wasm))))
  911. (define* (compile-call proc-exp
  912. #:key
  913. (imports %default-program-imports)
  914. (wasm-imports '())
  915. (load-path '())
  916. #:rest rest)
  917. (let* ((extend (library-load-path-extension load-path))
  918. (proc-module (hoot-instantiate (compile proc-exp
  919. #:imports imports
  920. #:extend-load-library extend)
  921. wasm-imports
  922. (force reflect-wasm)))
  923. (proc (hoot-load proc-module))
  924. (reflector (hoot-module-reflector proc-module))
  925. ;; Filter kwargs from argument expressions.
  926. (arg-exps (let loop ((rest rest))
  927. (match rest
  928. (() '())
  929. (((? keyword?) _ . rest)
  930. (loop rest))
  931. ((x . rest)
  932. (cons x (loop rest))))))
  933. (args (map (lambda (exp)
  934. (hoot-load
  935. (hoot-instantiate (compile exp
  936. #:imports imports
  937. #:extend-load-library extend
  938. #:import-abi? #t
  939. #:export-abi? #f)
  940. wasm-imports
  941. reflector)))
  942. arg-exps)))
  943. (apply proc args)))