vm.scm 70 KB

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