assemble.scm 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941
  1. ;;; WebAssembly assembler
  2. ;;; Copyright (C) 2023 Igalia, S.L.
  3. ;;; Copyright (C) 2024 David Thompson <dave@spritely.institute>
  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. ;;; Assembler for WebAssembly.
  19. ;;;
  20. ;;; Code:
  21. (define-module (wasm assemble)
  22. #:use-module (ice-9 binary-ports)
  23. #:use-module (ice-9 match)
  24. #:use-module (rnrs bytevectors)
  25. #:use-module (wasm types)
  26. #:export (assemble-wasm))
  27. (define (assemble-wasm wasm)
  28. (define (put-uleb port val)
  29. (let lp ((val val))
  30. (let ((next (ash val -7)))
  31. (if (zero? next)
  32. (put-u8 port val)
  33. (begin
  34. (put-u8 port (logior #x80 (logand val #x7f)))
  35. (lp next))))))
  36. (define (put-sleb port val)
  37. (let lp ((val val))
  38. (if (<= 0 (+ val 64) 127)
  39. (put-u8 port (logand val #x7f))
  40. (begin
  41. (put-u8 port (logior #x80 (logand val #x7f)))
  42. (lp (ash val -7))))))
  43. (define (put-u32le port val)
  44. (let ((bv (u32vector 0)))
  45. (bytevector-u32-set! bv 0 val (endianness little))
  46. (put-bytevector port bv)))
  47. (define (->s32 val)
  48. (if (< val (ash 1 31)) val (- val (ash 1 32))))
  49. (define (->s64 val)
  50. (if (< val (ash 1 63)) val (- val (ash 1 64))))
  51. (define (emit-u8 port val) (put-u8 port val))
  52. (define (emit-u32 port val) (put-uleb port val))
  53. (define (emit-s32 port val) (put-sleb port (->s32 val)))
  54. (define (emit-s64 port val) (put-sleb port (->s64 val)))
  55. (define (emit-f32 port val) (put-bytevector port (f32vector val)))
  56. (define (emit-f64 port val) (put-bytevector port (f64vector val)))
  57. (define (emit-vec port items emit)
  58. (emit-u32 port (length items))
  59. (for-each (lambda (item) (emit port item)) items))
  60. (define (emit-vec/u8 port bv)
  61. (emit-u32 port (bytevector-length bv))
  62. (put-bytevector port bv))
  63. (define (emit-heap-type port ht)
  64. (match ht
  65. ((and (? exact-integer?) (not (? negative?))) (put-sleb port ht))
  66. ('nofunc (emit-u8 port #x73))
  67. ('noextern (emit-u8 port #x72))
  68. ('none (emit-u8 port #x71))
  69. ('func (emit-u8 port #x70))
  70. ('extern (emit-u8 port #x6F))
  71. ('any (emit-u8 port #x6E))
  72. ('eq (emit-u8 port #x6D))
  73. ('i31 (emit-u8 port #x6C))
  74. ('struct (emit-u8 port #x6B))
  75. ('array (emit-u8 port #x6A))
  76. ('string (emit-u8 port #x67))
  77. ('stringview_wtf8 (emit-u8 port #x66))
  78. ('stringview_wtf16 (emit-u8 port #x62))
  79. ('stringview_iter (emit-u8 port #x61))
  80. (_ (error "unexpected heap type" ht))))
  81. (define (emit-val-type port vt)
  82. (match vt
  83. ('i32 (emit-u8 port #x7F))
  84. ('i64 (emit-u8 port #x7E))
  85. ('f32 (emit-u8 port #x7D))
  86. ('f64 (emit-u8 port #x7C))
  87. ('v128 (emit-u8 port #x7B))
  88. ('nullfuncref (emit-u8 port #x73))
  89. ('nullexternref (emit-u8 port #x72))
  90. ('nullref (emit-u8 port #x71))
  91. ('funcref (emit-u8 port #x70))
  92. ('externref (emit-u8 port #x6F))
  93. ('anyref (emit-u8 port #x6E))
  94. ('eqref (emit-u8 port #x6D))
  95. ('i31ref (emit-u8 port #x6C))
  96. ('structref (emit-u8 port #x6B))
  97. ('arrayref (emit-u8 port #x6A))
  98. ;; Non-finalized proposals below.
  99. ('stringref (emit-u8 port #x67))
  100. ('stringview_wtf8ref (emit-u8 port #x66))
  101. ('stringview_wtf16ref (emit-u8 port #x62))
  102. ('stringview_iterref (emit-u8 port #x61))
  103. (($ <ref-type> nullable? ht)
  104. (emit-u8 port (if nullable? #x63 #x64))
  105. (emit-heap-type port ht))
  106. (_ (error "unexpected valtype" vt))))
  107. (define (emit-result-type port rt)
  108. (emit-vec port rt emit-val-type))
  109. (define (emit-block-type port bt)
  110. (match bt
  111. (#f (emit-u8 port #x40))
  112. ((? exact-integer?) (emit-u32 port bt))
  113. ((or (? symbol?) ($ <ref-type>)) (emit-val-type port bt))
  114. (($ <type-use> #f ($ <func-sig> () ())) (emit-u8 port #x40))
  115. (($ <type-use> #f ($ <func-sig> () (vt))) (emit-val-type port vt))
  116. (($ <type-use> idx) (emit-u32 port idx))))
  117. (define (emit-limits port limits)
  118. (match limits
  119. (($ <limits> min #f)
  120. (emit-u8 port #x00)
  121. (emit-u32 port min))
  122. (($ <limits> min max)
  123. (emit-u8 port #x01)
  124. (emit-u32 port min)
  125. (emit-u32 port max))))
  126. (define (emit-ref-type port rt)
  127. (match rt
  128. ((or 'i32 'i64 'f32 'f64 'i128)
  129. (error "unexpected reftype" rt))
  130. (_ (emit-val-type port rt))))
  131. (define (emit-elem-type port et)
  132. (emit-ref-type port et))
  133. (define (emit-table-type port tt)
  134. (match tt
  135. (($ <table-type> limits elem-type)
  136. (emit-elem-type port elem-type)
  137. (emit-limits port limits))))
  138. (define (emit-mem-type port mt)
  139. (match mt
  140. (($ <mem-type> limits) (emit-limits port limits))))
  141. (define (emit-global-type port gt)
  142. (match gt
  143. (($ <global-type> mutable? vt)
  144. (emit-val-type port vt)
  145. (emit-u8 port (if mutable? 1 0)))))
  146. (define (emit-name port str)
  147. (emit-vec/u8 port (string->utf8 str)))
  148. (define (emit-end port)
  149. (emit-u8 port #x0B))
  150. (define (emit-instruction port inst)
  151. (define (bad-instruction) (error "bad instruction" inst))
  152. (define-values (op args)
  153. (match inst
  154. ((op args ...) (values op args))
  155. (op (values op '()))))
  156. (define (emit code)
  157. (match args
  158. (() (emit-u8 port code))
  159. (_ (bad-instruction))))
  160. (define (emit-block code)
  161. (match args
  162. ((label bt insts)
  163. (emit-u8 port code)
  164. (emit-block-type port bt)
  165. (emit-instructions port insts)
  166. (emit-end port))
  167. (_ (bad-instruction))))
  168. (define (emit-if code)
  169. (define else-code #x05)
  170. (match args
  171. ((label bt consequent alternate)
  172. (emit-u8 port code)
  173. (emit-block-type port bt)
  174. (emit-instructions port consequent)
  175. (unless (null? alternate)
  176. (emit-u8 port else-code)
  177. (emit-instructions port alternate))
  178. (emit-end port))
  179. (_ (bad-instruction))))
  180. (define (emit-try code)
  181. (define catch-code #x07)
  182. (define delegate-code #x18)
  183. (define catch_all-code #x19)
  184. (match args
  185. ((label type body catches catch-all)
  186. (emit-u8 port code)
  187. (emit-instructions port body)
  188. (for-each (lambda (catch)
  189. (emit-u8 port catch-code)
  190. (emit-instructions port catch))
  191. catches)
  192. (when catch-all
  193. (emit-u8 port catch_all-code)
  194. (emit-instructions port catch-all))
  195. (emit-end port))))
  196. (define (emit-try_delegate code)
  197. (define delegate-code #x18)
  198. (match args
  199. ((label type body delegate)
  200. (emit-u8 port code)
  201. (emit-instructions port body)
  202. (emit-u8 port delegate-code)
  203. (emit-u32 port delegate))))
  204. (define (emit-idx code)
  205. (match args
  206. ((idx)
  207. (emit-u8 port code)
  208. (emit-u32 port idx))
  209. (_ (bad-instruction))))
  210. (define (emit-br_table code)
  211. (match args
  212. ((targets default)
  213. (emit-u8 port code)
  214. (emit-vec port targets emit-u32)
  215. (emit-u32 port default))
  216. (_ (bad-instruction))))
  217. (define (emit-call_indirect code)
  218. (match args
  219. ((table type)
  220. (emit-u8 port code)
  221. (emit-u32 port type)
  222. (emit-u32 port table))
  223. (_ (bad-instruction))))
  224. (define (emit-select old-code new-code)
  225. (match args
  226. (()
  227. (emit-u8 port old-code))
  228. ((types)
  229. (emit-u8 port new-code)
  230. (emit-vec port types emit-val-type))
  231. (_ (bad-instruction))))
  232. (define (emit-mem code)
  233. (match args
  234. ((($ <mem-arg> id offset align))
  235. (emit-u8 port code)
  236. (emit-u32 port
  237. (if (zero? id)
  238. align
  239. (logior align (ash 1 6))))
  240. (unless (zero? id)
  241. (emit-u32 port id))
  242. (emit-u32 port offset))
  243. (_ (bad-instruction))))
  244. (define (emit-const code emit-val)
  245. (match args
  246. ((val)
  247. (emit-u8 port code)
  248. (emit-val port val))
  249. (_ (bad-instruction))))
  250. (define (emit-ht code)
  251. (match args
  252. ((ht)
  253. (emit-u8 port code)
  254. (emit-heap-type port ht))
  255. (_ (bad-instruction))))
  256. (define (emit-gc-op code)
  257. (emit-u8 port #xfb)
  258. (put-uleb port code))
  259. (define (emit-gc code)
  260. (match args
  261. (() (emit-gc-op code))
  262. (_ (bad-instruction))))
  263. (define (emit-gc-idx code)
  264. (match args
  265. ((idx)
  266. (emit-gc-op code)
  267. (emit-u32 port idx))
  268. (_ (bad-instruction))))
  269. (define (emit-gc-idx-idx code)
  270. (match args
  271. ((idx0 idx1)
  272. (emit-gc-op code)
  273. (emit-u32 port idx0)
  274. (emit-u32 port idx1))
  275. (_ (bad-instruction))))
  276. (define (emit-gc-idx-len code)
  277. (emit-gc-idx-idx code))
  278. (define (emit-gc-rt code nullable-code)
  279. (match args
  280. ((($ <ref-type> nullable? ht))
  281. (emit-gc-op (if nullable? nullable-code code))
  282. (emit-heap-type port ht))
  283. (_ (bad-instruction))))
  284. (define (emit-gc-idx-rt-rt code)
  285. (match args
  286. ((idx ($ <ref-type> nullable1? ht1) ($ <ref-type> nullable2? ht2))
  287. (emit-gc-op code)
  288. (emit-u8 port (logior (if nullable1? 1 0) (if nullable2? 2 0)))
  289. (emit-idx idx)
  290. (emit-heap-type port ht1)
  291. (emit-heap-type port ht2))))
  292. (define (emit-misc-op code)
  293. (emit-u8 port #xfc)
  294. (put-uleb port code))
  295. (define (emit-misc code)
  296. (match args
  297. (()
  298. (emit-misc-op code))
  299. (_ (bad-instruction))))
  300. (define (emit-misc-idx code)
  301. (match args
  302. ((idx)
  303. (emit-misc-op code)
  304. (emit-u32 port idx))
  305. (_ (bad-instruction))))
  306. (define (emit-misc-idx-idx code)
  307. (match args
  308. ((idx0 idx1)
  309. (emit-misc-op code)
  310. (emit-u32 port idx0)
  311. (emit-u32 port idx1))
  312. (_ (bad-instruction))))
  313. (define (emit-simd-splat code)
  314. (match args
  315. (()
  316. (emit-u8 port #xfd)
  317. (emit-u32 port code))
  318. (_ (bad-instruction))))
  319. (match op
  320. ('unreachable (emit #x00))
  321. ('nop (emit #x01))
  322. ('block (emit-block #x02))
  323. ('loop (emit-block #x03))
  324. ('if (emit-if #x04))
  325. ('try (emit-try #x06))
  326. ('try_delegate (emit-try_delegate #x06))
  327. ('throw (emit-idx #x08))
  328. ('rethrow (emit-idx #x09))
  329. ('br (emit-idx #x0C))
  330. ('br_if (emit-idx #x0D))
  331. ('br_table (emit-br_table #x0E))
  332. ('return (emit #x0F))
  333. ('call (emit-idx #x10))
  334. ('call_indirect (emit-call_indirect #x11))
  335. ('return_call (emit-idx #x12))
  336. ('return_call_indirect (emit-call_indirect #x13))
  337. ('call_ref (emit-idx #x14))
  338. ('return_call_ref (emit-idx #x15))
  339. ('drop (emit #x1A))
  340. ('select (emit-select #x1B #x1C))
  341. ('local.get (emit-idx #x20))
  342. ('local.set (emit-idx #x21))
  343. ('local.tee (emit-idx #x22))
  344. ('global.get (emit-idx #x23))
  345. ('global.set (emit-idx #x24))
  346. ('table.get (emit-idx #x25))
  347. ('table.set (emit-idx #x26))
  348. ('i32.load (emit-mem #x28))
  349. ('i64.load (emit-mem #x29))
  350. ('f32.load (emit-mem #x2A))
  351. ('f64.load (emit-mem #x2B))
  352. ('i32.load8_s (emit-mem #x2C))
  353. ('i32.load8_u (emit-mem #x2D))
  354. ('i32.load16_s (emit-mem #x2E))
  355. ('i32.load16_u (emit-mem #x2F))
  356. ('i64.load8_s (emit-mem #x30))
  357. ('i64.load8_u (emit-mem #x31))
  358. ('i64.load16_s (emit-mem #x32))
  359. ('i64.load16_u (emit-mem #x33))
  360. ('i64.load32_s (emit-mem #x34))
  361. ('i64.load32_u (emit-mem #x35))
  362. ('i32.store (emit-mem #x36))
  363. ('i64.store (emit-mem #x37))
  364. ('f32.store (emit-mem #x38))
  365. ('f64.store (emit-mem #x39))
  366. ('i32.store8 (emit-mem #x3A))
  367. ('i32.store16 (emit-mem #x3B))
  368. ('i64.store8 (emit-mem #x3C))
  369. ('i64.store16 (emit-mem #x3D))
  370. ('i64.store32 (emit-mem #x3E))
  371. ('memory.size (emit-idx #x3F))
  372. ('memory.grow (emit-idx #x40))
  373. ('i32.const (emit-const #x41 emit-s32))
  374. ('i64.const (emit-const #x42 emit-s64))
  375. ('f32.const (emit-const #x43 emit-f32))
  376. ('f64.const (emit-const #x44 emit-f64))
  377. ('i32.eqz (emit #x45))
  378. ('i32.eq (emit #x46))
  379. ('i32.ne (emit #x47))
  380. ('i32.lt_s (emit #x48))
  381. ('i32.lt_u (emit #x49))
  382. ('i32.gt_s (emit #x4A))
  383. ('i32.gt_u (emit #x4B))
  384. ('i32.le_s (emit #x4C))
  385. ('i32.le_u (emit #x4D))
  386. ('i32.ge_s (emit #x4E))
  387. ('i32.ge_u (emit #x4F))
  388. ('i64.eqz (emit #x50))
  389. ('i64.eq (emit #x51))
  390. ('i64.ne (emit #x52))
  391. ('i64.lt_s (emit #x53))
  392. ('i64.lt_u (emit #x54))
  393. ('i64.gt_s (emit #x55))
  394. ('i64.gt_u (emit #x56))
  395. ('i64.le_s (emit #x57))
  396. ('i64.le_u (emit #x58))
  397. ('i64.ge_s (emit #x59))
  398. ('i64.ge_u (emit #x5A))
  399. ('f32.eq (emit #x5B))
  400. ('f32.ne (emit #x5C))
  401. ('f32.lt (emit #x5D))
  402. ('f32.gt (emit #x5E))
  403. ('f32.le (emit #x5F))
  404. ('f32.ge (emit #x60))
  405. ('f64.eq (emit #x61))
  406. ('f64.ne (emit #x62))
  407. ('f64.lt (emit #x63))
  408. ('f64.gt (emit #x64))
  409. ('f64.le (emit #x65))
  410. ('f64.ge (emit #x66))
  411. ('i32.clz (emit #x67))
  412. ('i32.ctz (emit #x68))
  413. ('i32.popcnt (emit #x69))
  414. ('i32.add (emit #x6A))
  415. ('i32.sub (emit #x6B))
  416. ('i32.mul (emit #x6C))
  417. ('i32.div_s (emit #x6D))
  418. ('i32.div_u (emit #x6E))
  419. ('i32.rem_s (emit #x6F))
  420. ('i32.rem_u (emit #x70))
  421. ('i32.and (emit #x71))
  422. ('i32.or (emit #x72))
  423. ('i32.xor (emit #x73))
  424. ('i32.shl (emit #x74))
  425. ('i32.shr_s (emit #x75))
  426. ('i32.shr_u (emit #x76))
  427. ('i32.rotl (emit #x77))
  428. ('i32.rotr (emit #x78))
  429. ('i64.clz (emit #x79))
  430. ('i64.ctz (emit #x7A))
  431. ('i64.popcnt (emit #x7B))
  432. ('i64.add (emit #x7C))
  433. ('i64.sub (emit #x7D))
  434. ('i64.mul (emit #x7E))
  435. ('i64.div_s (emit #x7F))
  436. ('i64.div_u (emit #x80))
  437. ('i64.rem_s (emit #x81))
  438. ('i64.rem_u (emit #x82))
  439. ('i64.and (emit #x83))
  440. ('i64.or (emit #x84))
  441. ('i64.xor (emit #x85))
  442. ('i64.shl (emit #x86))
  443. ('i64.shr_s (emit #x87))
  444. ('i64.shr_u (emit #x88))
  445. ('i64.rotl (emit #x89))
  446. ('i64.rotr (emit #x8A))
  447. ('f32.abs (emit #x8B))
  448. ('f32.neg (emit #x8C))
  449. ('f32.ceil (emit #x8D))
  450. ('f32.floor (emit #x8E))
  451. ('f32.trunc (emit #x8F))
  452. ('f32.nearest (emit #x90))
  453. ('f32.sqrt (emit #x91))
  454. ('f32.add (emit #x92))
  455. ('f32.sub (emit #x93))
  456. ('f32.mul (emit #x94))
  457. ('f32.div (emit #x95))
  458. ('f32.min (emit #x96))
  459. ('f32.max (emit #x97))
  460. ('f32.copysign (emit #x98))
  461. ('f64.abs (emit #x99))
  462. ('f64.neg (emit #x9A))
  463. ('f64.ceil (emit #x9B))
  464. ('f64.floor (emit #x9C))
  465. ('f64.trunc (emit #x9D))
  466. ('f64.nearest (emit #x9E))
  467. ('f64.sqrt (emit #x9F))
  468. ('f64.add (emit #xA0))
  469. ('f64.sub (emit #xA1))
  470. ('f64.mul (emit #xA2))
  471. ('f64.div (emit #xA3))
  472. ('f64.min (emit #xA4))
  473. ('f64.max (emit #xA5))
  474. ('f64.copysign (emit #xA6))
  475. ('i32.wrap_i64 (emit #xA7))
  476. ('i32.trunc_f32_s (emit #xA8))
  477. ('i32.trunc_f32_u (emit #xA9))
  478. ('i32.trunc_f64_s (emit #xAA))
  479. ('i32.trunc_f64_u (emit #xAB))
  480. ('i64.extend_i32_s (emit #xAC))
  481. ('i64.extend_i32_u (emit #xAD))
  482. ('i64.trunc_f32_s (emit #xAE))
  483. ('i64.trunc_f32_u (emit #xAF))
  484. ('i64.trunc_f64_s (emit #xB0))
  485. ('i64.trunc_f64_u (emit #xB1))
  486. ('f32.convert_i32_s (emit #xB2))
  487. ('f32.convert_i32_u (emit #xB3))
  488. ('f32.convert_i64_s (emit #xB4))
  489. ('f32.convert_i64_u (emit #xB5))
  490. ('f32.demote_f64 (emit #xB6))
  491. ('f64.convert_i32_s (emit #xB7))
  492. ('f64.convert_i32_u (emit #xB8))
  493. ('f64.convert_i64_s (emit #xB9))
  494. ('f64.convert_i64_u (emit #xBA))
  495. ('f64.promote_f32 (emit #xBB))
  496. ('i32.reinterpret_f32 (emit #xBC))
  497. ('i64.reinterpret_f64 (emit #xBD))
  498. ('f32.reinterpret_i32 (emit #xBE))
  499. ('f64.reinterpret_i64 (emit #xBF))
  500. ('i32.extend8_s (emit #xc0))
  501. ('i32.extend16_s (emit #xc1))
  502. ('i64.extend8_s (emit #xc2))
  503. ('i64.extend16_s (emit #xc3))
  504. ('i64.extend32_s (emit #xc4))
  505. ;; GC.
  506. ('ref.null (emit-ht #xd0))
  507. ('ref.is_null (emit #xd1))
  508. ('ref.func (emit-idx #xd2))
  509. ('ref.eq (emit #xd3))
  510. ('ref.as_non_null (emit #xd4))
  511. ('struct.new (emit-gc-idx 0))
  512. ('struct.new_default (emit-gc-idx 1))
  513. ('struct.get (emit-gc-idx-idx 2))
  514. ('struct.get_s (emit-gc-idx-idx 3))
  515. ('struct.get_u (emit-gc-idx-idx 4))
  516. ('struct.set (emit-gc-idx-idx 5))
  517. ('array.new (emit-gc-idx 6))
  518. ('array.new_default (emit-gc-idx 7))
  519. ('array.new_fixed (emit-gc-idx-len 8))
  520. ('array.new_data (emit-gc-idx-idx 9))
  521. ('array.new_elem (emit-gc-idx-idx 10))
  522. ('array.get (emit-gc-idx 11))
  523. ('array.get_s (emit-gc-idx 12))
  524. ('array.get_u (emit-gc-idx 13))
  525. ('array.set (emit-gc-idx 14))
  526. ('array.len (emit-gc 15))
  527. ('array.fill (emit-gc-idx 16))
  528. ('array.copy (emit-gc-idx-idx 17))
  529. ('array.init_data (emit-gc-idx-idx 18))
  530. ('array.init_elem (emit-gc-idx-idx 19))
  531. ('ref.test (emit-gc-rt 20 21))
  532. ('ref.cast (emit-gc-rt 22 23))
  533. ('br_on_cast (emit-gc-idx-rt-rt 24))
  534. ('br_on_cast_fail (emit-gc-idx-rt-rt 25))
  535. ('extern.internalize (emit-gc 26))
  536. ('extern.externalize (emit-gc 27))
  537. ('ref.i31 (emit-gc 28))
  538. ('i31.get_s (emit-gc 29))
  539. ('i31.get_u (emit-gc 30))
  540. ;; Stringref.
  541. ('string.new_utf8 (emit-gc-idx #x80))
  542. ('string.new_wtf16 (emit-gc-idx #x81))
  543. ('string.const (emit-gc-idx #x82))
  544. ('string.measure_utf8 (emit-gc #x83))
  545. ('string.measure_wtf8 (emit-gc #x84))
  546. ('string.measure_wtf16 (emit-gc #x85))
  547. ('string.encode_utf8 (emit-gc-idx #x86))
  548. ('string.encode_wtf16 (emit-gc-idx #x87))
  549. ('string.concat (emit-gc #x88))
  550. ('string.eq (emit-gc #x89))
  551. ('string.is_usv_sequence (emit-gc #x8a))
  552. ('string.new_lossy_utf8 (emit-gc-idx #x8b))
  553. ('string.new_wtf8 (emit-gc-idx #x8c))
  554. ('string.encode_lossy_utf8 (emit-gc-idx #x8d))
  555. ('string.encode_wtf8 (emit-gc-idx #x8e))
  556. ('string.as_wtf8 (emit-gc #x90))
  557. ('stringview_wtf8.advance (emit-gc #x91))
  558. ('stringview_wtf8.encode_utf8 (emit-gc-idx #x92))
  559. ('stringview_wtf8.slice (emit-gc #x93))
  560. ('stringview_wtf8.encode_lossy_utf8 (emit-gc-idx #x94))
  561. ('stringview_wtf8.encode_wtf8 (emit-gc-idx #x95))
  562. ('string.as_wtf16 (emit-gc #x98))
  563. ('stringview_wtf16.length (emit-gc #x99))
  564. ('stringview_wtf16.get_codeunit (emit-gc #x9a))
  565. ('stringview_wtf16.encode (emit-gc-idx #x9b))
  566. ('stringview_wtf16.slice (emit-gc #x9c))
  567. ('string.as_iter (emit-gc #xa0))
  568. ('stringview_iter.next (emit-gc #xa1))
  569. ('stringview_iter.advance (emit-gc #xa2))
  570. ('stringview_iter.rewind (emit-gc #xa3))
  571. ('stringview_iter.slice (emit-gc #xa4))
  572. ('string.compare (emit-gc #xa8))
  573. ('string.from_code_point (emit-gc #xa9))
  574. ('string.new_utf8_array (emit-gc #xb0))
  575. ('string.new_wtf16_array (emit-gc #xb1))
  576. ('string.encode_utf8_array (emit-gc #xb2))
  577. ('string.encode_wtf16_array (emit-gc #xb3))
  578. ('string.new_lossy_utf8_array (emit-gc #xb4))
  579. ('string.new_wtf8_array (emit-gc #xb5))
  580. ('string.encode_lossy_utf8_array (emit-gc #xb6))
  581. ('string.encode_wtf8_array (emit-gc #xb7))
  582. ;; Vector opcodes.
  583. ('i8x16.splat (emit-simd-splat #x0f))
  584. ('i16x8.splat (emit-simd-splat #x10))
  585. ('i32x4.splat (emit-simd-splat #x11))
  586. ('i64x2.splat (emit-simd-splat #x12))
  587. ('f32x4.splat (emit-simd-splat #x13))
  588. ('f64x2.splat (emit-simd-splat #x14))
  589. ;; Misc opcodes.
  590. ('i32.trunc_sat_f32_s (emit-misc #x00))
  591. ('i32.trunc_sat_f32_u (emit-misc #x01))
  592. ('i32.trunc_sat_f64_s (emit-misc #x02))
  593. ('i32.trunc_sat_f64_u (emit-misc #x03))
  594. ('i64.trunc_sat_f32_s (emit-misc #x04))
  595. ('i64.trunc_sat_f32_u (emit-misc #x05))
  596. ('i64.trunc_sat_f64_s (emit-misc #x06))
  597. ('i64.trunc_sat_f64_u (emit-misc #x07))
  598. ('memory.init (emit-misc-idx-idx #x08))
  599. ('data.drop (emit-misc-idx #x09))
  600. ('memory.copy (emit-misc-idx-idx #x0a))
  601. ('memory.fill (emit-misc-idx #x0b))
  602. ('table.init (emit-misc-idx-idx #x0c))
  603. ('elem.drop (emit-misc-idx #x0d))
  604. ('table.copy (emit-misc-idx-idx #x0e))
  605. ('table.grow (emit-misc-idx #x0f))
  606. ('table.size (emit-misc-idx #x10))
  607. ('table.fill (emit-misc-idx #x11))
  608. (_ (bad-instruction))))
  609. (define (emit-instructions port insts)
  610. (for-each (lambda (inst) (emit-instruction port inst)) insts))
  611. (define (emit-expr port expr)
  612. (emit-instructions port expr)
  613. (emit-end port))
  614. (define (emit-type-def port def)
  615. (define (emit-field-type port mutable? st)
  616. (match st
  617. ('i8 (emit-u8 port #x78))
  618. ('i16 (emit-u8 port #x77))
  619. (_ (emit-val-type port st)))
  620. (emit-u8 port (if mutable? 1 0)))
  621. (define (emit-field port field)
  622. (match field
  623. (($ <field> id mutable? type)
  624. (emit-field-type port mutable? type))))
  625. (define (emit-base-type-def port def)
  626. (match def
  627. (($ <func-sig> (($ <param> _ param-type) ...) (result-type ...))
  628. (emit-u8 port #x60)
  629. (emit-result-type port param-type)
  630. (emit-result-type port result-type))
  631. (($ <struct-type> fields)
  632. (emit-u8 port #x5f)
  633. (emit-vec port fields emit-field))
  634. (($ <array-type> mutable? type)
  635. (emit-u8 port #x5e)
  636. (emit-field-type port mutable? type))))
  637. (define (emit-sub-type-def port def)
  638. (match def
  639. (($ <sub-type> final? supers def)
  640. (emit-u8 port (if final? #x4f #x50))
  641. (emit-vec port supers emit-u32)
  642. (emit-base-type-def port def))
  643. (_ (emit-base-type-def port def))))
  644. (match def
  645. (($ <rec-group> (($ <type> _ def) ...))
  646. (emit-u8 port #x4e)
  647. (emit-vec port def emit-sub-type-def))
  648. (($ <type> id def)
  649. (emit-sub-type-def port def))))
  650. (define (emit-type-use port type)
  651. (match type
  652. (($ <type-use> idx)
  653. (emit-u32 port idx))))
  654. (define (emit-import port import)
  655. (match import
  656. (($ <import> mod name kind id type)
  657. (emit-name port mod)
  658. (emit-name port name)
  659. (match kind
  660. ('func
  661. (emit-u8 port #x00)
  662. (emit-type-use port type))
  663. ('table
  664. (emit-u8 port #x01)
  665. (emit-table-type port type))
  666. ('memory
  667. (emit-u8 port #x02)
  668. (emit-mem-type port type))
  669. ('global
  670. (emit-u8 port #x03)
  671. (emit-global-type port type))))))
  672. (define (emit-func-decl port func)
  673. (match func
  674. (($ <func> id type locals body)
  675. (emit-type-use port type))))
  676. (define (emit-table port table)
  677. (match table
  678. (($ <table> id type #f)
  679. (emit-table-type port type))
  680. (($ <table> id type init)
  681. (emit-u8 port #x40)
  682. (emit-u8 port #x00)
  683. (emit-table-type port type)
  684. (emit-expr port init))))
  685. (define (emit-memory port memory)
  686. (match memory
  687. (($ <memory> id type)
  688. (emit-mem-type port type))))
  689. (define (emit-global port global)
  690. (match global
  691. (($ <global> id type init)
  692. (emit-global-type port type)
  693. (emit-expr port init))))
  694. (define (emit-export port export)
  695. (match export
  696. (($ <export> name kind id)
  697. (emit-name port name)
  698. (match kind
  699. ('func (emit-u8 port #x00))
  700. ('table (emit-u8 port #x01))
  701. ('memory (emit-u8 port #x02))
  702. ('global (emit-u8 port #x03)))
  703. (emit-u32 port id))))
  704. (define (emit-element port elem)
  705. (match elem
  706. (($ <elem> id 'active 0 'funcref offset ((('ref.func idx)) ...))
  707. (emit-u8 port #x00)
  708. (emit-expr port offset)
  709. (emit-vec port idx emit-u32))
  710. (($ <elem> id 'passive #f 'funcref #f ((('ref.func idx)) ...))
  711. (emit-u8 port #x01)
  712. (emit-u8 port #x00) ;; elemkind: funcref
  713. (emit-vec port idx emit-u32))
  714. (($ <elem> id 'active table 'funcref offset ((('ref.func idx)) ...))
  715. (emit-u8 port #x02)
  716. (emit-u32 port table)
  717. (emit-expr port offset)
  718. (emit-u8 port #x00) ;; elemkind: funcref
  719. (emit-vec port idx emit-u32))
  720. (($ <elem> id 'declarative #f 'funcref #f ((('ref.func idx)) ...))
  721. (emit-u8 port #x03)
  722. (emit-u8 port #x00) ;; elemkind: funcref
  723. (emit-vec port idx emit-u32))
  724. (($ <elem> id 'active 0 'funcref offset (expr ...))
  725. (emit-u8 port #x04)
  726. (emit-expr port offset)
  727. (emit-vec port expr emit-expr))
  728. (($ <elem> id 'passive #f type #f (expr ...))
  729. (emit-u8 port #x05)
  730. (emit-ref-type port type)
  731. (emit-vec port expr emit-expr))
  732. (($ <elem> id 'active table type offset (expr ...))
  733. (emit-u8 port #x06)
  734. (emit-u32 port table)
  735. (emit-expr port offset)
  736. (emit-ref-type port type)
  737. (emit-vec port expr emit-expr))
  738. (($ <elem> id 'declarative #f type #f (expr ...))
  739. (emit-u8 port #x07)
  740. (emit-ref-type port type)
  741. (emit-vec port expr emit-expr))))
  742. (define (emit-func-def port func)
  743. (define (emit-compressed-locals port locals)
  744. (define compressed
  745. (let compress ((locals locals))
  746. (match locals
  747. (() '())
  748. ((($ <local> id type) . locals)
  749. (match (compress locals)
  750. (((count . (? (lambda (vt) (equal? vt type)))) . compressed)
  751. (acons (1+ count) type compressed))
  752. (compressed (acons 1 type compressed)))))))
  753. (emit-vec port compressed
  754. (lambda (port pair)
  755. (match pair
  756. ((count . vt)
  757. (emit-u32 port count)
  758. (emit-val-type port vt))))))
  759. (match func
  760. (($ <func> id type locals body)
  761. (emit-vec/u8 port
  762. (call-with-output-bytevector
  763. (lambda (port)
  764. (emit-compressed-locals port locals)
  765. (emit-expr port body)))))))
  766. (define (emit-data port data)
  767. (match data
  768. (($ <data> id 'active 0 offset init)
  769. (emit-u8 port #x00)
  770. (emit-expr port offset)
  771. (emit-vec/u8 port init))
  772. (($ <data> id 'passive #f offset init)
  773. (emit-u8 port #x01)
  774. (emit-vec/u8 port init))
  775. (($ <data> id 'active mem offset init)
  776. (emit-u8 port #x02)
  777. (emit-u32 port mem)
  778. (emit-expr port offset)
  779. (emit-vec/u8 port init))))
  780. (define (emit-custom port custom)
  781. (match custom
  782. (($ <custom> name bytes)
  783. (emit-name port name)
  784. (put-bytevector port bytes))
  785. (($ <names> module function local label type table memory global elem
  786. data field tag)
  787. (define (id->string id)
  788. (substring (symbol->string id) 1))
  789. (define (emit-name-map port name-map)
  790. (emit-vec port name-map
  791. (lambda (port pair)
  792. (match pair
  793. ((id . name)
  794. (emit-u32 port id)
  795. (emit-name port (id->string name)))))))
  796. (define (emit-indirect-name-map port iname-map)
  797. (emit-vec port iname-map
  798. (lambda (port pair)
  799. (match pair
  800. ((id . name-map)
  801. (emit-u32 port id)
  802. (emit-name-map port name-map))))))
  803. (define (emit-subsection port id subsection)
  804. (emit-u8 port id)
  805. (emit-vec/u8 port subsection))
  806. (define (emit-names port id name-map)
  807. (unless (null? name-map)
  808. (emit-subsection port id
  809. (call-with-output-bytevector
  810. (lambda (port)
  811. (emit-name-map port name-map))))))
  812. (define (emit-indirect-names port id iname-map)
  813. (unless (null? iname-map)
  814. (emit-subsection port id
  815. (call-with-output-bytevector
  816. (lambda (port)
  817. (emit-indirect-name-map port iname-map))))))
  818. (let ((bytes
  819. (call-with-output-bytevector
  820. (lambda (port)
  821. (when module
  822. (emit-subsection port 0
  823. (call-with-output-bytevector
  824. (lambda (port)
  825. (emit-name port (id->string module))))))
  826. (emit-names port 1 function)
  827. (emit-indirect-names port 2 local)
  828. (emit-indirect-names port 3 label)
  829. (emit-names port 4 type)
  830. (emit-names port 5 table)
  831. (emit-names port 6 memory)
  832. (emit-names port 7 global)
  833. (emit-names port 8 elem)
  834. (emit-names port 9 data)
  835. (emit-indirect-names port 10 field)
  836. (emit-names port 11 tag)))))
  837. (emit-custom port (make-custom "name" bytes))))))
  838. (define (emit-tag port tag)
  839. (match tag
  840. (($ <tag> id ($ <type-use> idx _))
  841. (emit-u32 port idx))))
  842. (define (emit-section port code bytes)
  843. (emit-u8 port code)
  844. (emit-vec/u8 port bytes))
  845. (define (emit-vec-section port code items emit-item)
  846. (unless (null? items)
  847. (emit-section port code
  848. (call-with-output-bytevector
  849. (lambda (port)
  850. (emit-vec port items emit-item))))))
  851. (match wasm
  852. (($ <wasm> id types imports funcs tables memories globals exports start
  853. elems datas tags strings custom)
  854. (call-with-output-bytevector
  855. (lambda (port)
  856. (put-bytevector port #vu8(#x00 #x61 #x73 #x6d)) ;; "\0asm"
  857. (put-bytevector port #vu8(1 0 0 0)) ;; version
  858. (emit-vec-section port 1 types emit-type-def)
  859. (emit-vec-section port 2 imports emit-import)
  860. (emit-vec-section port 3 funcs emit-func-decl)
  861. (emit-vec-section port 4 tables emit-table)
  862. (emit-vec-section port 5 memories emit-memory)
  863. (emit-vec-section port 13 tags emit-tag)
  864. (unless (null? strings)
  865. (emit-section port 14 (call-with-output-bytevector
  866. (lambda (port)
  867. (emit-u8 port #x00)
  868. (emit-vec port strings emit-name)))))
  869. (emit-vec-section port 6 globals emit-global)
  870. (emit-vec-section port 7 exports emit-export)
  871. (when start
  872. (emit-section port 8 (call-with-output-bytevector
  873. (lambda (port)
  874. (emit-u32 port start)))))
  875. (emit-vec-section port 9 elems emit-element)
  876. (unless (null? datas)
  877. (emit-section port 12 (call-with-output-bytevector
  878. (lambda (port)
  879. (emit-u32 port (length datas))))))
  880. (emit-vec-section port 10 funcs emit-func-def)
  881. (emit-vec-section port 11 datas emit-data)
  882. (unless (null? custom)
  883. (for-each (lambda (custom)
  884. (emit-section port 0
  885. (call-with-output-bytevector
  886. (lambda (port)
  887. (emit-custom port custom)))))
  888. custom)))))))