reflect.scm 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019
  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. (#nil (~ reflector "scm_nil"))
  485. (() (~ reflector "scm_null"))
  486. ((? unspecified?) (~ reflector "scm_unspecified"))
  487. ((? eof-object?) (~ reflector "scm_eof"))
  488. ((? char?) (~ reflector "scm_from_char" (char->integer x)))
  489. ((? string?) (~ reflector "scm_from_string" x))
  490. ((or ($ <hoot-complex> _ obj)
  491. ($ <hoot-fraction> _ obj)
  492. ($ <hoot-pair> _ obj)
  493. ($ <mutable-hoot-pair> _ obj)
  494. ($ <hoot-vector> _ obj)
  495. ($ <mutable-hoot-vector> _ obj)
  496. ($ <hoot-bytevector> _ obj)
  497. ($ <mutable-hoot-bytevector> _ obj)
  498. ($ <hoot-bitvector> _ obj)
  499. ($ <mutable-hoot-bitvector> _ obj)
  500. ($ <mutable-hoot-string> _ obj)
  501. ($ <hoot-procedure> _ _ obj)
  502. ($ <hoot-symbol> _ obj)
  503. ($ <hoot-keyword> _ obj)
  504. ($ <hoot-variable> _ obj)
  505. ($ <hoot-atomic-box> _ obj)
  506. ($ <hoot-hash-table> _ obj)
  507. ($ <hoot-weak-table> _ obj)
  508. ($ <hoot-fluid> _ obj)
  509. ($ <hoot-dynamic-state> _ obj)
  510. ($ <hoot-syntax> _ obj)
  511. ($ <hoot-syntax-transformer> _ obj)
  512. ($ <hoot-port> _ obj)
  513. ($ <hoot-struct> _ obj))
  514. obj)
  515. (_ (~ reflector "scm_from_extern" x))))
  516. (define $wtf8 (canonicalize-type! (make-array-type #t 'i8)))
  517. (define (wtf8->string wtf8)
  518. (let* ((k (wasm-array-length wtf8))
  519. (bv (make-bytevector k)))
  520. (do ((i 0 (+ i 1)))
  521. ((= i k))
  522. (bytevector-u8-set! bv i (wasm-array-ref-unsigned wtf8 i)))
  523. (utf8->string bv)))
  524. (define (string->wtf8 str)
  525. (let* ((bv (string->utf8 str))
  526. (k (bytevector-length bv))
  527. (array (make-wasm-array $wtf8 k 0)))
  528. (do ((i 0 (+ i 1)))
  529. ((= i k))
  530. (wasm-array-set! array i (bytevector-u8-ref bv i)))
  531. array))
  532. (define (rsh a b)
  533. (ash a (- b)))
  534. (define (bignum->i64 x)
  535. (max (min x (1- (ash 1 63))) (ash -1 63)))
  536. (define (u64->bignum x)
  537. (logand x #xffffFFFFffffFFFF))
  538. (define-record-type <clock>
  539. (make-clock jiffies-per-second current-jiffy current-second)
  540. clock?
  541. (jiffies-per-second clock-jiffies-per-second)
  542. (current-jiffy %clock-current-jiffy)
  543. (current-second %clock-current-second))
  544. (define (clock-current-jiffy clock)
  545. ((%clock-current-jiffy clock)))
  546. (define (clock-current-second clock)
  547. ((%clock-current-second clock)))
  548. (define real-clock
  549. (make-clock internal-time-units-per-second
  550. get-internal-real-time
  551. current-time))
  552. (define current-clock (make-parameter real-clock))
  553. (define (call-with-fake-clock jiffies-per-second current-jiffy current-second thunk)
  554. (let ((fake (make-clock jiffies-per-second current-jiffy current-second)))
  555. (parameterize ((current-clock fake))
  556. (thunk))))
  557. (define current-scheduler (make-parameter #f))
  558. (define-syntax-rule (assert-scheduler x)
  559. (if (scheduler? x)
  560. x
  561. (raise-exception
  562. (make-exception-with-message "not in async context"))))
  563. (define (async-invoke thunk)
  564. (scheduler-run! (assert-scheduler (current-scheduler)) thunk))
  565. (define (async-invoke-later thunk delay)
  566. (scheduler-delay! (assert-scheduler (current-scheduler)) thunk delay))
  567. (define (make-regexp* pattern flags)
  568. (let ((flags (map (match-lambda
  569. (#\i regexp/icase)
  570. (#\m regexp/newline))
  571. (string->list flags))))
  572. (apply make-regexp pattern flags)))
  573. (define (async-read port)
  574. (make-promise
  575. (lambda (resolve reject)
  576. (scheduler-run! (assert-scheduler (current-scheduler))
  577. (lambda () (resolve (get-bytevector-some port)))))))
  578. (define (async-write port bv)
  579. (make-promise
  580. (lambda (resolve reject)
  581. (scheduler-run! (assert-scheduler (current-scheduler))
  582. (lambda ()
  583. (put-bytevector port bv)
  584. (force-output port)
  585. (resolve #t))))))
  586. (define (async-close port)
  587. (make-promise
  588. (lambda (resolve reject)
  589. (scheduler-run! (assert-scheduler (current-scheduler))
  590. (lambda ()
  591. (close port)
  592. (resolve #t))))))
  593. (define %runtime-imports
  594. `(("rt" .
  595. (("bignum_from_string" . ,string->number)
  596. ("bignum_from_i32" . ,identity)
  597. ("bignum_from_i64" . ,identity)
  598. ("bignum_from_u64" . ,u64->bignum)
  599. ("bignum_to_f64" . ,exact->inexact)
  600. ("bignum_is_i64" . ,s64?)
  601. ("bignum_is_u64" . ,u64?)
  602. ("bignum_get_i64" . ,bignum->i64)
  603. ("bignum_add" . ,+)
  604. ("bignum_sub" . ,-)
  605. ("bignum_mul" . ,*)
  606. ("bignum_lsh" . ,ash)
  607. ("bignum_rsh" . ,rsh)
  608. ("bignum_quo" . ,quotient)
  609. ("bignum_rem" . ,remainder)
  610. ("bignum_mod" . ,modulo)
  611. ("bignum_gcd" . ,gcd)
  612. ("bignum_logand" . ,logand)
  613. ("bignum_logior" . ,logior)
  614. ("bignum_logxor" . ,logxor)
  615. ("bignum_lt" . ,<)
  616. ("bignum_le" . ,<=)
  617. ("bignum_eq" . ,=)
  618. ("flonum_to_string" . ,number->string)
  619. ("string_upcase" . ,string-upcase)
  620. ("string_downcase" . ,string-downcase)
  621. ("make_weak_ref" . ,weak-vector)
  622. ("weak_ref_deref" . ,(lambda (ref fail)
  623. (or (weak-vector-ref ref 0) fail)))
  624. ("make_weak_map" . ,make-weak-key-hash-table)
  625. ("weak_map_get" . ,hashq-ref)
  626. ("weak_map_set" . ,hashq-set!)
  627. ("weak_map_delete" . ,hashq-remove!)
  628. ("fsqrt" . ,sqrt)
  629. ("fsin" . ,sin)
  630. ("fcos" . ,cos)
  631. ("ftan" . ,tan)
  632. ("fasin" . ,asin)
  633. ("facos" . ,acos)
  634. ("fatan" . ,atan)
  635. ("fatan2" . ,atan)
  636. ("flog" . ,log)
  637. ("fexp" . ,exp)
  638. ("jiffies_per_second" . ,(lambda ()
  639. (clock-jiffies-per-second (current-clock))))
  640. ("current_jiffy" . ,(lambda ()
  641. (clock-current-jiffy (current-clock))))
  642. ("current_second" . ,(lambda ()
  643. (exact->inexact
  644. (clock-current-second (current-clock)))))
  645. ("async_invoke" . ,async-invoke)
  646. ("async_invoke_later" . ,async-invoke-later)
  647. ("promise_on_completed" . ,on)
  648. ("promise_complete" . ,(lambda (callback val) (callback val)))
  649. ("wtf8_to_string" . ,wtf8->string)
  650. ("string_to_wtf8" . ,string->wtf8)
  651. ("make_regexp" . ,make-regexp*)
  652. ("regexp_exec" . ,regexp-exec)
  653. ("regexp_match_string" . ,match:string)
  654. ("regexp_match_start" . ,match:start)
  655. ("regexp_match_end" . ,match:end)
  656. ("regexp_match_count" . ,match:count)
  657. ("regexp_match_substring" . ,match:substring)
  658. ("die" . ,(lambda (key . args)
  659. (apply throw (string->symbol key) args)))
  660. ("quit" . ,(lambda (status) (error "Hoot exited with status" status)))
  661. ("stream_make_chunk" . ,(lambda (len) (make-bytevector len)))
  662. ("stream_chunk_length" . ,(lambda (bv) (bytevector-length bv)))
  663. ("stream_chunk_ref" . ,(lambda (bv idx) (bytevector-u8-ref bv idx)))
  664. ("stream_chunk_set" . ,(lambda (bv idx val) (bytevector-u8-set! bv idx val)))
  665. ("stream_get_reader" . ,(lambda (port) port))
  666. ("stream_read" . ,async-read)
  667. ("stream_result_chunk" . ,(lambda (ret) (if (eof-object? ret) #vu8() ret)))
  668. ("stream_result_done" . ,(lambda (ret) (if (eof-object? ret) 1 0)))
  669. ("stream_get_writer" . ,(lambda (port) port))
  670. ("stream_write" . ,async-write)
  671. ("stream_close_writer" . ,async-close)))
  672. ("io" .
  673. (("write_stdout" . ,(lambda (str)
  674. (put-string (current-output-port) str)
  675. (force-output (current-output-port))))
  676. ("write_stderr" . ,(lambda (str)
  677. (put-string (current-error-port) str)
  678. (force-output (current-error-port))))
  679. ("read_stdin" . ,(lambda () ""))
  680. ("file_exists" . ,file-exists?)
  681. ("open_input_file" . ,(lambda (filename)
  682. (list (open-input-file filename)
  683. (make-bytevector 1024))))
  684. ("open_output_file" . ,(lambda (filename)
  685. (list (open-output-file filename)
  686. (make-bytevector 1024))))
  687. ("close_file" . ,(match-lambda
  688. ((port _) (close-port port))))
  689. ("read_file" . ,(lambda (handle count)
  690. (match handle
  691. ((port bv)
  692. (match (get-bytevector-n! port bv 0 count)
  693. ((? eof-object?) 0)
  694. (n n))))))
  695. ("write_file" . ,(lambda (handle count)
  696. (match handle
  697. ((port bv)
  698. (put-bytevector port bv 0 count)
  699. count))))
  700. ("seek_file" . ,(lambda (handle offset whence)
  701. (match handle
  702. ((port _)
  703. (seek port offset whence)))))
  704. ("file_random_access" . ,(lambda (handle) #t))
  705. ("file_buffer_size" . ,(match-lambda
  706. ((_ bv) (bytevector-length bv))))
  707. ("file_buffer_ref" . ,(lambda (handle i)
  708. (match handle
  709. ((_ bv) (bytevector-u8-ref bv i)))))
  710. ("file_buffer_set" . ,(lambda (handle i x)
  711. (match handle
  712. ((_ bv) (bytevector-u8-set! bv i x)))))
  713. ("delete_file" . ,delete-file)
  714. ("stream_stdin" . ,(lambda () (current-input-port)))
  715. ("stream_stdout" . ,(lambda () (current-output-port)))
  716. ("stream_stderr" . ,(lambda () (current-error-port)))))))
  717. (define (make-abi-imports instance)
  718. `(("abi" . ,(map (lambda (name)
  719. (cons name (wasm-instance-export-ref instance name)))
  720. (wasm-instance-export-names instance)))))
  721. (define *all-instances* (make-weak-key-hash-table))
  722. (define (all-instances)
  723. (hash-map->list (lambda (k v) k) *all-instances*))
  724. (define (code-origin code)
  725. ;; O(n) and not cached, as there is a cycle between instances and
  726. ;; their funcs, and Guile doesn't currently have ephemeron tables.
  727. (let check-instances ((instances (all-instances)))
  728. (match instances
  729. (() (values #f #f))
  730. ((instance . instances)
  731. (let ((get-code (wasm-instance-export-ref instance "%instance-code")))
  732. (if get-code
  733. (let check-funcs ((i 0))
  734. (match (get-code i)
  735. ((? wasm-null?) (check-instances instances))
  736. (func (if (equal? func code)
  737. (values instance i)
  738. (check-funcs (1+ i))))))
  739. (values #f #f)))))))
  740. (define (code-meta code getter not-found)
  741. ;; O(n) and not cached, as there is a cycle between instances and
  742. ;; their funcs, and Guile doesn't currently have ephemeron tables.
  743. (call-with-values (lambda () (code-origin code))
  744. (lambda (instance idx)
  745. (if instance
  746. (match (wasm-instance-export-ref instance getter)
  747. (#f (not-found))
  748. (getter (getter idx)))
  749. (not-found)))))
  750. (define (code-name code)
  751. (code-meta code "%instance-code-name" (lambda () #f)))
  752. (define (code-source code)
  753. (code-meta code "%instance-code-source" (lambda () (values #f 0 0))))
  754. (define *finalization-registries* (make-weak-key-hash-table))
  755. (define (poll-finalization-registries!)
  756. (hash-for-each (lambda (registry _)
  757. (poll-finalization-registry! registry))
  758. *finalization-registries*))
  759. (define* (hoot-instantiate scheme-wasm #:optional (imports '())
  760. (reflector (force reflect-wasm)))
  761. (define (debug-str str)
  762. (format #t "debug: ~a\n" str))
  763. (define (debug-str-i32 str x)
  764. (format #t "debug: ~a: ~s\n" str x))
  765. (define (debug-str-scm str x)
  766. (format #t "debug: ~a: ~s\n" str (wasm->guile reflector x)))
  767. (define debug-imports
  768. `(("debug" .
  769. (("debug_str" . ,debug-str)
  770. ("debug_str_i32" . ,debug-str-i32)
  771. ("debug_str_scm" . ,debug-str-scm)
  772. ("code_name" . ,code-name)
  773. ("code_source" . ,code-source)))))
  774. (define (procedure->extern obj)
  775. (wasm->guile reflector obj))
  776. (define ffi-imports
  777. `(("ffi" .
  778. (("procedure_to_extern" . ,procedure->extern)))))
  779. (define (make-finalization-registry* proc)
  780. (let ((registry (make-finalization-registry proc)))
  781. (hashq-set! *finalization-registries* registry #t)
  782. registry))
  783. (define* (finalization-registry-register!* registry obj held-value
  784. #:optional unregister-token)
  785. (finalization-registry-register! registry obj
  786. (wasm->guile reflector held-value)
  787. unregister-token))
  788. (define finalization-imports
  789. `(("finalization" .
  790. (("make_finalization_registry" . ,make-finalization-registry)
  791. ("finalization_registry_register" . ,finalization-registry-register!*)
  792. ("finalization_registry_register_with_token" . ,finalization-registry-register!*)
  793. ("finalization_registry_unregister" . ,finalization-registry-unregister!)))))
  794. (define (instantiate wasm abi-imports)
  795. (instantiate-wasm (validate-wasm wasm)
  796. #:imports (append imports
  797. abi-imports
  798. debug-imports
  799. ffi-imports
  800. finalization-imports)))
  801. (define (instantiate-module)
  802. ;; You can either pass an existing reflector and import its ABI, or
  803. ;; pass a parsed reflection WASM module and create a new reflector.
  804. (if (reflector? reflector)
  805. (let ((imports (append %runtime-imports (reflector-abi reflector))))
  806. (make-hoot-module reflector (instantiate scheme-wasm imports)))
  807. (let* ((instance (instantiate scheme-wasm %runtime-imports))
  808. (abi (make-abi-imports instance))
  809. (imports (append %runtime-imports abi)))
  810. (set! reflector (make-reflector (instantiate reflector imports) abi))
  811. (make-hoot-module reflector instance))))
  812. (let ((module (instantiate-module)))
  813. (hashq-set! *all-instances* (hoot-module-instance module) #t)
  814. module))
  815. (define (hoot-call reflector f args)
  816. (let ((argv (~ reflector "make_vector"
  817. (+ (length args) 1)
  818. (~ reflector "scm_false"))))
  819. (~ reflector "vector_set" argv 0 f)
  820. (let loop ((args args) (i 1))
  821. (match args
  822. (() #t)
  823. ((arg . rest)
  824. (~ reflector "vector_set" argv i (guile->wasm reflector arg))
  825. (loop rest (+ i 1)))))
  826. (let* ((results (~ reflector "call" f argv))
  827. (n-results (~ reflector "vector_length" results)))
  828. (apply values
  829. (let loop ((i 0))
  830. (if (= i n-results)
  831. '()
  832. (let ((result (~ reflector "vector_ref" results i)))
  833. (cons (wasm->guile reflector result)
  834. (loop (+ i 1))))))))))
  835. (define (hoot-apply proc . args)
  836. (match proc
  837. (($ <hoot-procedure> _ reflector obj)
  838. (hoot-call reflector obj args))))
  839. (define (hoot-call-async reflector f args)
  840. (let ((scheduler (make-scheduler (%clock-current-jiffy (current-clock)))))
  841. ;; Simple event loop that ticks the scheduler and polls all of the
  842. ;; live finalization registries until either the promise is
  843. ;; resolved/rejected or there are no tasks in the scheduler.
  844. (define (await promise)
  845. (define done? #f)
  846. (define results #f)
  847. (on promise
  848. (lambda vals
  849. (set! done? #t)
  850. (set! results vals))
  851. (match-lambda*
  852. (((? exception? err))
  853. (raise-exception err))
  854. (irritants
  855. (raise-exception
  856. (make-exception (make-exception-with-message "rejected promise")
  857. (make-exception-with-irritants irritants))))))
  858. (let lp ()
  859. (cond
  860. (done?
  861. (apply values results))
  862. ((scheduler-empty? scheduler)
  863. (raise-exception
  864. (make-exception-with-message "awaited promise unresolved")))
  865. (else
  866. (scheduler-tick! scheduler)
  867. (poll-finalization-registries!)
  868. (lp)))))
  869. (parameterize ((current-scheduler scheduler))
  870. (await
  871. (make-promise
  872. (lambda (resolve reject)
  873. (hoot-call reflector f
  874. (cons* (lambda (val)
  875. (resolve (wasm->guile reflector val)))
  876. (lambda (err)
  877. (reject (wasm->guile reflector err)))
  878. args))))))))
  879. (define (hoot-apply-async proc . args)
  880. (match proc
  881. (($ <hoot-procedure> _ reflector obj)
  882. (hoot-call-async reflector obj args))))
  883. (define (hoot-load module)
  884. (match module
  885. (($ <hoot-module> reflector instance)
  886. (let* (($load (wasm-instance-export-ref instance "$load")))
  887. ((wasm->guile reflector (wasm-global-ref $load)))))))
  888. (define reflect-wasm
  889. (delay
  890. (call-with-input-file (in-vicinity %reflect-wasm-dir "reflect.wasm")
  891. parse-wasm)))
  892. (define* (compile-value exp #:key
  893. (imports %default-program-imports)
  894. (wasm-imports '())
  895. (load-path '()))
  896. (hoot-load
  897. (hoot-instantiate (compile exp
  898. #:imports imports
  899. #:extend-load-library
  900. (library-load-path-extension load-path))
  901. wasm-imports
  902. (force reflect-wasm))))
  903. (define* (compile-call proc-exp
  904. #:key
  905. (imports %default-program-imports)
  906. (wasm-imports '())
  907. (load-path '())
  908. #:rest rest)
  909. (let* ((extend (library-load-path-extension load-path))
  910. (proc-module (hoot-instantiate (compile proc-exp
  911. #:imports imports
  912. #:extend-load-library extend)
  913. wasm-imports
  914. (force reflect-wasm)))
  915. (proc (hoot-load proc-module))
  916. (reflector (hoot-module-reflector proc-module))
  917. ;; Filter kwargs from argument expressions.
  918. (arg-exps (let loop ((rest rest))
  919. (match rest
  920. (() '())
  921. (((? keyword?) _ . rest)
  922. (loop rest))
  923. ((x . rest)
  924. (cons x (loop rest))))))
  925. (args (map (lambda (exp)
  926. (hoot-load
  927. (hoot-instantiate (compile exp
  928. #:imports imports
  929. #:extend-load-library extend
  930. #:import-abi? #t
  931. #:export-abi? #f)
  932. wasm-imports
  933. reflector)))
  934. arg-exps)))
  935. (apply proc args)))