vm.scm 69 KB

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