reflect.scm 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  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)
  117. hoot-pair?
  118. (reflector hoot-pair-reflector)
  119. (obj hoot-pair-obj))
  120. (define-record-type <mutable-hoot-pair>
  121. (make-mutable-hoot-pair reflector obj)
  122. mutable-hoot-pair?
  123. (reflector mutable-hoot-pair-reflector)
  124. (obj mutable-hoot-pair-obj))
  125. (define-record-type <hoot-vector>
  126. (make-hoot-vector reflector obj)
  127. hoot-vector?
  128. (reflector hoot-vector-reflector)
  129. (obj hoot-vector-obj))
  130. (define-record-type <mutable-hoot-vector>
  131. (make-mutable-hoot-vector reflector obj)
  132. mutable-hoot-vector?
  133. (reflector mutable-hoot-vector-reflector)
  134. (obj mutable-hoot-vector-obj))
  135. (define-record-type <hoot-bytevector>
  136. (make-hoot-bytevector reflector obj)
  137. hoot-bytevector?
  138. (reflector hoot-bytevector-reflector)
  139. (obj hoot-bytevector-obj))
  140. (define-record-type <mutable-hoot-bytevector>
  141. (make-mutable-hoot-bytevector reflector obj)
  142. mutable-hoot-bytevector?
  143. (reflector mutable-hoot-bytevector-reflector)
  144. (obj mutable-hoot-bytevector-obj))
  145. (define-record-type <hoot-bitvector>
  146. (make-hoot-bitvector reflector obj)
  147. hoot-bitvector?
  148. (reflector hoot-bitvector-reflector)
  149. (obj hoot-bitvector-obj))
  150. (define-record-type <mutable-hoot-bitvector>
  151. (make-mutable-hoot-bitvector reflector obj)
  152. mutable-hoot-bitvector?
  153. (reflector mutable-hoot-bitvector-reflector)
  154. (obj mutable-hoot-bitvector-obj))
  155. (define-record-type <mutable-hoot-string>
  156. (make-mutable-hoot-string reflector obj)
  157. mutable-hoot-string?
  158. (reflector mutable-hoot-string-reflector)
  159. (obj mutable-hoot-string-obj))
  160. (define-record-type <hoot-symbol>
  161. (make-hoot-symbol reflector obj)
  162. hoot-symbol?
  163. (reflector hoot-symbol-reflector)
  164. (obj hoot-symbol-obj))
  165. (define-record-type <hoot-keyword>
  166. (make-hoot-keyword reflector obj)
  167. hoot-keyword?
  168. (reflector hoot-keyword-reflector)
  169. (obj hoot-keyword-obj))
  170. (define-record-type <hoot-variable>
  171. (make-hoot-variable reflector obj)
  172. hoot-variable?
  173. (reflector hoot-variable-reflector)
  174. (obj hoot-variable-obj))
  175. (define-record-type <hoot-atomic-box>
  176. (make-hoot-atomic-box reflector obj)
  177. hoot-atomic-box?
  178. (reflector hoot-atomic-box-reflector)
  179. (obj hoot-atomic-box-obj))
  180. (define-record-type <hoot-hash-table>
  181. (make-hoot-hash-table reflector obj)
  182. hoot-hash-table?
  183. (reflector hoot-hash-table-reflector)
  184. (obj hoot-hash-table-obj))
  185. (define-record-type <hoot-weak-table>
  186. (make-hoot-weak-table reflector obj)
  187. hoot-weak-table?
  188. (reflector hoot-weak-table-reflector)
  189. (obj hoot-weak-table-obj))
  190. (define-record-type <hoot-fluid>
  191. (make-hoot-fluid reflector obj)
  192. hoot-fluid?
  193. (reflector hoot-fluid-reflector)
  194. (obj hoot-fluid-obj))
  195. (define-record-type <hoot-dynamic-state>
  196. (make-hoot-dynamic-state reflector obj)
  197. hoot-dynamic-state?
  198. (reflector hoot-dynamic-state-reflector)
  199. (obj hoot-dynamic-state-obj))
  200. (define-record-type <hoot-syntax>
  201. (make-hoot-syntax reflector obj)
  202. hoot-syntax?
  203. (reflector hoot-syntax-reflector)
  204. (obj hoot-syntax-obj))
  205. (define-record-type <hoot-port>
  206. (make-hoot-port reflector obj)
  207. hoot-port?
  208. (reflector hoot-port-reflector)
  209. (obj hoot-port-obj))
  210. (define-record-type <hoot-struct>
  211. (make-hoot-struct reflector obj)
  212. hoot-struct?
  213. (reflector hoot-struct-reflector)
  214. (obj hoot-struct-obj))
  215. ;; The Hoot procedure type is defined using Guile's low-level struct
  216. ;; API so that we can use applicable structs, allowing Hoot procedures
  217. ;; to be called as if they were native ones.
  218. (define <hoot-procedure>
  219. (make-struct/no-tail <applicable-struct-vtable> 'pwpwpw))
  220. (define (hoot-procedure? obj)
  221. (and (struct? obj) (eq? (struct-vtable obj) <hoot-procedure>)))
  222. (define (make-hoot-procedure reflector obj)
  223. (define (hoot-apply . args)
  224. (hoot-call reflector obj args))
  225. (make-struct/no-tail <hoot-procedure> hoot-apply reflector obj))
  226. (define (hoot-object? obj)
  227. (or (hoot-complex? obj)
  228. (hoot-fraction? obj)
  229. (hoot-pair? obj)
  230. (mutable-hoot-pair? obj)
  231. (hoot-vector? obj)
  232. (mutable-hoot-vector? obj)
  233. (hoot-bytevector? obj)
  234. (mutable-hoot-bytevector? obj)
  235. (hoot-bitvector? obj)
  236. (mutable-hoot-bitvector? obj)
  237. (mutable-hoot-string? obj)
  238. (hoot-procedure? obj)
  239. (hoot-symbol? obj)
  240. (hoot-keyword? obj)
  241. (hoot-variable? obj)
  242. (hoot-atomic-box? obj)
  243. (hoot-hash-table? obj)
  244. (hoot-weak-table? obj)
  245. (hoot-fluid? obj)
  246. (hoot-dynamic-state? obj)
  247. (hoot-syntax? obj)
  248. (hoot-port? obj)
  249. (hoot-struct? obj)))
  250. (define-syntax-rule (~ reflector name args ...)
  251. ((wasm-instance-export-ref (reflector-instance reflector) name) args ...))
  252. (define (hoot-pair-car pair)
  253. (match pair
  254. ((or ($ <hoot-pair> reflector obj)
  255. ($ <mutable-hoot-pair> reflector obj))
  256. (wasm->guile reflector (~ reflector "car" obj)))))
  257. (define (hoot-pair-cdr pair)
  258. (match pair
  259. ((or ($ <hoot-pair> reflector obj)
  260. ($ <mutable-hoot-pair> reflector obj))
  261. (wasm->guile reflector (~ reflector "cdr" obj)))))
  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" (make-hoot-pair reflector x))
  432. ("mutable-pair" (make-mutable-hoot-pair reflector x))
  433. ("vector" (make-hoot-vector reflector x))
  434. ("mutable-vector" (make-mutable-hoot-vector reflector x))
  435. ("bytevector" (make-hoot-bytevector reflector x))
  436. ("mutable-bytevector" (make-mutable-hoot-bytevector reflector x))
  437. ("bitvector" (make-hoot-bitvector reflector x))
  438. ("mutable-bitvector" (make-mutable-hoot-bitvector reflector x))
  439. ("procedure" (make-hoot-procedure reflector x))
  440. ("variable" (make-hoot-variable reflector x))
  441. ("atomic-box" (make-hoot-atomic-box reflector x))
  442. ("hash-table" (make-hoot-hash-table reflector x))
  443. ("weak-table" (make-hoot-weak-table reflector x))
  444. ("fluid" (make-hoot-fluid reflector x))
  445. ("dynamic-state" (make-hoot-dynamic-state reflector x))
  446. ("syntax" (make-hoot-syntax reflector x))
  447. ("port" (make-hoot-port reflector x))
  448. ("struct" (make-hoot-struct reflector x))
  449. ("extern-ref" (~ reflector "extern_value" x))))
  450. (define (guile->wasm reflector x)
  451. (match x
  452. ((and (? number?) (? inexact?)) (~ reflector "scm_from_f64" x))
  453. ((? exact-integer?)
  454. (if (<= (~ reflector "scm_most_negative_fixnum")
  455. x
  456. (~ reflector "scm_most_positive_fixnum"))
  457. (~ reflector "scm_from_fixnum" x)
  458. (~ reflector "scm_from_bignum" x)))
  459. ((and (? number?) (? exact?)) (~ reflector "scm_from_fraction" (numerator x) (denominator x)))
  460. ((? complex?) (~ reflector "scm_from_complex" (real-part x) (imag-part x)))
  461. (#t (~ reflector "scm_true"))
  462. (#f (~ reflector "scm_false"))
  463. (#nil (~ reflector "scm_nil"))
  464. (() (~ reflector "scm_null"))
  465. ((? unspecified?) (~ reflector "scm_unspecified"))
  466. ((? eof-object?) (~ reflector "scm_eof"))
  467. ((? char?) (~ reflector "scm_from_char" (char->integer x)))
  468. ((? string?) (~ reflector "scm_from_string" x))
  469. ((or ($ <hoot-complex> _ obj)
  470. ($ <hoot-fraction> _ obj)
  471. ($ <hoot-pair> _ obj)
  472. ($ <mutable-hoot-pair> _ obj)
  473. ($ <hoot-vector> _ obj)
  474. ($ <mutable-hoot-vector> _ obj)
  475. ($ <hoot-bytevector> _ obj)
  476. ($ <mutable-hoot-bytevector> _ obj)
  477. ($ <hoot-bitvector> _ obj)
  478. ($ <mutable-hoot-bitvector> _ obj)
  479. ($ <mutable-hoot-string> _ obj)
  480. ($ <hoot-procedure> _ _ obj)
  481. ($ <hoot-symbol> _ obj)
  482. ($ <hoot-keyword> _ obj)
  483. ($ <hoot-variable> _ obj)
  484. ($ <hoot-atomic-box> _ obj)
  485. ($ <hoot-hash-table> _ obj)
  486. ($ <hoot-weak-table> _ obj)
  487. ($ <hoot-fluid> _ obj)
  488. ($ <hoot-dynamic-state> _ obj)
  489. ($ <hoot-syntax> _ obj)
  490. ($ <hoot-port> _ obj)
  491. ($ <hoot-struct> _ obj))
  492. obj)
  493. (_ (~ reflector "scm_from_extern" x))))
  494. (define wasm-array-vector (@@ (wasm vm) wasm-array-vector))
  495. (define make-wasm-array (@@ (wasm vm) make-wasm-array))
  496. (define wasm-array-set! (@@ (wasm vm) wasm-array-set!))
  497. (define $wtf8 (canonicalize-type! (make-array-type #t 'i8)))
  498. (define (wtf8->string wtf8)
  499. (let* ((vec (wasm-array-vector wtf8))
  500. (bv (make-bytevector (vector-length vec))))
  501. (do ((i 0 (+ i 1)))
  502. ((= i (vector-length vec)))
  503. (bytevector-u8-set! bv i (vector-ref vec i)))
  504. (utf8->string bv)))
  505. (define (string->wtf8 str)
  506. (let* ((bv (string->utf8 str))
  507. (array (make-wasm-array $wtf8 (bytevector-length bv) 0)))
  508. (do ((i 0 (+ i 1)))
  509. ((= i (bytevector-length bv)))
  510. (wasm-array-set! array i (bytevector-u8-ref bv i)))
  511. array))
  512. (define (logsub a b)
  513. (logand a (lognot b)))
  514. (define (rsh a b)
  515. (ash a (- b)))
  516. (define %runtime-imports
  517. `(("rt" .
  518. (("bignum_from_string" . ,string->number)
  519. ("bignum_from_i32" . ,identity)
  520. ("bignum_from_i64" . ,identity)
  521. ("bignum_from_u64" . ,identity)
  522. ("bignum_to_f64" . ,exact->inexact)
  523. ("bignum_is_i64" . ,s64?)
  524. ("bignum_is_u64" . ,u64?)
  525. ("bignum_get_i64" . ,identity)
  526. ("bignum_add" . ,+)
  527. ("bignum_sub" . ,-)
  528. ("bignum_mul" . ,*)
  529. ("bignum_lsh" . ,ash)
  530. ("bignum_rsh" . ,rsh)
  531. ("bignum_quo" . ,quotient)
  532. ("bignum_rem" . ,remainder)
  533. ("bignum_mod" . ,modulo)
  534. ("bignum_gcd" . ,gcd)
  535. ("bignum_logand" . ,logand)
  536. ("bignum_logior" . ,logior)
  537. ("bignum_logxor" . ,logxor)
  538. ("bignum_logsub" . ,logsub)
  539. ("bignum_lt" . ,<)
  540. ("bignum_le" . ,<=)
  541. ("bignum_eq" . ,=)
  542. ("f64_is_nan" . ,nan?)
  543. ("f64_is_infinite" . ,inf?)
  544. ("flonum_to_string" . ,number->string)
  545. ("string_upcase" . ,string-upcase)
  546. ("string_downcase" . ,string-downcase)
  547. ("make_weak_map" . ,make-weak-key-hash-table)
  548. ("weak_map_get" . ,hash-ref)
  549. ("weak_map_set" . ,hash-set!)
  550. ("weak_map_delete" . ,hash-remove!)
  551. ("fsqrt" . ,sqrt)
  552. ("fsin" . ,sin)
  553. ("fcos" . ,cos)
  554. ("ftan" . ,tan)
  555. ("fasin" . ,asin)
  556. ("facos" . ,acos)
  557. ("fatan" . ,atan)
  558. ("fatan2" . ,atan)
  559. ("flog" . ,log)
  560. ("fexp" . ,exp)
  561. ("jiffies_per_second" . ,(lambda () internal-time-units-per-second))
  562. ("current_jiffy" . ,get-internal-real-time)
  563. ("current_second" . ,(lambda () (exact->inexact (current-time))))
  564. ("wtf8_to_string" . ,wtf8->string)
  565. ("string_to_wtf8" . ,string->wtf8)
  566. ("die" . ,(lambda (key . args)
  567. (apply throw (string->symbol key) args)))))
  568. ("io" .
  569. (("write_stdout" . ,(lambda (str)
  570. (put-string (current-output-port) str)
  571. (force-output (current-output-port))))
  572. ("write_stderr" . ,(lambda (str)
  573. (put-string (current-error-port) str)
  574. (force-output (current-error-port))))
  575. ("read_stdin" . ,(lambda () ""))
  576. ("file_exists" . ,file-exists?)
  577. ("open_input_file" . ,(lambda (filename)
  578. (list (open-input-file filename)
  579. (make-bytevector 1024))))
  580. ("open_output_file" . ,(lambda (filename)
  581. (list (open-output-file filename)
  582. (make-bytevector 1024))))
  583. ("close_file" . ,(match-lambda
  584. ((port _) (close-port port))))
  585. ("read_file" . ,(lambda (handle count)
  586. (match handle
  587. ((port bv)
  588. (match (get-bytevector-n! port bv 0 count)
  589. ((? eof-object?) 0)
  590. (n n))))))
  591. ("write_file" . ,(lambda (handle count)
  592. (match handle
  593. ((port bv)
  594. (put-bytevector port bv 0 count)
  595. count))))
  596. ("seek_file" . ,(lambda (handle offset whence)
  597. (match handle
  598. ((port _)
  599. (seek port offset whence)))))
  600. ("file_random_access" . ,(lambda (handle) #t))
  601. ("file_buffer_size" . ,(match-lambda
  602. ((_ bv) (bytevector-length bv))))
  603. ("file_buffer_ref" . ,(lambda (handle i)
  604. (match handle
  605. ((_ bv) (bytevector-u8-ref bv i)))))
  606. ("file_buffer_set" . ,(lambda (handle i x)
  607. (match handle
  608. ((_ bv) (bytevector-u8-set! bv i x)))))
  609. ("delete_file" . ,delete-file)))))
  610. (define (make-abi-imports instance)
  611. `(("abi" . ,(map (lambda (name)
  612. (cons name (wasm-instance-export-ref instance name)))
  613. (wasm-instance-export-names instance)))))
  614. (define* (hoot-instantiate scheme-wasm #:optional (imports '())
  615. (reflector (force reflect-wasm)))
  616. (define (debug-str str)
  617. (format #t "debug: ~a\n" str))
  618. (define (debug-str-i32 str x)
  619. (format #t "debug: ~a: ~s\n" str x))
  620. (define (debug-str-scm str x)
  621. (format #t "debug: ~a: ~s\n" str (wasm->guile reflector x)))
  622. (define debug-imports
  623. `(("debug" .
  624. (("debug_str" . ,debug-str)
  625. ("debug_str_i32" . ,debug-str-i32)
  626. ("debug_str_scm" . ,debug-str-scm)))))
  627. (define (procedure->extern obj)
  628. (wasm->guile reflector obj))
  629. (define ffi-imports
  630. `(("ffi" .
  631. (("procedure_to_extern" . ,procedure->extern)))))
  632. (define (instantiate wasm abi-imports)
  633. (instantiate-wasm (validate-wasm wasm)
  634. #:imports (append imports
  635. abi-imports
  636. debug-imports
  637. ffi-imports)))
  638. ;; You can either pass an existing reflector and import its ABI, or
  639. ;; pass a parsed reflection WASM module and create a new reflector.
  640. (if (reflector? reflector)
  641. (let* ((imports (append %runtime-imports (reflector-abi reflector)))
  642. (instance (instantiate scheme-wasm imports)))
  643. (make-hoot-module reflector instance))
  644. (let* ((instance (instantiate scheme-wasm %runtime-imports))
  645. (abi (make-abi-imports instance))
  646. (imports (append %runtime-imports abi)))
  647. (set! reflector (make-reflector (instantiate reflector imports) abi))
  648. (make-hoot-module reflector instance))))
  649. (define (hoot-call reflector f args)
  650. (let ((argv (~ reflector "make_vector"
  651. (+ (length args) 1)
  652. (~ reflector "scm_false"))))
  653. (~ reflector "vector_set" argv 0 f)
  654. (let loop ((args args) (i 1))
  655. (match args
  656. (() #t)
  657. ((arg . rest)
  658. (~ reflector "vector_set" argv i (guile->wasm reflector arg))
  659. (loop rest (+ i 1)))))
  660. (let* ((results (~ reflector "call" f argv))
  661. (n-results (~ reflector "vector_length" results)))
  662. (apply values
  663. (let loop ((i 0))
  664. (if (= i n-results)
  665. '()
  666. (let ((result (~ reflector "vector_ref" results i)))
  667. (cons (wasm->guile reflector result)
  668. (loop (+ i 1))))))))))
  669. (define (hoot-load module)
  670. (match module
  671. (($ <hoot-module> reflector instance)
  672. (let* (($load (wasm-instance-export-ref instance "$load")))
  673. ((wasm->guile reflector (wasm-global-ref $load)))))))
  674. (define reflect-wasm
  675. (delay
  676. (call-with-input-file (string-append %hoot-datadir "/js-runtime/reflect.wasm")
  677. parse-wasm)))
  678. (define* (compile-value exp #:key
  679. (imports %default-program-imports)
  680. (wasm-imports '())
  681. (load-path '()))
  682. (hoot-load
  683. (hoot-instantiate (compile exp
  684. #:imports imports
  685. #:extend-load-library
  686. (library-load-path-extension load-path))
  687. wasm-imports
  688. (force reflect-wasm))))
  689. (define* (compile-call proc-exp
  690. #:key
  691. (imports %default-program-imports)
  692. (wasm-imports '())
  693. (load-path '())
  694. #:rest rest)
  695. (let* ((extend (library-load-path-extension load-path))
  696. (proc-module (hoot-instantiate (compile proc-exp
  697. #:imports imports
  698. #:extend-load-library extend)
  699. wasm-imports
  700. (force reflect-wasm)))
  701. (proc (hoot-load proc-module))
  702. (reflector (hoot-module-reflector proc-module))
  703. ;; Filter kwargs from argument expressions.
  704. (arg-exps (let loop ((rest rest))
  705. (match rest
  706. (() '())
  707. (((? keyword?) _ . rest)
  708. (loop rest))
  709. ((x . rest)
  710. (cons x (loop rest))))))
  711. (args (map (lambda (exp)
  712. (hoot-load
  713. (hoot-instantiate (compile exp
  714. #:imports imports
  715. #:extend-load-library extend
  716. #:import-abi? #t
  717. #:export-abi? #f)
  718. wasm-imports
  719. reflector)))
  720. arg-exps)))
  721. (apply proc args)))