assemble.scm 35 KB

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