vm.scm 69 KB

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