vm.scm 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728
  1. ;;; WebAssembly virtual machine
  2. ;;; Copyright (C) 2023 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. ;;; Interpreter for WebAssembly.
  19. ;;;
  20. ;;; Code:
  21. (define-module (wasm vm)
  22. #:use-module (ice-9 binary-ports)
  23. #:use-module (ice-9 exceptions)
  24. #:use-module (ice-9 match)
  25. #:use-module (rnrs bytevectors)
  26. #:use-module (srfi srfi-1)
  27. #:use-module (srfi srfi-9)
  28. #:use-module (srfi srfi-9 gnu)
  29. #:use-module (wasm canonical-types)
  30. #:use-module (wasm parse)
  31. #:use-module (wasm stack)
  32. #:use-module (wasm types)
  33. #:export (validate-wasm
  34. load-and-validate-wasm
  35. validated-wasm?
  36. validated-wasm-ref
  37. make-wasm-global
  38. wasm-global?
  39. wasm-global-ref
  40. wasm-global-set!
  41. wasm-global-mutable?
  42. make-wasm-memory
  43. wasm-memory?
  44. wasm-memory-bytes
  45. wasm-memory-size
  46. wasm-memory-limits
  47. wasm-memory-grow!
  48. make-wasm-table
  49. wasm-table?
  50. wasm-table-size
  51. wasm-table-ref
  52. wasm-table-set!
  53. wasm-table-fill!
  54. wasm-table-copy!
  55. wasm-table-init!
  56. wasm-table-grow!
  57. wasm-stack?
  58. wasm-stack-items
  59. wasm-func?
  60. wasm-null?
  61. wasm-struct?
  62. wasm-array?
  63. instantiate-wasm
  64. wasm-instance?
  65. wasm-instance-module
  66. wasm-instance-export-ref
  67. wasm-instance-export-names
  68. current-instruction-listener
  69. &wasm-error
  70. &wasm-validation-error
  71. wasm-validation-error?
  72. wasm-validation-error-module
  73. &wasm-instance-error
  74. wasm-instance-error?
  75. &wasm-runtime-error
  76. wasm-runtime-error?
  77. wasm-runtime-error-position
  78. wasm-runtime-error-instruction
  79. wasm-runtime-error-instance
  80. wasm-runtime-error-stack
  81. wasm-runtime-error-blocks
  82. wasm-runtime-error-locals))
  83. ;;;
  84. ;;; Types
  85. ;;;
  86. (define (s32? x)
  87. (and (exact-integer? x) (< (- (ash -1 31) 1) x (ash 1 31))))
  88. (define (s31? x)
  89. (and (exact-integer? x) (< (- (ash -1 30) 1) x (ash 1 30))))
  90. (define (u32? x)
  91. (and (exact-integer? x) (< -1 x (- (ash 1 32) 1))))
  92. (define (s8->u8 x)
  93. (logand x #xff))
  94. (define (s8-overflow x)
  95. (centered-remainder x (ash 1 8)))
  96. (define (s16->u16 x)
  97. (logand x #xffff))
  98. (define (s16-overflow x)
  99. (centered-remainder x (ash 1 16)))
  100. (define (s32->u32 x)
  101. (logand x #xffffFFFF))
  102. (define (s31->u31 x)
  103. (logand x #x7fffFFFF))
  104. (define (s32-overflow x)
  105. (centered-remainder x (ash 1 32)))
  106. (define (s64? x)
  107. (and (exact-integer? x) (< (- (ash -1 63) 1) x (ash 1 63))))
  108. (define (u64? x)
  109. (and (exact-integer? x) (< -1 x (- (ash 1 64) 1))))
  110. (define (s64->u64 x)
  111. (logand x #xffffFFFFffffFFFF))
  112. (define (s64-overflow x)
  113. (centered-remainder x (ash 1 64)))
  114. (define (f32? x)
  115. (and (number? x) (or (inexact? x) (exact-integer? x))))
  116. (define (f64? x)
  117. (and (number? x) (or (inexact? x) (exact-integer? x))))
  118. (define (resolve-type type)
  119. (match type
  120. (($ <sub-type> _ _ type) type)
  121. (_ type)))
  122. ;;;
  123. ;;; Validation
  124. ;;;
  125. (define-record-type <validated-wasm>
  126. (make-validated-wasm wasm)
  127. validated-wasm?
  128. (wasm validated-wasm-ref))
  129. (define-exception-type &wasm-error &error
  130. make-wasm-error
  131. wasm-error?)
  132. (define-exception-type &wasm-validation-error &wasm-error
  133. make-wasm-validation-error
  134. wasm-validation-error?
  135. (wasm wasm-validation-error-wasm))
  136. ;; TODO: Trace instruction position within function to give context to
  137. ;; validation errors.
  138. (define (validate-wasm wasm)
  139. (define types
  140. (list->vector
  141. (append-map (match-lambda
  142. (($ <rec-group> (($ <type> _ types) ...)) types)
  143. (($ <type> _ type) (list type)))
  144. (wasm-types wasm))))
  145. (define global-types
  146. (list->vector
  147. (append (filter-map (match-lambda
  148. (($ <import> _ _ 'global _ type) type)
  149. (_ #f))
  150. (wasm-imports wasm))
  151. (map global-type (wasm-globals wasm)))))
  152. (define func-sigs
  153. (list->vector
  154. (append (filter-map
  155. (match-lambda
  156. (($ <import> _ _ 'func _ ($ <type-use> _ sig))
  157. sig)
  158. (_ #f))
  159. (wasm-imports wasm))
  160. (map (match-lambda
  161. (($ <func> _ ($ <type-use> _ sig))
  162. sig))
  163. (wasm-funcs wasm)))))
  164. (define memories
  165. (list->vector
  166. (append (filter-map (match-lambda
  167. (($ <import> _ _ 'memory _ type) type)
  168. (_ #f))
  169. (wasm-imports wasm))
  170. (wasm-memories wasm))))
  171. (define tables
  172. (list->vector
  173. (append (filter-map (match-lambda
  174. (($ <import> _ _ 'table _ type) type)
  175. (_ #f))
  176. (wasm-imports wasm))
  177. (map table-type (wasm-tables wasm)))))
  178. (define elems (list->vector (wasm-elems wasm)))
  179. (define strings (list->vector (wasm-strings wasm)))
  180. (define (validation-error msg . irritants)
  181. (raise-exception
  182. (make-exception
  183. (make-wasm-validation-error wasm)
  184. (make-exception-with-message
  185. (format #f "WASM validation error: ~a" msg))
  186. (make-exception-with-irritants irritants))))
  187. (define (assert-s32 x)
  188. (unless (s32? x)
  189. (validation-error "i32 constant out of range" x)))
  190. (define (assert-s64 x)
  191. (unless (s64? x)
  192. (validation-error "i64 constant out of range" x)))
  193. (define (assert-f32 x)
  194. (unless (f32? x)
  195. (validation-error "f32 constant out of range" x)))
  196. (define (assert-f64 x)
  197. (unless (f64? x)
  198. (validation-error "f64 constant out of range" x)))
  199. (define (check-vector vec id msg)
  200. (unless (< -1 id (vector-length vec))
  201. (validation-error msg id)))
  202. (define (check-func id)
  203. (check-vector func-sigs id "invalid function"))
  204. (define (check-memory id)
  205. (check-vector memories id "invalid memory"))
  206. (define (check-table id)
  207. (check-vector tables id "invalid table"))
  208. (define (check-elem id)
  209. (check-vector elems id "invalid element"))
  210. (define (check-string id)
  211. (check-vector strings id "invalid string"))
  212. (define (assert-preceding-and-immutable-global i k)
  213. (if (< i k)
  214. (when (global-type-mutable? (vector-ref global-types i))
  215. (validation-error "mutable global reference in constant" i))
  216. (validation-error "uninitialized global reference in constant" i)))
  217. (define* (validate-const type instrs #:optional
  218. (global-count (vector-length global-types)))
  219. (define (validate-instr ctx instr)
  220. (match (apply-stack-effect ctx (compute-stack-effect ctx instr))
  221. (($ <invalid-ctx> reason)
  222. (validation-error reason instr))
  223. (ctx
  224. (match instr
  225. (('i32.const x) (assert-s32 x))
  226. (('i64.const x) (assert-s64 x))
  227. (('f32.const x) (assert-f32 x))
  228. (('f64.const x) (assert-f64 x))
  229. (('global.get idx)
  230. (assert-preceding-and-immutable-global idx global-count))
  231. (('string.const idx) (check-string idx))
  232. (('ref.func f) (check-func f))
  233. ((or ('ref.null _)
  234. ('ref.i31)
  235. ('struct.new _)
  236. ('struct.new_default _)
  237. ('array.new _)
  238. ('array.new_default _)
  239. ('array.new_fixed _ _)
  240. ('extern.internalize)
  241. ('extern.externalize))
  242. #t)
  243. (_ (validation-error "invalid constant instruction" instr)))
  244. ctx)))
  245. ;; We need to make a phony func object that represents the
  246. ;; expected result type of the constant instructions.
  247. (let* ((sig (make-func-sig '() (list type)))
  248. (func (make-func #f (make-type-use #f sig) '() '())))
  249. (let loop ((ctx (initial-ctx wasm func))
  250. (instrs instrs))
  251. (match instrs
  252. (() #t)
  253. ((instr . rest)
  254. (loop (validate-instr ctx instr) rest))))))
  255. (define (validate-global global idx)
  256. (match global
  257. (($ <global> id ($ <global-type> _ type) instrs)
  258. (validate-const type instrs idx))))
  259. (define (validate-data data)
  260. (match data
  261. (($ <data> _ _ _ offset _)
  262. (when offset
  263. (validate-const 'i32 offset)))))
  264. (define (validate-elem elem)
  265. (match elem
  266. (($ <elem> _ mode _ type offset inits)
  267. (when (eq? mode 'active)
  268. (validate-const 'i32 offset))
  269. (for-each (lambda (init)
  270. (validate-const type init))
  271. inits))))
  272. (define (validate-func func)
  273. (match func
  274. (($ <func> _ ($ <type-use> _ type) _ body)
  275. (define (lookup-block-type bt)
  276. (match bt
  277. (#f (make-func-sig '() '()))
  278. ((? exact-integer? idx) (type-val (list-ref (wasm-types wasm) idx)))
  279. (($ <type-use> _ sig) sig)
  280. (type (make-func-sig '() (list type)))))
  281. (define (push-block* ctx bt loop?)
  282. (match bt
  283. (($ <func-sig> (($ <param> _ params) ...) results)
  284. (push-block ctx #f params results #:is-loop? loop?))))
  285. (define (defaultable-type? type)
  286. (match type
  287. ((or 'i8 'i16 'i32 'i64 'f32 'f64) #t)
  288. (($ <ref-type> #t) #t)
  289. (_ #f)))
  290. (define (validate-instr ctx instr)
  291. (match (apply-stack-effect ctx (compute-stack-effect ctx instr))
  292. (($ <invalid-ctx> reason)
  293. (validation-error reason instr))
  294. (ctx
  295. (match instr
  296. (('if _ (= lookup-block-type bt) consequent alternate)
  297. (validate-branch (push-block* ctx bt #f) consequent)
  298. (validate-branch (push-block* ctx bt #f) alternate))
  299. (('block _ (= lookup-block-type bt) body)
  300. (validate-branch (push-block* ctx bt #f) body))
  301. (('loop _ (= lookup-block-type bt) body)
  302. (validate-branch (push-block* ctx bt #t) body))
  303. (('i32.const x) (assert-s32 x))
  304. (('i64.const x) (assert-s64 x))
  305. (('f32.const x) (assert-f32 x))
  306. (('f64.const x) (assert-f64 x))
  307. (('string.const idx) (check-string idx))
  308. (('global.set idx)
  309. (match (vector-ref global-types idx)
  310. (($ <global-type> mutable? _)
  311. (unless mutable?
  312. (validation-error "global is immutable" idx)))))
  313. (((or 'memory.size 'memory.grow) id)
  314. (check-memory id))
  315. (((or 'i32.load 'i32.load8_s 'i32.load8_u
  316. 'i32.load16_s 'i32.load16_u
  317. 'i64.load 'i64.load8_s 'i64.load8_u
  318. 'i64.load16_s 'i64.load16_u 'i64.load32_s 'i64.load32_u
  319. 'i32.store 'i32.store8 'i32.store16
  320. 'i64.store 'i64.store8 'i64.store16 'i64.store32)
  321. ($ <mem-arg> id _ _))
  322. (check-memory id))
  323. (((or 'table.set 'table.get 'table.size
  324. 'table.grow 'table.fill) table)
  325. (check-table table))
  326. (('table.copy dst src)
  327. (check-table dst)
  328. (check-table src))
  329. (('table.init table elem)
  330. (check-table table)
  331. (check-elem elem))
  332. (('elem.drop table) (check-elem table))
  333. (('ref.func f) (check-func f))
  334. (('struct.new_default t)
  335. ;; Validate that all fields have defaults.
  336. (match (resolve-type (vector-ref types t))
  337. ((and struct ($ <struct-type> (($ <field> _ _ types) ...)))
  338. (unless (every defaultable-type? types)
  339. (validation-error "struct type has non-defaultable fields"
  340. struct)))))
  341. (('struct.set t i)
  342. (let* ((type (resolve-type (vector-ref types t)))
  343. (field (list-ref (struct-type-fields type) i)))
  344. (unless (field-mutable? field)
  345. (validation-error "struct field is immutable" type field instr))))
  346. (('array.new_default t)
  347. (let ((array (resolve-type (vector-ref types t))))
  348. (unless (defaultable-type? (array-type-type array))
  349. (validation-error "array type has non-defaultable element type"
  350. array))))
  351. ((or ('array.set t)
  352. ('array.init_data t _)
  353. ('array.init_elem t _))
  354. (let ((type (resolve-type (vector-ref types t))))
  355. (unless (array-type-mutable? type)
  356. (validation-error "array is immutable" type instr))))
  357. ;; TODO: Validate array.get_s, ref.cast, etc.
  358. (_ #t))
  359. ctx)))
  360. (define (validate-branch ctx instrs)
  361. (let loop ((ctx ctx)
  362. (instrs* instrs))
  363. (match instrs*
  364. (()
  365. (match (fallthrough ctx)
  366. (($ <invalid-ctx> reason)
  367. (validation-error reason instrs))
  368. (_ #t)))
  369. ((instr . rest)
  370. (loop (validate-instr ctx instr) rest)))))
  371. (validate-branch (initial-ctx wasm func) body))))
  372. ;; Because global.get is a valid constant expression, we need to
  373. ;; track the index of the global that is currently being validated.
  374. ;; Any global.get instructions that reference an index greater than
  375. ;; or equal to the current global's index is invalid.
  376. (let ((imported-globals-count
  377. (fold (lambda (i sum)
  378. (match i
  379. (($ <import> _ _ 'global) (+ sum 1))
  380. (_ sum)))
  381. 0 (wasm-imports wasm))))
  382. (let loop ((globals (wasm-globals wasm))
  383. (i imported-globals-count))
  384. (match globals
  385. (() #t)
  386. ((global . rest)
  387. (validate-global global i)
  388. (loop rest (+ i 1))))))
  389. (for-each validate-func (wasm-funcs wasm))
  390. (for-each validate-data (wasm-datas wasm))
  391. (for-each validate-elem (wasm-elems wasm))
  392. (make-validated-wasm wasm))
  393. (define (load-and-validate-wasm obj)
  394. "Load and validate the WASM module within OBJ. OBJ may be a <wasm>
  395. record produced by 'resolve-wasm', a bytevector containing a WASM
  396. binary, or an input port from which a WASM binary is read."
  397. (validate-wasm
  398. (cond
  399. ((wasm? obj) obj)
  400. ((bytevector? obj)
  401. (call-with-input-bytevector obj parse-wasm))
  402. ((port? obj)
  403. (parse-wasm obj))
  404. (else
  405. (error "not a WASM object" obj)))))
  406. ;;;
  407. ;;; Instances
  408. ;;;
  409. (define-exception-type &wasm-runtime-error &wasm-error
  410. make-wasm-runtime-error
  411. wasm-runtime-error?
  412. (instruction wasm-runtime-error-instruction)
  413. (position wasm-runtime-error-position)
  414. (instance wasm-runtime-error-instance)
  415. (stack wasm-runtime-error-stack)
  416. (blocks wasm-runtime-error-blocks)
  417. (locals wasm-runtime-error-locals))
  418. ;; TODO: Use a vector instead of a list to avoid allocation for each
  419. ;; push. Maximum stack depth for each function can be determined at
  420. ;; validation time.
  421. (define-record-type <wasm-stack>
  422. (%make-wasm-stack items)
  423. wasm-stack?
  424. (items wasm-stack-items set-wasm-stack-items!))
  425. (define (make-wasm-stack)
  426. (%make-wasm-stack '()))
  427. (define (stack-push! stack x)
  428. (set-wasm-stack-items! stack (cons x (wasm-stack-items stack))))
  429. (define (stack-push-all! stack vals)
  430. (for-each (lambda (val)
  431. (stack-push! stack val))
  432. vals))
  433. (define (stack-peek stack)
  434. (match (wasm-stack-items stack)
  435. (() #f)
  436. ((head . _)
  437. head)))
  438. (define (stack-pop! stack)
  439. (match (wasm-stack-items stack)
  440. (() #f)
  441. ((head . rest)
  442. (set-wasm-stack-items! stack rest)
  443. head)))
  444. (define (stack-pop-n! stack n)
  445. (let loop ((n n)
  446. (result '()))
  447. (if (= n 0)
  448. result
  449. (loop (- n 1) (cons (stack-pop! stack) result)))))
  450. ;; This is similar to what's in (wasm dump), but our runtime type
  451. ;; canonicalization introduces promises for recursive type groups that
  452. ;; need special handling.
  453. (define (type-repr type)
  454. (define (params-repr params)
  455. (match params
  456. (() '())
  457. ((($ <param> #f type) ...)
  458. `((param ,@(map type-repr type))))
  459. ((($ <param> id type) . params)
  460. (cons `(param ,id ,(type-repr type))
  461. (params-repr params)))))
  462. (define (results-repr results)
  463. `((result ,@(map type-repr results))))
  464. (define (field-repr field)
  465. (define (wrap mutable? repr)
  466. (if mutable? `(mut ,repr) repr))
  467. (match field
  468. (($ <field> id mutable? type)
  469. (let ((repr (wrap mutable? (type-repr type))))
  470. (if id
  471. `(field ,id ,repr)
  472. repr)))))
  473. (match type
  474. (($ <func-sig> params results)
  475. `(func ,@(params-repr params) ,@(results-repr results)))
  476. (($ <sub-type> final? supers type)
  477. `(sub ,@(if final? '(final) '())
  478. ,@(map type-repr supers)
  479. ,(type-repr type)))
  480. (($ <struct-type> fields)
  481. `(struct ,@(map field-repr fields)))
  482. (($ <array-type> mutable? type)
  483. `(array ,(field-repr (make-field #f mutable? type))))
  484. (($ <ref-type> #t ht)
  485. `(ref null ,(type-repr ht)))
  486. (($ <ref-type> #f ht)
  487. `(ref ,(type-repr ht)))
  488. ;; TODO: Figure out how to display useful information about
  489. ;; recursive types without cycles.
  490. ((? promise?) '_)
  491. (_ type)))
  492. ;; TODO: Replace with global weak hash table that maps procedures to
  493. ;; signatures.
  494. (define-record-type <wasm-func>
  495. (make-wasm-func proc sig)
  496. wasm-func?
  497. (proc wasm-func-proc)
  498. (sig wasm-func-sig))
  499. (set-record-type-printer! <wasm-func>
  500. (lambda (f port)
  501. (format port "#<wasm-func ~a ~a>"
  502. (type-repr (wasm-func-sig f))
  503. (object-address f))))
  504. (define-record-type <wasm-global>
  505. (make-wasm-global value mutable?)
  506. wasm-global?
  507. (value wasm-global-ref %wasm-global-set!)
  508. (mutable? wasm-global-mutable?))
  509. (define (wasm-global-set! global val)
  510. (if (wasm-global-mutable? global)
  511. (%wasm-global-set! global val)
  512. (error "WASM global is immutable" global)))
  513. (define %page-size (* 64 1024))
  514. (define %max-pages (/ (ash 1 32) %page-size))
  515. (define (clamp-to-limits x limits default-max)
  516. (match limits
  517. (($ <limits> min max)
  518. (let ((max* (or max default-max)))
  519. (cond
  520. ((< x min) min)
  521. ((> x max*) max*)
  522. (else x))))))
  523. (define-record-type <wasm-memory>
  524. (%make-wasm-memory bytes size limits)
  525. wasm-memory?
  526. (bytes wasm-memory-bytes set-wasm-memory-bytes!)
  527. (size wasm-memory-size set-wasm-memory-size!)
  528. (limits wasm-memory-limits))
  529. (define (make-bytevector/pages n)
  530. (make-bytevector (* n %page-size) 0))
  531. (define* (make-wasm-memory size #:optional (limits (make-limits 1 #f)))
  532. (let ((size* (clamp-to-limits size limits %max-pages)))
  533. (%make-wasm-memory (make-bytevector/pages size*) size* limits)))
  534. (define (wasm-memory-grow! memory n)
  535. (match memory
  536. (($ <wasm-memory> old-bytes old-size limits)
  537. (if (= n 0)
  538. old-size
  539. (let ((new-size (clamp-to-limits (+ (wasm-memory-size memory) n)
  540. limits %max-pages)))
  541. (if (= new-size old-size)
  542. -1
  543. (let ((new-bytes (make-bytevector/pages new-size)))
  544. (bytevector-copy! old-bytes 0 new-bytes 0
  545. (* old-size %page-size))
  546. (set-wasm-memory-bytes! memory new-bytes)
  547. (set-wasm-memory-size! memory new-size)
  548. old-size)))))))
  549. (define-record-type <wasm-table>
  550. (%make-wasm-table elements limits)
  551. wasm-table?
  552. (elements wasm-table-elements set-wasm-table-elements!)
  553. (limits wasm-table-limits))
  554. (define %max-table-size (- (ash 1 32) 1))
  555. (define* (make-wasm-table size #:optional (limits (make-limits 1 #f)))
  556. (let ((size* (clamp-to-limits size limits %max-table-size)))
  557. (%make-wasm-table (make-vector size*) limits)))
  558. (define (wasm-table-size table)
  559. (vector-length (wasm-table-elements table)))
  560. (define (wasm-table-ref table i)
  561. (vector-ref (wasm-table-elements table) i))
  562. (define (wasm-table-set! table i x)
  563. (vector-set! (wasm-table-elements table) i x))
  564. (define (wasm-table-fill! table start fill length)
  565. (vector-fill! (wasm-table-elements table) fill start (+ start length)))
  566. (define (wasm-table-copy! table at src start length)
  567. (vector-copy! (wasm-table-elements table) at (wasm-table-elements src)
  568. start (+ start length)))
  569. (define (wasm-table-init! table at elems start length)
  570. (vector-copy! (wasm-table-elements table) at elems start (+ start length)))
  571. (define (wasm-table-grow! table n init)
  572. (match table
  573. (($ <wasm-table> elems limits)
  574. (let ((old-size (vector-length elems)))
  575. (if (= n 0)
  576. old-size
  577. (let ((new-size (clamp-to-limits (+ old-size n) limits %max-table-size)))
  578. (if (= new-size old-size)
  579. -1
  580. (let ((new-elems (make-vector new-size)))
  581. (vector-copy! new-elems 0 elems)
  582. (do ((i old-size (+ i 1)))
  583. ((= i new-size))
  584. (vector-set! new-elems i init))
  585. (set-wasm-table-elements! table new-elems)
  586. old-size))))))))
  587. (define-record-type <wasm-null>
  588. (make-wasm-null type)
  589. wasm-null?
  590. (type wasm-null-type))
  591. (set-record-type-printer! <wasm-null>
  592. (lambda (struct port)
  593. (format port "#<wasm-null ~a>"
  594. (type-repr (wasm-null-type struct)))))
  595. ;; TODO: Packed fields.
  596. (define-record-type <wasm-struct>
  597. (%make-wasm-struct type fields)
  598. wasm-struct?
  599. (type wasm-struct-type)
  600. (fields wasm-struct-fields))
  601. (set-record-type-printer! <wasm-struct>
  602. (lambda (struct port)
  603. (format port "#<wasm-struct ~a ~a>"
  604. (type-repr (wasm-struct-type struct))
  605. (object-address struct))))
  606. (define (make-wasm-struct type fields)
  607. (%make-wasm-struct type (list->vector fields)))
  608. (define (wasm-struct-ref struct field)
  609. (vector-ref (wasm-struct-fields struct) field))
  610. (define (wasm-struct-type-fields struct)
  611. (struct-type-fields (resolve-type (wasm-struct-type struct))))
  612. (define (wasm-struct-ref-unsigned struct field)
  613. (let ((x (wasm-struct-ref struct field)))
  614. (match (field-type (list-ref (wasm-struct-type-fields struct) field))
  615. ('i8 (s8->u8 x))
  616. ('i16 (s16->u16 x)))))
  617. (define (wasm-struct-ref-signed struct field)
  618. (let ((x (wasm-struct-ref struct field)))
  619. (match (field-type (list-ref (wasm-struct-type-fields struct) field))
  620. ('i8 (s8-overflow x))
  621. ('i16 (s16-overflow x)))))
  622. (define (wasm-struct-set! struct field value)
  623. (vector-set! (wasm-struct-fields struct) field value))
  624. ;; TODO: Use bytevectors for packed arrays.
  625. (define-record-type <wasm-array>
  626. (%make-wasm-array type vector)
  627. wasm-array?
  628. (type wasm-array-type)
  629. (vector wasm-array-vector))
  630. (set-record-type-printer! <wasm-array>
  631. (lambda (array port)
  632. (format port "#<wasm-array ~a ~a>"
  633. (type-repr (wasm-array-type array))
  634. (object-address array))))
  635. (define* (make-wasm-array type k #:optional (fill *unspecified*))
  636. (%make-wasm-array type (make-vector k fill)))
  637. (define (wasm-array-length array)
  638. (vector-length (wasm-array-vector array)))
  639. (define (wasm-array-element-type array)
  640. (array-type-type (resolve-type (wasm-array-type array))))
  641. (define (wasm-array-ref array i)
  642. (vector-ref (wasm-array-vector array) i))
  643. (define (wasm-array-ref-unsigned array i)
  644. (let ((x (wasm-array-ref array i)))
  645. (match (wasm-array-element-type array)
  646. ('i8 (s8->u8 x))
  647. ('i16 (s16->u16 x)))))
  648. (define (wasm-array-ref-signed array i)
  649. (let ((x (wasm-array-ref array i)))
  650. (match (wasm-array-element-type array)
  651. ('i8 (s8-overflow x))
  652. ('i16 (s16-overflow x)))))
  653. (define (wasm-array-set! array i value)
  654. (vector-set! (wasm-array-vector array) i value))
  655. (define (wasm-array-init-data! array at data offset length)
  656. (let ((ref (match (array-type-type (wasm-array-type array))
  657. ('f64 f64vector-ref)
  658. ('f32 f32vector-ref)
  659. ('i32 s32vector-ref)
  660. ('i16 u16vector-ref)
  661. ('i8 u8vector-ref)
  662. (type (error "non-numeric array type" type)))))
  663. (do ((i 0 (+ i 1)))
  664. ((= i length))
  665. (wasm-array-set! array (+ i at) (ref data (+ i offset))))))
  666. (define (wasm-array-init-elem! array at elem offset length)
  667. (do ((i 0 (+ i 1)))
  668. ((= i length))
  669. (wasm-array-set! array (+ i at) (vector-ref elem (+ i offset)))))
  670. (define (wasm-array-fill! array start fill length)
  671. (vector-fill! (wasm-array-vector array) fill start (+ start length)))
  672. (define (wasm-array-copy! dst at src start length)
  673. (vector-copy! (wasm-array-vector dst) at
  674. (wasm-array-vector src) start (+ start length)))
  675. (define (wasm-array->string array start end)
  676. (list->string
  677. (let loop ((i start))
  678. (if (= i end)
  679. '()
  680. (cons (integer->char (wasm-array-ref-unsigned array i))
  681. (loop (+ i 1)))))))
  682. (define (wasm-array-encode-string! array str start)
  683. (let ((utf8 (string->utf8 str)))
  684. (do ((i 0 (+ i 1)))
  685. ((= i (bytevector-length utf8)))
  686. (wasm-array-set! array (+ i start) (bytevector-u8-ref utf8 i)))))
  687. (define-record-type <wasm-string-iterator>
  688. (make-wasm-string-iterator string index)
  689. wasm-string-iterator?
  690. (string wasm-string-iterator-string)
  691. (index wasm-string-iterator-index set-wasm-string-iterator-index!))
  692. (define (wasm-string-iterator-next! iter)
  693. (match iter
  694. (($ <wasm-string-iterator> str i)
  695. (let ((len (string-length str)))
  696. (set-wasm-string-iterator-index! iter (+ i 1))
  697. (if (>= i len)
  698. -1
  699. (char->integer (string-ref str i)))))))
  700. (define (wasm-string-iterator-advance! iter k)
  701. (match iter
  702. (($ <wasm-string-iterator> str i)
  703. (let ((len (string-length str)))
  704. (set-wasm-string-iterator-index! iter (+ i k))
  705. (max (- (min (+ i k) len) i) 0)))))
  706. (define (default-for-type type)
  707. (match type
  708. ((or 'i8 'i16 'i32 'i64) 0)
  709. ((or 'f32 'f64) 0.0)
  710. ((or (? ref-type?) (? struct-type?) (? array-type?) (? sub-type?))
  711. (make-wasm-null type))))
  712. (define (is-a? x type)
  713. (match type
  714. ('i32 (s32? x))
  715. ('i64 (s64? x))
  716. ('f32 (f32? x))
  717. ('f64 (f64? x))
  718. ('i31 (s31? x))
  719. ('extern #t)
  720. ('func (wasm-func? x))
  721. ((? func-sig?)
  722. (and (wasm-func? x) (eq? (wasm-func-sig x) type)))
  723. ((or 'eq 'any)
  724. (or (s31? x) (wasm-struct? x) (wasm-array? x)))
  725. ('i31 (s31? x))
  726. ('struct (wasm-struct? x))
  727. ('array (wasm-array? x))
  728. ('string (string? x))
  729. (($ <ref-type> _ heap-type)
  730. (is-a? x heap-type))
  731. (_
  732. (let loop ((x-type (cond
  733. ((wasm-func? x) (wasm-func-sig x))
  734. ((wasm-struct? x) (wasm-struct-type x))
  735. ((wasm-array? x) (wasm-array-type x))
  736. (else #f))))
  737. (match x-type
  738. (#f #f)
  739. ((and x-type ($ <sub-type> _ x-supers _))
  740. (or (eq? x-type type)
  741. (any (match-lambda
  742. ((? promise? x-super) (loop (force x-super)))
  743. (x-super (loop x-super)))
  744. x-supers)))
  745. (x-type (eq? x-type type)))))))
  746. ;; Some more global state that keeps a record of all exported WASM
  747. ;; functions so that we can avoid runtime type checking when making
  748. ;; calls directly from one instance to another.
  749. (define *exported-functions* (make-weak-key-hash-table))
  750. (define (register-exported-function! wrap func)
  751. (hashq-set! *exported-functions* wrap func))
  752. (define (lookup-exported-function wrap)
  753. (hashq-ref *exported-functions* wrap))
  754. (define-record-type <wasm-instance>
  755. (make-wasm-instance module types globals funcs memories tables datas elems
  756. strings exports)
  757. wasm-instance?
  758. (module wasm-instance-module)
  759. (types wasm-instance-types)
  760. (globals wasm-instance-globals)
  761. (funcs wasm-instance-funcs)
  762. (memories wasm-instance-memories)
  763. (tables wasm-instance-tables)
  764. (datas wasm-instance-datas)
  765. (elems wasm-instance-elems)
  766. (strings wasm-instance-strings)
  767. (exports wasm-instance-exports))
  768. (set-record-type-printer! <wasm-instance>
  769. (lambda (instance port)
  770. (format port "#<wasm-instance ~a>"
  771. (object-address instance))))
  772. (define-exception-type &wasm-instance-error &wasm-error
  773. make-wasm-instance-error
  774. wasm-instance-error?)
  775. (define (instance-error msg . irritants)
  776. (raise-exception
  777. (make-exception
  778. (make-wasm-instance-error)
  779. (make-exception-with-message
  780. (format #f "WASM instantiation error: ~a" msg))
  781. (make-exception-with-irritants irritants))))
  782. (define* (instantiate-wasm module #:key (imports '()))
  783. (define (lookup-import mod name)
  784. (assoc-ref (or (assoc-ref imports mod) '()) name))
  785. (match module
  786. (($ <validated-wasm>
  787. ($ <wasm> id types wasm-imports funcs tables memories globals exports
  788. start elems datas tags strings custom))
  789. (define (count-imports kind)
  790. (fold (lambda (i sum)
  791. (match i
  792. (($ <import> _ _ k)
  793. (if (eq? kind k) (+ sum 1) sum))))
  794. 0 wasm-imports))
  795. (let* ((n-global-imports (count-imports 'global))
  796. (n-func-imports (count-imports 'func))
  797. (n-memory-imports (count-imports 'memory))
  798. (n-table-imports (count-imports 'table))
  799. ;; TODO: Canonicalization has already happened during
  800. ;; validation! <validated-wasm> should just store the
  801. ;; canonicalized types so we aren't duplicating work here.
  802. (type-vec (list->vector (map type-val (canonicalize-types! types))))
  803. (global-vec (make-vector (+ n-global-imports (length globals))))
  804. (func-vec (make-vector (+ n-func-imports (length funcs))))
  805. (memory-vec (make-vector (+ n-memory-imports (length memories))))
  806. (table-vec (make-vector (+ n-table-imports (length tables))))
  807. (data-vec (make-vector (length datas)))
  808. (elem-vec (make-vector (length elems)))
  809. (string-vec (list->vector strings))
  810. (export-table (make-hash-table))
  811. (instance (make-wasm-instance module type-vec global-vec func-vec
  812. memory-vec table-vec data-vec elem-vec
  813. string-vec export-table)))
  814. (define (type-check vals types)
  815. (unless (let loop ((vals vals)
  816. (types types))
  817. (match vals
  818. (()
  819. (match types
  820. (() #t)
  821. (_ #f)))
  822. ((val . rest-vals)
  823. (match types
  824. (() #f)
  825. ((type . rest-types)
  826. (and (is-a? val type)
  827. (loop rest-vals rest-types)))))))
  828. (error (format #f "type mismatch; expected ~a" types)
  829. vals)))
  830. (define (convert-results vals types)
  831. (map (lambda (val type)
  832. (match type
  833. ('i32
  834. (match val
  835. ((? s32?) val)
  836. (#t 1)
  837. (#f 0)
  838. (_ (error "invalid i32" val))))
  839. ;; For (ref null extern), #f is converted to a null
  840. ;; WASM value.
  841. (($ <ref-type> #t 'extern)
  842. (match val
  843. (#f (make-wasm-null type))
  844. (_ val)))
  845. (_ val)))
  846. vals types))
  847. (define (make-import-closure mod name proc sig)
  848. (let ((result-types (func-sig-results sig)))
  849. (define (wrap . args)
  850. (call-with-values (lambda () (apply proc args))
  851. (lambda vals
  852. (let ((vals* (convert-results vals result-types)))
  853. (type-check vals* result-types)
  854. (apply values vals*)))))
  855. (set-procedure-property! wrap 'name (format #f "~a:~a" mod name))
  856. wrap))
  857. (define (make-export-closure name func)
  858. (match func
  859. (($ <wasm-func> proc ($ <func-sig> (($ <param> _ param-types) ...)))
  860. (define (wrap . args)
  861. (type-check args param-types)
  862. (apply proc args))
  863. (set-procedure-property! wrap 'name (string->symbol name))
  864. wrap)))
  865. (define (instantiate-func idx func)
  866. (match func
  867. (($ <func> _ ($ <type-use> type-idx) locals body)
  868. (let* ((local-types (map local-type locals))
  869. (sig (vector-ref type-vec type-idx))
  870. (n-params (length (func-sig-params sig)))
  871. (n-results (length (func-sig-results sig)))
  872. (n-locals (length local-types))
  873. (base-path `(,idx func)))
  874. (define (wasm-proc . args)
  875. (let ((stack (make-wasm-stack))
  876. (locals (make-vector (+ n-params n-locals))))
  877. ;; Initialize first n locals with args.
  878. (let loop ((args args)
  879. (i 0))
  880. (match args
  881. (() #t)
  882. ((arg . rest)
  883. (vector-set! locals i arg)
  884. (loop rest (+ i 1)))))
  885. ;; Initialize rest of locals with defaults.
  886. (let loop ((types local-types)
  887. (i n-params))
  888. (match types
  889. (() #t)
  890. ((type . rest)
  891. (vector-set! locals i (default-for-type type))
  892. (loop rest (+ i 1)))))
  893. ;; Execute the function body, handling early
  894. ;; returns. There are two classes of returns:
  895. ;; return and return-call. A regular return simply
  896. ;; returns the top n values on the stack. A
  897. ;; return-call passes along a thunk to be tail
  898. ;; called which will continue the computation.
  899. (let ((tail-cont #f))
  900. (call-with-block
  901. (lambda (tag)
  902. (execute* body base-path instance stack (list tag) locals))
  903. (lambda (k)
  904. (set! tail-cont k)))
  905. (if tail-cont
  906. (tail-cont)
  907. (apply values (stack-pop-n! stack n-results))))))
  908. (make-wasm-func wasm-proc sig)))))
  909. (define (exec-init base-path init)
  910. (let ((stack (make-wasm-stack)))
  911. (execute* init (reverse base-path) instance stack '() #())
  912. (stack-pop! stack)))
  913. ;; Process imports.
  914. (let loop ((wasm-imports wasm-imports)
  915. (global-idx 0)
  916. (func-idx 0)
  917. (memory-idx 0)
  918. (table-idx 0))
  919. (match wasm-imports
  920. (() #t)
  921. ((($ <import> mod name 'func _ ($ <type-use> idx)) . rest)
  922. (let ((sig (vector-ref type-vec idx)))
  923. (match (lookup-import mod name)
  924. ((? procedure? proc)
  925. ;; If proc is a wrapper around a WASM function from
  926. ;; another instance, then we'll just use the internal
  927. ;; procedure instead and skip unnecessary runtime type
  928. ;; checking.
  929. (match (lookup-exported-function proc)
  930. ((and func ($ <wasm-func> _ other-sig))
  931. (if (eq? sig other-sig)
  932. (vector-set! func-vec func-idx func)
  933. (instance-error "imported function signature mismatch"
  934. mod name sig other-sig)))
  935. (#f
  936. (let ((wrap (make-import-closure mod name proc sig)))
  937. (vector-set! func-vec func-idx (make-wasm-func wrap sig)))))
  938. (loop rest global-idx (+ func-idx 1) memory-idx table-idx))
  939. (x (instance-error "invalid function import" mod name x)))))
  940. ((($ <import> mod name 'global _ type) . rest)
  941. (match (lookup-import mod name)
  942. ((? wasm-global? global)
  943. (vector-set! global-vec global-idx global)
  944. (loop rest (+ global-idx 1) func-idx memory-idx table-idx))
  945. (x (instance-error "invalid global import" mod name x))))
  946. ((($ <import> mod name 'memory _ type) . rest)
  947. (match (lookup-import mod name)
  948. ((? wasm-memory? memory)
  949. (vector-set! memory-vec memory-idx memory)
  950. (loop rest global-idx func-idx (+ memory-idx 1) table-idx))
  951. (x (instance-error "invalid memory import" mod name x))))
  952. ((($ <import> mod name 'table _ type) . rest)
  953. (match (lookup-import mod name)
  954. ((? wasm-table? table)
  955. (vector-set! table-vec table-idx table)
  956. (loop rest global-idx func-idx memory-idx (+ table-idx 1)))
  957. (x (instance-error "invalid table import" mod name x))))))
  958. ;; Initialize functions.
  959. (let loop ((funcs funcs)
  960. (idx n-func-imports))
  961. (match funcs
  962. (() #t)
  963. ((func . rest)
  964. (vector-set! func-vec idx (instantiate-func idx func))
  965. (loop rest (+ idx 1)))))
  966. ;; Initialize globals.
  967. (let loop ((globals globals)
  968. (idx n-global-imports))
  969. (match globals
  970. (() #t)
  971. (((and ($ <global> _ ($ <global-type> mutable? type) init) global) . rest)
  972. (let ((global (make-wasm-global (exec-init `(global ,idx) init) mutable?)))
  973. (vector-set! global-vec idx global))
  974. (loop rest (+ idx 1)))))
  975. ;; Initialize memories.
  976. (let loop ((memories memories)
  977. (idx n-memory-imports))
  978. (match memories
  979. (() #t)
  980. ((($ <memory> _ ($ <mem-type> (and ($ <limits> min) limits))) . rest)
  981. (vector-set! memory-vec idx (make-wasm-memory min limits))
  982. (loop rest (+ idx 1)))))
  983. ;; Initialize data segments and copy active ones into memory.
  984. (let loop ((datas datas) (idx 0))
  985. (match datas
  986. (() #t)
  987. (((and ($ <data> _ mode mem-id instrs init) data) . rest)
  988. (vector-set! data-vec idx init)
  989. (when (eq? mode 'active)
  990. ;; Invoke the VM to process the constant
  991. ;; expressions that produce the offset value.
  992. (let ((offset (exec-init `(data ,idx) instrs))
  993. (memory (vector-ref memory-vec mem-id)))
  994. (bytevector-copy! init 0 (wasm-memory-bytes memory)
  995. offset (bytevector-length init))))
  996. (loop rest (+ idx 1)))))
  997. ;; Initialize tables.
  998. (let loop ((tables tables)
  999. (idx n-table-imports))
  1000. (match tables
  1001. (() #t)
  1002. ((($ <table> _ ($ <table-type> (and ($ <limits> min) limits)) init) . rest)
  1003. (vector-set! table-vec idx (make-wasm-table min limits))
  1004. (loop rest (+ idx 1)))))
  1005. ;; Initialize elements and copy active elements into tables.
  1006. (let loop ((elems elems)
  1007. (idx 0))
  1008. (match elems
  1009. (() #t)
  1010. (((and elem ($ <elem> _ mode table-idx type offset inits)) . rest)
  1011. (let ((table (and table-idx (vector-ref table-vec table-idx)))
  1012. (offset (and (eq? mode 'active)
  1013. (exec-init `(elem ,idx 0) offset)))
  1014. (init-vec (list->vector
  1015. (let init-loop ((inits inits) (j 1))
  1016. (match inits
  1017. (() '())
  1018. ((instrs . rest)
  1019. (cons (exec-init `(elem ,idx ,j) instrs)
  1020. (init-loop rest (+ j 1)))))))))
  1021. (vector-set! elem-vec idx init-vec)
  1022. (when table
  1023. (do ((i 0 (+ i 1)))
  1024. ((= i (vector-length init-vec)))
  1025. (wasm-table-set! table (+ offset i) (vector-ref init-vec i))))
  1026. (loop rest (+ idx 1))))))
  1027. ;; Call start function, if present.
  1028. (when start ((wasm-func-proc (vector-ref func-vec start))))
  1029. ;; Populate export table.
  1030. (for-each (match-lambda
  1031. (($ <export> name 'func idx)
  1032. (let* ((func (vector-ref func-vec idx))
  1033. (wrap (make-export-closure name func)))
  1034. (register-exported-function! wrap func)
  1035. (hash-set! export-table name wrap)))
  1036. (($ <export> name 'global idx)
  1037. (hash-set! export-table name (vector-ref global-vec idx)))
  1038. (($ <export> name 'memory idx)
  1039. (hash-set! export-table name (vector-ref memory-vec idx)))
  1040. (($ <export> name 'table idx)
  1041. (hash-set! export-table name (vector-ref table-vec idx))))
  1042. exports)
  1043. instance))))
  1044. (define (wasm-instance-export-ref instance name)
  1045. (hash-ref (wasm-instance-exports instance) name))
  1046. (define (wasm-instance-export-names instance)
  1047. (hash-fold (lambda (k v memo) (cons k memo))
  1048. '() (wasm-instance-exports instance)))
  1049. (define (wasm-instance-global-ref instance idx)
  1050. (vector-ref (wasm-instance-globals instance) idx))
  1051. (define (wasm-instance-drop-elem! instance idx)
  1052. (vector-set! (wasm-instance-elems instance) idx #f))
  1053. ;; Blocks are delimited by a prompt so that 'br', 'return',
  1054. ;; 'return_call' and friends can abort to that prompt.
  1055. (define (call-with-block proc handler)
  1056. (let ((tag (make-prompt-tag 'wasm-block)))
  1057. (call-with-prompt tag
  1058. (lambda ()
  1059. (proc tag))
  1060. ;; The 'return_call' family of instructions need to pass along a
  1061. ;; continuation that can be tail called after aborting to the
  1062. ;; prompt.
  1063. (lambda (_k thunk)
  1064. (handler thunk)))))
  1065. ;; Debugging/instrumentation hook, called before each instruction.
  1066. (define current-instruction-listener
  1067. (make-parameter (lambda (instr path instance stack blocks locals) #t)))
  1068. ;; Per Andy: Don't bother with br_on_cast right now!
  1069. (define (execute instr path instance stack blocks locals)
  1070. (define (runtime-error msg . irritants)
  1071. (let ((path* (reverse path)))
  1072. (raise-exception
  1073. (make-exception
  1074. (make-wasm-runtime-error instr path* instance stack blocks locals)
  1075. (make-exception-with-message
  1076. (format #f "WASM runtime error: ~a" msg))
  1077. (make-exception-with-irritants irritants))
  1078. #:continuable? #t)))
  1079. ;; Stack shorthands.
  1080. (define (push x) (stack-push! stack x))
  1081. (define (push-all lst) (stack-push-all! stack lst))
  1082. (define (pop) (or (stack-pop! stack) (runtime-error "empty stack")))
  1083. (define (pop-n n) (stack-pop-n! stack n))
  1084. (define (peek) (or (stack-peek stack) (runtime-error "empty stack")))
  1085. ;; Macro for let-binding values popped off the stack.
  1086. (define-syntax lets
  1087. (lambda (x)
  1088. (syntax-case x ()
  1089. ((_ (var ...) body ...)
  1090. ;; Popping the stack gets the last arg, so reverse binding
  1091. ;; order.
  1092. (with-syntax (((var ...) (reverse #'(var ...))))
  1093. #'(let* ((var (pop)) ...) body ...))))))
  1094. ;; Control flow helpers.
  1095. (define (call* func)
  1096. (match func
  1097. (($ <wasm-func> proc ($ <func-sig> params))
  1098. (apply proc (pop-n (length params))))
  1099. (x (runtime-error "not a function" x))))
  1100. (define (call func)
  1101. (call-with-values (lambda () (call* func))
  1102. (lambda vals (push-all vals))))
  1103. (define (return* thunk)
  1104. ;; The current function's tag is at the bottom.
  1105. (match blocks
  1106. ((_ ... tag)
  1107. (abort-to-prompt tag thunk))))
  1108. (define (return) (return* #f))
  1109. (define (return-call f) (return* (lambda () (call* f))))
  1110. (define (branch l) (abort-to-prompt (list-ref blocks l) #f))
  1111. (define (block path body branch)
  1112. (call-with-block
  1113. (lambda (block)
  1114. (execute* body path instance stack (cons block blocks) locals))
  1115. (lambda (_) (branch))))
  1116. (define (end) 'end)
  1117. ;; Convenience macros.
  1118. (define-syntax-rule (unop proc)
  1119. (push (proc (pop))))
  1120. (define-syntax-rule (u32-unop proc)
  1121. (unop (lambda (a) (proc (s32->u32 a)))))
  1122. (define-syntax-rule (u64-unop proc)
  1123. (unop (lambda (a) (proc (s64->u64 a)))))
  1124. (define-syntax-rule (binop proc)
  1125. (lets (a b) (push (proc a b))))
  1126. (define-syntax-rule (compare pred)
  1127. (binop (lambda (a b) (if (pred a b) 1 0))))
  1128. (define-syntax-rule (compare1 pred)
  1129. (unop (lambda (a) (if (pred a) 1 0))))
  1130. (define-syntax-rule (s32-binop proc)
  1131. (binop (lambda (a b) (s32-overflow (proc a b)))))
  1132. (define-syntax-rule (s64-binop proc)
  1133. (binop (lambda (a b) (s64-overflow (proc a b)))))
  1134. (define-syntax-rule (u32-binop proc)
  1135. (s32-binop (lambda (a b) (s32-overflow (proc (s32->u32 a) (s32->u32 b))))))
  1136. (define-syntax-rule (u64-binop proc)
  1137. (s64-binop (lambda (a b) (s64-overflow (proc (s64->u64 a) (s64->u64 b))))))
  1138. (define-syntax-rule (u32-compare pred)
  1139. (compare (lambda (a b) (pred (s32->u32 a) (s32->u32 b)))))
  1140. (define-syntax-rule (u64-compare pred)
  1141. (compare (lambda (a b) (pred (s64->u64 a) (s64->u64 b)))))
  1142. ;; Math/bitwise op helpers.
  1143. (define (!= a b) (not (= a b)))
  1144. (define (shl n m k) (modulo (ash n (modulo m k)) (ash 1 k)))
  1145. (define (shl32 n m) (shl n m 32))
  1146. (define (shl64 n m) (shl n m 64))
  1147. (define (shr n m k) (ash n (- (modulo m k))))
  1148. (define (shr32 n m) (shr n m 32))
  1149. (define (shr64 n m) (shr n m 64))
  1150. (define (rotl n m k) (logior (ash n m) (ash n (- (- k m)))))
  1151. (define (rotl32 n m) (rotl n m 32))
  1152. (define (rotl64 n m) (rotl n m 64))
  1153. (define (rotr n m k) (logior (ash n (- m)) (ash n (- k m))))
  1154. (define (rotr32 n m) (rotr n m 32))
  1155. (define (rotr64 n m) (rotr n m 64))
  1156. (define (clz n k)
  1157. (let loop ((i (- k 1))
  1158. (result 0))
  1159. (if (or (= i -1) (logbit? i n))
  1160. result
  1161. (loop (- i 1) (+ result 1)))))
  1162. (define (clz32 n) (clz n 32))
  1163. (define (clz64 n) (clz n 64))
  1164. (define (ctz n k)
  1165. (let loop ((i 0)
  1166. (result 0))
  1167. (if (or (= i k) (logbit? i n))
  1168. result
  1169. (loop (+ i 1) (+ result 1)))))
  1170. (define (ctz32 n) (ctz n 32))
  1171. (define (ctz64 n) (ctz n 64))
  1172. (define (popcnt n k)
  1173. (let loop ((i 0)
  1174. (result 0))
  1175. (cond
  1176. ((= i k) result)
  1177. ((logbit? i n) (loop (+ i 1) (+ result 1)))
  1178. (else (loop (+ i 1) result)))))
  1179. (define (popcnt32 n) (popcnt n 32))
  1180. (define (popcnt64 n) (popcnt n 64))
  1181. (define (wrap n k)
  1182. (remainder n (ash 1 k)))
  1183. (define (wrap8 n) (wrap n 8))
  1184. (define (wrap16 n) (wrap n 16))
  1185. (define (wrap32 n) (wrap n 32))
  1186. (define (wrap64 n) (wrap n 64))
  1187. (define (s32->s64 x) x)
  1188. (define (u32->s64 x) (s32->u32 x))
  1189. (define (copy-sign a b)
  1190. (* (abs a) (/ b (abs b))))
  1191. (define (float->int x pred)
  1192. (let ((y (inexact->exact (truncate x))))
  1193. (if (pred y) y (runtime-error "integer overflow"))))
  1194. (define (float->s32 x) (float->int x s32?))
  1195. (define (float->u32 x) (float->int x u32?))
  1196. (define (float->s64 x) (float->int x s64?))
  1197. (define (float->u64 x) (float->int x u64?))
  1198. (define (reinterpret x make-bv ref)
  1199. (ref (make-bv x) 0))
  1200. (define (reinterpret/s32->f32 x)
  1201. (reinterpret x s32vector f32vector-ref))
  1202. (define (reinterpret/s64->f64 x)
  1203. (reinterpret x s64vector f64vector-ref))
  1204. (define (reinterpret/f32->s32 x)
  1205. (reinterpret x f32vector s32vector-ref))
  1206. (define (reinterpret/f64->s64 x)
  1207. (reinterpret x f64vector s64vector-ref))
  1208. ;; Memory helpers
  1209. (define (memory-ref id)
  1210. (vector-ref (wasm-instance-memories instance) id))
  1211. (define (memory-bytes id)
  1212. (wasm-memory-bytes (memory-ref id)))
  1213. (define (load* id offset ref)
  1214. (let* ((i (+ (s32->u32 (pop)) offset))
  1215. (bv (memory-bytes id)))
  1216. (push (ref bv i))))
  1217. (define (load id offset ref)
  1218. (load* id offset (lambda (bv i) (ref bv i (endianness little)))))
  1219. (define (load-s64 id offset) (load id offset bytevector-s64-ref))
  1220. (define (load-s32 id offset) (load id offset bytevector-s32-ref))
  1221. (define (load-u32 id offset) (load id offset bytevector-u32-ref))
  1222. (define (load-s16 id offset) (load id offset bytevector-s16-ref))
  1223. (define (load-u16 id offset) (load id offset bytevector-u16-ref))
  1224. (define (load-s8 id offset) (load* id offset bytevector-s8-ref))
  1225. (define (load-u8 id offset) (load* id offset bytevector-u8-ref))
  1226. (define (load-f32 id offset) (load id offset bytevector-ieee-single-ref))
  1227. (define (load-f64 id offset) (load id offset bytevector-ieee-double-ref))
  1228. (define (storei* id offset set wrap s->u)
  1229. (let* ((c (wrap (s->u (pop))))
  1230. (i (+ (s32->u32 (pop)) offset))
  1231. (bv (memory-bytes id)))
  1232. (set bv i c)))
  1233. (define (storei id offset set wrap s->u)
  1234. (storei* id offset
  1235. (lambda (bv i c) (set bv i c (endianness little)))
  1236. wrap s->u))
  1237. (define (store-u64 id offset s->u)
  1238. (storei id offset bytevector-u64-set! wrap64 s->u))
  1239. (define (store-u32 id offset s->u)
  1240. (storei id offset bytevector-u32-set! wrap32 s->u))
  1241. (define (store-u16 id offset s->u)
  1242. (storei id offset bytevector-u16-set! wrap16 s->u))
  1243. (define (store-u8 id offset s->u)
  1244. (storei* id offset bytevector-u8-set! wrap8 s->u))
  1245. (define (storef id offset set)
  1246. (let* ((c (pop))
  1247. (i (+ (s32->u32 (pop)) offset))
  1248. (bv (memory-bytes id)))
  1249. (set bv i c (endianness little))))
  1250. (define (store-f32 id offset) (storef id offset bytevector-ieee-single-set!))
  1251. (define (store-f64 id offset) (storef id offset bytevector-ieee-double-set!))
  1252. ;; Reference helpers:
  1253. (define (type-ref type-or-idx)
  1254. (match type-or-idx
  1255. ((? integer? idx)
  1256. (type-ref (vector-ref (wasm-instance-types instance) idx)))
  1257. ((? symbol? sym) sym)
  1258. ;;(($ <sub-type> _ _ type) type)
  1259. (type type)))
  1260. (define (table-ref idx)
  1261. (vector-ref (wasm-instance-tables instance) idx))
  1262. (define (elem-ref idx)
  1263. (vector-ref (wasm-instance-elems instance) idx))
  1264. (define (data-ref idx)
  1265. (vector-ref (wasm-instance-datas instance) idx))
  1266. (define (func-ref idx)
  1267. (vector-ref (wasm-instance-funcs instance) idx))
  1268. (define (string-ref idx)
  1269. (vector-ref (wasm-instance-strings instance) idx))
  1270. (define (can-downcast? x rt)
  1271. (match rt
  1272. (($ <ref-type> nullable? ht)
  1273. (if (wasm-null? x) nullable? (is-a? x (type-ref ht))))))
  1274. ;; Call instrumentation hook then execute the instruction.
  1275. ((current-instruction-listener) path instr instance stack blocks locals)
  1276. (match instr
  1277. ;; Control:
  1278. (('nop) 'nop)
  1279. (('unreachable)
  1280. (runtime-error "unreachable"))
  1281. (('block _ _ body)
  1282. ;; Branching to a 'block' label exits the block.
  1283. (block path body end))
  1284. (('if _ _ consequent alternate)
  1285. ;; Same behavior as branching to 'block', which is to exit.
  1286. (let ((test (= (pop) 0)))
  1287. (block (if test (cons 0 path) (cons 1 path))
  1288. (if test alternate consequent)
  1289. end)))
  1290. (('loop _ _ body)
  1291. (define (iterate)
  1292. ;; Branching to a 'loop' label re-enters the loop.
  1293. (block path body iterate))
  1294. (iterate))
  1295. (('call idx) (call (func-ref idx)))
  1296. (('call_indirect idx _)
  1297. (call (wasm-table-ref (table-ref idx) (pop))))
  1298. (('call_ref _)
  1299. (lets (f)
  1300. (if (wasm-null? f)
  1301. (runtime-error "null function reference" f)
  1302. (call f))))
  1303. (('return) (return))
  1304. (('return_call idx)
  1305. (return-call (func-ref idx)))
  1306. (('return_call_indirect idx _)
  1307. (return-call (wasm-table-ref (table-ref idx) (pop))))
  1308. (('return_call_ref _)
  1309. (lets (f)
  1310. (if (wasm-null? f)
  1311. (runtime-error "null function reference" f)
  1312. (return-call f))))
  1313. (('br l) (branch l))
  1314. (('br_if l) (unless (= (pop) 0) (branch l)))
  1315. (('br_table l* l)
  1316. (let ((i (s32->u32 (pop))))
  1317. (branch (if (< i (length l*)) (list-ref l* i) l))))
  1318. ;; Parametric:
  1319. (('drop) (pop))
  1320. (('select)
  1321. (if (= (pop) 0)
  1322. (let ((x (pop)))
  1323. (pop)
  1324. (push x))
  1325. (pop)))
  1326. ;; Locals:
  1327. (('local.get idx) (push (vector-ref locals idx)))
  1328. (('local.set idx) (vector-set! locals idx (pop)))
  1329. (('local.tee idx) (vector-set! locals idx (peek)))
  1330. ;; Globals:
  1331. (('global.get idx)
  1332. (push (wasm-global-ref (wasm-instance-global-ref instance idx))))
  1333. (('global.set idx)
  1334. (wasm-global-set! (wasm-instance-global-ref instance idx) (pop)))
  1335. ;; Numeric:
  1336. (('i32.const x) (push x))
  1337. (('i32.eqz) (compare1 zero?))
  1338. (('i32.eq) (compare =))
  1339. (('i32.ne) (compare !=))
  1340. (('i32.lt_s) (compare <))
  1341. (('i32.lt_u) (u32-compare <))
  1342. (('i32.le_s) (compare <=))
  1343. (('i32.le_u) (u32-compare <=))
  1344. (('i32.gt_s) (compare >))
  1345. (('i32.gt_u) (u32-compare >))
  1346. (('i32.ge_s) (compare >=))
  1347. (('i32.ge_u) (u32-compare >=))
  1348. (('i32.add) (s32-binop +))
  1349. (('i32.sub) (s32-binop -))
  1350. (('i32.mul) (s32-binop *))
  1351. (('i32.div_s) (s32-binop quotient))
  1352. (('i32.div_u) (u32-binop quotient))
  1353. (('i32.rem_s) (s32-binop remainder))
  1354. (('i32.rem_u) (u32-binop remainder))
  1355. (('i32.and) (binop logand))
  1356. (('i32.or) (binop logior))
  1357. (('i32.xor) (binop logxor))
  1358. (('i32.shl) (s32-binop shl32))
  1359. (('i32.shr_s) (s32-binop shr32))
  1360. (('i32.shr_u) (u32-binop shr32))
  1361. (('i32.rotl) (u32-binop rotl32))
  1362. (('i32.rotr) (u32-binop rotr32))
  1363. (('i32.clz) (u32-unop clz32))
  1364. (('i32.ctz) (u32-unop ctz32))
  1365. (('i32.popcnt) (u32-unop popcnt32))
  1366. (('i32.wrap_i64) (unop wrap32))
  1367. (('i32.trunc_f32_s) (unop float->s32))
  1368. (('i32.trunc_f32_u) (unop float->u32))
  1369. (('i32.trunc_f64_s) (unop float->s32))
  1370. (('i32.trunc_f64_u) (unop float->u32))
  1371. (('i32.reinterpret_f32) (unop reinterpret/f32->s32))
  1372. (('i64.const x) (push x))
  1373. (('i64.eqz) (compare1 zero?))
  1374. (('i64.eq) (compare =))
  1375. (('i64.ne) (compare !=))
  1376. (('i64.lt_s) (compare <))
  1377. (('i64.lt_u) (u64-compare <))
  1378. (('i64.le_s) (compare <=))
  1379. (('i64.le_u) (u64-compare <=))
  1380. (('i64.gt_s) (compare >))
  1381. (('i64.gt_u) (u64-compare >))
  1382. (('i64.ge_s) (compare >=))
  1383. (('i64.ge_u) (u64-compare >=))
  1384. (('i64.add) (s64-binop +))
  1385. (('i64.sub) (s64-binop -))
  1386. (('i64.mul) (s64-binop *))
  1387. (('i64.div_s) (s64-binop quotient))
  1388. (('i64.div_u) (u64-binop quotient))
  1389. (('i64.rem_s) (s64-binop remainder))
  1390. (('i64.rem_u) (u64-binop remainder))
  1391. (('i64.and) (binop logand))
  1392. (('i64.or) (binop logior))
  1393. (('i64.xor) (binop logxor))
  1394. (('i64.shl) (s64-binop shl64))
  1395. (('i64.shr_s) (s64-binop shr64))
  1396. (('i64.shr_u) (u64-binop shr64))
  1397. (('i64.rotl) (u64-binop rotl64))
  1398. (('i64.rotr) (u64-binop rotr64))
  1399. (('i64.clz) (u64-unop clz64))
  1400. (('i64.ctz) (u64-unop ctz64))
  1401. (('i64.popcnt) (u64-unop popcnt64))
  1402. (('i64.extend_i32_s) (unop s32->s64))
  1403. (('i64.extend_i32_u) (unop u32->s64))
  1404. (('i64.trunc_f32_s) (unop float->s64))
  1405. (('i64.trunc_f32_u) (unop float->u64))
  1406. (('i64.trunc_f64_s) (unop float->s64))
  1407. (('i64.trunc_f64_u) (unop float->u64))
  1408. (('i64.reinterpret_f64) (unop reinterpret/f64->s64))
  1409. (('f32.const x) (push x))
  1410. (('f32.eq) (compare =))
  1411. (('f32.ne) (compare !=))
  1412. (('f32.lt) (compare <))
  1413. (('f32.le) (compare <=))
  1414. (('f32.gt) (compare >))
  1415. (('f32.ge) (compare >=))
  1416. (('f32.add) (binop +))
  1417. (('f32.sub) (binop -))
  1418. (('f32.mul) (binop *))
  1419. (('f32.div) (binop /))
  1420. (('f32.abs) (unop abs))
  1421. (('f32.neg) (unop -))
  1422. (('f32.ceil) (unop ceiling))
  1423. (('f32.floor) (unop floor))
  1424. (('f32.trunc) (unop truncate))
  1425. (('f32.nearest) (unop round))
  1426. (('f32.sqrt) (unop sqrt))
  1427. (('f32.min) (binop min))
  1428. (('f32.max) (binop max))
  1429. (('f32.copysign) (binop copy-sign))
  1430. (('f32.convert_i32_s) (unop exact->inexact))
  1431. (('f32.convert_i32_u) (u32-unop exact->inexact))
  1432. (('f32.convert_i64_s) (unop exact->inexact))
  1433. (('f32.convert_i64_u) (u64-unop exact->inexact))
  1434. (('f32.demote_f64) #t)
  1435. (('f32.reinterpret_i32) (unop reinterpret/s32->f32))
  1436. (('f64.const x) (push x))
  1437. (('f64.eq) (compare =))
  1438. (('f64.ne) (compare !=))
  1439. (('f64.lt) (compare <))
  1440. (('f64.le) (compare <=))
  1441. (('f64.gt) (compare >))
  1442. (('f64.ge) (compare >=))
  1443. (('f64.add) (binop +))
  1444. (('f64.sub) (binop -))
  1445. (('f64.mul) (binop *))
  1446. (('f64.div) (binop /))
  1447. (('f64.abs) (unop abs))
  1448. (('f64.neg) (unop -))
  1449. (('f64.ceil) (unop ceiling))
  1450. (('f64.floor) (unop floor))
  1451. (('f64.trunc) (unop truncate))
  1452. (('f64.nearest) (unop round))
  1453. (('f64.sqrt) (unop sqrt))
  1454. (('f64.min) (binop min))
  1455. (('f64.max) (binop max))
  1456. (('f64.copysign) (binop copy-sign))
  1457. (('f64.convert_i32_s) (unop exact->inexact))
  1458. (('f64.convert_i32_u) (u32-unop exact->inexact))
  1459. (('f64.convert_i64_s) (unop exact->inexact))
  1460. (('f64.convert_i64_u) (u64-unop exact->inexact))
  1461. (('f64.promote_f32) #t)
  1462. (('f64.reinterpret_i64) (unop reinterpret/s64->f64))
  1463. ;; Linear memory:
  1464. (('i32.load ($ <mem-arg> id offset _)) (load-s32 id offset))
  1465. (('i32.load16_s ($ <mem-arg> id offset _)) (load-s16 id offset))
  1466. (('i32.load16_u ($ <mem-arg> id offset _)) (load-u16 id offset))
  1467. (('i32.load8_s ($ <mem-arg> id offset _)) (load-s8 id offset))
  1468. (('i32.load8_u ($ <mem-arg> id offset _)) (load-u8 id offset))
  1469. (('i32.store ($ <mem-arg> id offset _)) (store-u32 id offset s32->u32))
  1470. (('i32.store16 ($ <mem-arg> id offset _)) (store-u16 id offset s32->u32))
  1471. (('i32.store8 ($ <mem-arg> id offset _)) (store-u8 id offset s32->u32))
  1472. (('i64.load ($ <mem-arg> id offset _)) (load-s64 id offset))
  1473. (('i64.load32_s ($ <mem-arg> id offset _)) (load-s32 id offset))
  1474. (('i64.load32_u ($ <mem-arg> id offset _)) (load-u32 id offset))
  1475. (('i64.load16_s ($ <mem-arg> id offset _)) (load-s16 id offset))
  1476. (('i64.load16_u ($ <mem-arg> id offset _)) (load-u16 id offset))
  1477. (('i64.load8_s ($ <mem-arg> id offset _)) (load-s8 id offset))
  1478. (('i64.load8_u ($ <mem-arg> id offset _)) (load-u8 id offset))
  1479. (('f32.load ($ <mem-arg> id offset _)) (load-f32 id offset))
  1480. (('f64.load ($ <mem-arg> id offset _)) (load-f64 id offset))
  1481. (('i64.store ($ <mem-arg> id offset _)) (store-u64 id offset s64->u64))
  1482. (('i64.store32 ($ <mem-arg> id offset _)) (store-u32 id offset s64->u64))
  1483. (('i64.store16 ($ <mem-arg> id offset _)) (store-u16 id offset s64->u64))
  1484. (('i64.store8 ($ <mem-arg> id offset _)) (store-u8 id offset s64->u64))
  1485. (('f32.store ($ <mem-arg> id offset _)) (store-f32 id offset))
  1486. (('f64.store ($ <mem-arg> id offset _)) (store-f64 id offset))
  1487. (('memory.size id) (push (wasm-memory-size (memory-ref id))))
  1488. (('memory.grow id) (push (wasm-memory-grow! (memory-ref id) (pop))))
  1489. ;; Reference types:
  1490. (('table.get idx) (push (wasm-table-ref (table-ref idx) (pop))))
  1491. (('table.set idx)
  1492. (lets (i val) (wasm-table-set! (table-ref idx) i val)))
  1493. (('table.size idx) (push (wasm-table-size (table-ref idx))))
  1494. (('table.grow idx)
  1495. (lets (x n) (push (wasm-table-grow! (table-ref idx) n x))))
  1496. (('table.init dst src)
  1497. (lets (d s n) (wasm-table-init! (table-ref dst) d (elem-ref src) s n)))
  1498. (('table.fill idx)
  1499. (lets (i val n) (wasm-table-fill! (table-ref idx) i val n)))
  1500. (('table.copy dst src)
  1501. (lets (d s n) (wasm-table-copy! (table-ref dst) d (table-ref src) s n)))
  1502. (('elem.drop idx) (wasm-instance-drop-elem! instance idx))
  1503. (('ref.eq) (compare eq?))
  1504. (('ref.null t) (push (make-wasm-null (type-ref t))))
  1505. (('ref.as_non_null)
  1506. (let ((x (peek)))
  1507. (when (wasm-null? x)
  1508. (runtime-error "null value" x))))
  1509. (('ref.is_null) (compare1 wasm-null?))
  1510. (('ref.func idx) (push (func-ref idx)))
  1511. (('ref.test rt)
  1512. (push (if (can-downcast? (pop) rt) 1 0)))
  1513. (('ref.cast rt)
  1514. (let ((x (peek)))
  1515. (unless (can-downcast? x rt)
  1516. (runtime-error "invalid cast" x))))
  1517. (('br_on_cast l rt1 rt2)
  1518. (when (can-downcast? (peek) rt2)
  1519. (branch l)))
  1520. (('br_on_cast_fail l rt1 rt2)
  1521. (unless (can-downcast? (peek) rt2)
  1522. (branch l)))
  1523. (('ref.i31)
  1524. (let ((x (peek)))
  1525. (unless (s31? (peek))
  1526. (runtime-error "invalid i31" x))))
  1527. (('i31.get_s) #t)
  1528. (('i31.get_u) (unop s31->u31))
  1529. (('struct.new t)
  1530. (let ((type (type-ref t)))
  1531. (push
  1532. (make-wasm-struct type
  1533. (reverse
  1534. (map (lambda (_) (pop))
  1535. (struct-type-fields (resolve-type type))))))))
  1536. (('struct.new_default t)
  1537. (push
  1538. (let ((type (type-ref t)))
  1539. (make-wasm-struct type
  1540. (map (lambda (field)
  1541. (default-for-type (field-type field)))
  1542. (struct-type-fields (resolve-type type)))))))
  1543. (('struct.get _ field) (push (wasm-struct-ref (pop) field)))
  1544. (('struct.get_s _ field) (push (wasm-struct-ref-signed (pop) field)))
  1545. (('struct.get_u _ field) (push (wasm-struct-ref-unsigned (pop) field)))
  1546. (('struct.set _ field) (lets (s x) (wasm-struct-set! s field x)))
  1547. (('array.new t)
  1548. (lets (fill k) (push (make-wasm-array (type-ref t) (s32->u32 k) fill))))
  1549. (('array.new_fixed t k)
  1550. (let ((array (make-wasm-array (type-ref t) k)))
  1551. (do ((i (- k 1) (- i 1)))
  1552. ((< i 0))
  1553. (wasm-array-set! array i (pop)))
  1554. (push array)))
  1555. (('array.new_default t)
  1556. (lets (k)
  1557. (let ((type (type-ref t)))
  1558. (push (make-wasm-array type k
  1559. (default-for-type
  1560. (array-type-type
  1561. (resolve-type type))))))))
  1562. (('array.new_data t d)
  1563. (lets (offset k)
  1564. (let ((array (make-wasm-array (type-ref t) k)))
  1565. (wasm-array-init-data! array 0 (data-ref d) offset k)
  1566. (push array))))
  1567. (('array.new_elem t d)
  1568. (lets (offset k)
  1569. (let ((array (make-wasm-array (type-ref t) k)))
  1570. (wasm-array-init-elem! array 0 (elem-ref d) offset k)
  1571. (push array))))
  1572. (('array.init_data t d)
  1573. (lets (a at offset length)
  1574. (wasm-array-init-data! a at (data-ref d) offset length)))
  1575. (('array.init_elem t d)
  1576. (lets (a at offset length)
  1577. (wasm-array-init-elem! a at (elem-ref d) offset length)))
  1578. (('array.len) (lets (a) (push (wasm-array-length a))))
  1579. (('array.get _) (lets (a i) (push (wasm-array-ref a (s32->u32 i)))))
  1580. (('array.get_s _) (lets (a i) (push (wasm-array-ref-signed a (s32->u32 i)))))
  1581. (('array.get_u _) (lets (a i) (push (wasm-array-ref-unsigned a (s32->u32 i)))))
  1582. (('array.set _) (lets (a i x) (wasm-array-set! a (s32->u32 i) x)))
  1583. (('array.fill _) (lets (a d x n) (wasm-array-fill! a d x n)))
  1584. (('array.copy _ _) (lets (dst d src s n) (wasm-array-copy! dst d src s n)))
  1585. (('extern.internalize _) #t)
  1586. (('extern.externalize _) #t)
  1587. ;; Strings:
  1588. (('string.const idx) (push (string-ref idx)))
  1589. (('string.new_lossy_utf8_array)
  1590. (lets (array start end) (push (wasm-array->string array start end))))
  1591. (('string.encode_wtf8_array)
  1592. (lets (str array start)
  1593. (wasm-array-encode-string! array str start)
  1594. (push (string-utf8-length str))))
  1595. (((or 'string.measure_utf8 'string.measure_wtf8))
  1596. (lets (str) (push (string-utf8-length str))))
  1597. (('string.as_iter)
  1598. (lets (str)
  1599. (push (make-wasm-string-iterator str 0))))
  1600. (('stringview_iter.next)
  1601. (lets (iter) (push (wasm-string-iterator-next! iter))))
  1602. (('stringview_iter.advance)
  1603. (lets (iter k) (push (wasm-string-iterator-advance! iter k))))
  1604. (_ (runtime-error "unimplemented" instr))))
  1605. (define (execute* instrs path instance stack blocks locals)
  1606. (let loop ((instrs instrs) (i 0))
  1607. (match instrs
  1608. (() 'end)
  1609. ((instr . rest)
  1610. (execute instr (cons i path) instance stack blocks locals)
  1611. (loop rest (+ i 1))))))