reflect.scm 26 KB

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