resolve.scm 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707
  1. ;;; WebAssembly resolver
  2. ;;; Copyright (C) 2023, 2025 Igalia, S.L.
  3. ;;; Copyright (C) 2023 Robin Templeton <robin@spritely.institute>
  4. ;;; Copyright (C) 2023 David Thompson <dave@spritely.institute>
  5. ;;;
  6. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  7. ;;; you may not use this file except in compliance with the License.
  8. ;;; You may obtain a copy of the License at
  9. ;;;
  10. ;;; http://www.apache.org/licenses/LICENSE-2.0
  11. ;;;
  12. ;;; Unless required by applicable law or agreed to in writing, software
  13. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  14. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. ;;; See the License for the specific language governing permissions and
  16. ;;; limitations under the License.
  17. ;;; Commentary:
  18. ;;;
  19. ;;; Lowers WASM with human readable identifiers to WASM with only
  20. ;;; index references.
  21. ;;;
  22. ;;; Code:
  23. (define-module (wasm resolve)
  24. #:use-module (ice-9 match)
  25. #:use-module (srfi srfi-11)
  26. #:use-module (wasm types)
  27. #:export (resolve-wasm))
  28. (define (fold1 f l s0)
  29. (let lp ((l l) (s0 s0))
  30. (match l
  31. (() s0)
  32. ((elt . l) (lp l (f elt s0))))))
  33. (define (alist-sort alist)
  34. (sort alist (lambda (a b) (< (car a) (car b)))))
  35. (define (make-name-store)
  36. (let ((count 0)
  37. (ids (make-hash-table)))
  38. (values (lambda (id)
  39. (let ((idx count))
  40. (set! count (1+ count))
  41. (when id (hashq-set! ids id idx))
  42. idx))
  43. (lambda (id)
  44. (cond
  45. ((exact-integer? id) id)
  46. ((hashq-ref ids id))
  47. (else (error "unbound identifier" id))))
  48. (lambda ()
  49. (alist-sort
  50. (hash-fold (lambda (name idx result)
  51. (cons (cons idx name) result))
  52. '() ids))))))
  53. (define (make-indirect-name-store)
  54. (let ((table (make-hash-table)))
  55. (values (lambda (parent-id parent-idx id)
  56. (match (hashq-ref table parent-idx)
  57. (#f
  58. (let-values (((add-id! resolve-id name-map) (make-name-store)))
  59. (let ((procs (list add-id! resolve-id name-map)))
  60. (hashq-set! table parent-idx procs)
  61. (when parent-id
  62. (hashq-set! table parent-id procs)))
  63. (add-id! id)))
  64. ((add-id! resolve-id name-map)
  65. (add-id! id))))
  66. (lambda (parent-id-or-idx id-or-idx)
  67. (if (exact-integer? id-or-idx)
  68. id-or-idx
  69. (match (hashq-ref table parent-id-or-idx)
  70. ((add-id! resolve-id name-map)
  71. (resolve-id id-or-idx)))))
  72. (lambda ()
  73. (alist-sort
  74. (hash-fold
  75. (lambda (id-or-idx procs result)
  76. (if (exact-integer? id-or-idx)
  77. (match procs
  78. ((_ _ name-map)
  79. (match (name-map)
  80. ((name-map ..1) (cons (cons id-or-idx name-map) result))
  81. (_ result))))
  82. result))
  83. '()
  84. table))))))
  85. (define-syntax match-inst
  86. (syntax-rules (_)
  87. ((match-inst inst ((head . tail) . body) ... (_ . default))
  88. (match inst
  89. ((op . args)
  90. (match op
  91. (head (match args (tail . body)))
  92. ...
  93. (_ . default)))))))
  94. (define* (resolve-wasm mod #:key emit-names?)
  95. (define-values (add-type-id! resolve-type type-name-map) (make-name-store))
  96. (define-values (add-func-id! resolve-func func-name-map) (make-name-store))
  97. (define-values (add-table-id! resolve-table table-name-map) (make-name-store))
  98. (define-values (add-memory-id! resolve-memory memory-name-map) (make-name-store))
  99. (define-values (add-global-id! resolve-global global-name-map) (make-name-store))
  100. (define-values (add-elem-id! resolve-elem elem-name-map) (make-name-store))
  101. (define-values (add-data-id! resolve-data data-name-map) (make-name-store))
  102. (define-values (add-tag-id! resolve-tag tag-name-map) (make-name-store))
  103. (define-values (add-struct-field! resolve-struct-field struct-field-name-map)
  104. (make-indirect-name-store))
  105. (define-values (add-func-local! resolve-func-local func-local-name-map)
  106. (make-indirect-name-store))
  107. (define-values (add-func-label! resolve-func-label func-label-name-map)
  108. (make-indirect-name-store))
  109. (define (add-func-locals! func)
  110. (match func
  111. (($ <func> id ($ <type-use> _ type) locals)
  112. (let ((idx (resolve-func id)))
  113. (for-each (lambda (local-id)
  114. (add-func-local! id idx local-id))
  115. (append (map param-id (func-sig-params type))
  116. (map local-id locals)))))))
  117. (define (add-func-labels! func)
  118. (match func
  119. (($ <func> id _ _ body)
  120. (let ((idx (resolve-func id)))
  121. (let loop ((insts body))
  122. (match insts
  123. (() #t)
  124. ((((or 'block 'loop) label _ body) . rest)
  125. (add-func-label! id idx label)
  126. (loop body)
  127. (loop rest))
  128. ((('if label _ consequent alternate) . rest)
  129. (add-func-label! id idx label)
  130. (loop consequent)
  131. (loop alternate)
  132. (loop rest))
  133. ((_ . rest)
  134. (loop rest))))))))
  135. (define (resolve-memarg memarg)
  136. (match memarg
  137. (($ <mem-arg> id offset align)
  138. (make-mem-arg (resolve-memory id) offset align))))
  139. (define interned-strings (make-hash-table))
  140. (define interned-string-count 0)
  141. (define (intern-string string)
  142. (or (hash-ref interned-strings string)
  143. (let ((idx interned-string-count))
  144. (hash-set! interned-strings string idx)
  145. (set! interned-string-count (1+ idx))
  146. idx)))
  147. (define functions-used-as-values (make-hash-table))
  148. (define (record-function-used-as-value idx)
  149. (unless (exact-integer? idx) (error "expected resolved idx"))
  150. (hashv-set! functions-used-as-values idx #t)
  151. idx)
  152. (define (type-use-matcher params results)
  153. (define param-type (match-lambda (($ <param> id type) type)))
  154. (lambda (rec type-id type-idx supers type)
  155. (and (null? supers)
  156. (match type
  157. (($ <func-sig> params' results')
  158. (and (equal? (map param-type params)
  159. (map param-type params'))
  160. (equal? results results')
  161. (make-type-use type-idx (make-func-sig params results))))
  162. (_ #f)))))
  163. (define (adjoin-types-from-type-uses types funcs imports tags)
  164. (define (adjoin-type-use type types)
  165. (match type
  166. (($ <type-use> #f ($ <func-sig> params results))
  167. (if (find-type (type-use-matcher params results) types)
  168. types
  169. (append types
  170. (list (make-type #f (make-func-sig params results))))))
  171. (($ <type-use>) types)))
  172. (define (adjoin-type-uses-from-tag-type type types)
  173. (match type
  174. (($ <tag-type> attribute type)
  175. (adjoin-type-use type types))))
  176. (define (adjoin-type-uses-from-import import types)
  177. (match import
  178. (($ <import> mod name 'func id type)
  179. (adjoin-type-use type types))
  180. (($ <import> mod name 'tag id type)
  181. (adjoin-type-uses-from-tag-type type types))
  182. (($ <import>) types)))
  183. (define (adjoin-type-uses-from-tag tag types)
  184. (match tag
  185. (($ <tag> id type)
  186. (adjoin-type-uses-from-tag-type type types))))
  187. (define (adjoin-type-uses-from-func func types)
  188. (define (adjoin-type-use-for-block-type x types)
  189. (match x
  190. (($ <type-use> #f ($ <func-sig> () (or () (_))))
  191. types)
  192. (_ (adjoin-type-use x types))))
  193. (define (adjoin-type-uses-for-inst inst types)
  194. (match-inst inst
  195. (((or 'block 'loop) label type body)
  196. (fold1 adjoin-type-uses-for-inst body
  197. (adjoin-type-use-for-block-type type types)))
  198. (('if label type consequent alternate)
  199. (adjoin-type-uses-from-body
  200. consequent
  201. (adjoin-type-uses-from-body
  202. alternate
  203. (adjoin-type-use-for-block-type type types))))
  204. (('try label type body ((tag . catches) ...) catch-all)
  205. (fold1 adjoin-type-uses-from-body (cons body catches)
  206. (adjoin-type-use-for-block-type
  207. type
  208. (if catch-all
  209. (adjoin-type-uses-from-body catch-all types)
  210. types))))
  211. (('try_delegate label type body handler)
  212. (adjoin-type-uses-from-body
  213. body
  214. (adjoin-type-use-for-block-type type types)))
  215. (((or 'call_indirect 'return_call_indirect) table type)
  216. (adjoin-type-use type types))
  217. (_ types)))
  218. (define (adjoin-type-uses-from-body insts types)
  219. (fold1 adjoin-type-uses-for-inst insts types))
  220. (match func
  221. (($ <func> id type locals body)
  222. (adjoin-type-uses-from-body body (adjoin-type-use type types)))))
  223. (fold1 adjoin-type-uses-from-func funcs
  224. (fold1 adjoin-type-uses-from-tag tags
  225. (fold1 adjoin-type-uses-from-import imports types))))
  226. (match mod
  227. (($ <wasm> id %types imports funcs tables memories globals exports start
  228. elems datas tags strings custom)
  229. (define (generate-names)
  230. (make-names id
  231. (func-name-map)
  232. (func-local-name-map)
  233. (func-label-name-map)
  234. (type-name-map)
  235. (table-name-map)
  236. (memory-name-map)
  237. (global-name-map)
  238. (elem-name-map)
  239. (data-name-map)
  240. (struct-field-name-map)
  241. (tag-name-map)))
  242. (define types (adjoin-types-from-type-uses %types funcs imports tags))
  243. (for-each (match-lambda (($ <type> id type) (add-type-id! id))
  244. (($ <rec-group> (($ <type> id type) ...))
  245. (for-each add-type-id! id)))
  246. types)
  247. (for-each (match-lambda (($ <import> mod name kind id type)
  248. (match kind
  249. ('func (add-func-id! id))
  250. ('global (add-global-id! id))
  251. ('table (add-table-id! id))
  252. ('memory (add-memory-id! id))
  253. ('tag (add-tag-id! id)))))
  254. imports)
  255. (for-each (match-lambda (($ <func> id type locals body)
  256. (add-func-id! id)))
  257. funcs)
  258. (for-each (match-lambda (($ <table> id type init)
  259. (add-table-id! id)))
  260. tables)
  261. (for-each (match-lambda (($ <memory> id type)
  262. (add-memory-id! id)))
  263. memories)
  264. (for-each (match-lambda (($ <global> id type init)
  265. (add-global-id! id)))
  266. globals)
  267. (for-each (match-lambda (($ <elem> id mode table type offset init)
  268. (add-elem-id! id)))
  269. elems)
  270. (for-each (match-lambda (($ <data> id mode mem offset init)
  271. (add-data-id! id)))
  272. datas)
  273. (for-each (match-lambda (($ <tag> id type)
  274. (add-tag-id! id)))
  275. tags)
  276. (for-each intern-string strings)
  277. (find-type (lambda (rec type-id type-idx supers type)
  278. (match type
  279. (($ <struct-type>
  280. (($ <field> field-id mutable? type) ...))
  281. (for-each
  282. (lambda (field-id)
  283. (add-struct-field! type-id type-idx field-id))
  284. field-id))
  285. (_ (values)))
  286. #f)
  287. types)
  288. (when emit-names?
  289. (for-each add-func-locals! funcs)
  290. (for-each add-func-labels! funcs))
  291. (define (type-by-idx idx)
  292. (or (find-type (lambda (rec type-id type-idx supers type)
  293. (and (eqv? type-idx idx)
  294. type))
  295. types)
  296. (error "unknown type" idx)))
  297. (define (resolve-heap-type ht)
  298. (match ht
  299. ((or 'func 'extern
  300. 'any 'eq 'i31 'noextern 'nofunc 'struct 'array 'none
  301. 'string 'stringview_wtf8 'stringview_wtf16 'stringview_iter)
  302. ht)
  303. (_ (resolve-type ht))))
  304. (define (resolve-val-type vt)
  305. (match vt
  306. ((or 'i32 'i64 'f32 'f64 'v128
  307. 'funcref 'externref 'anyref 'eqref 'i31ref
  308. 'nullexternref 'nullfuncref
  309. 'structref 'arrayref 'nullref
  310. 'stringref
  311. 'stringview_wtf8ref 'stringview_wtf16ref 'stringview_iterref)
  312. vt)
  313. (($ <ref-type> nullable? ht)
  314. (make-ref-type nullable? (resolve-heap-type ht)))))
  315. (define (resolve-ref-type rt)
  316. (resolve-val-type rt))
  317. (define (resolve-storage-type type)
  318. (match type
  319. ((or 'i8 'i16) type)
  320. (_ (resolve-val-type type))))
  321. (define (resolve-param param)
  322. (match param
  323. (($ <param> id type)
  324. (make-param id (resolve-val-type type)))))
  325. (define (resolve-type-use x)
  326. ;; Transform symbolic or anonymous type uses to indexed type
  327. ;; uses.
  328. (define (lookup-type-use params results)
  329. (or (find-type (type-use-matcher params results) types)
  330. (error "unreachable")))
  331. (match x
  332. (($ <type-use> idx (and use-sig ($ <func-sig> params results)))
  333. (if idx
  334. (let ((idx (resolve-type idx)))
  335. (let ((def-sig (type-by-idx idx)))
  336. (make-type-use idx
  337. (if (and (null? params) (null? results))
  338. def-sig
  339. use-sig))))
  340. (match (lookup-type-use params results)
  341. (($ <type-use> idx ($ <func-sig> params results))
  342. (let ((params (map resolve-param params))
  343. (results (map resolve-val-type results)))
  344. (make-type-use idx (make-func-sig params results)))))))))
  345. (define (resolve-type-use-as-idx x)
  346. (match (resolve-type-use x)
  347. (($ <type-use> idx func-sig)
  348. idx)))
  349. (define (resolve-block-type x)
  350. (match x
  351. (($ <type-use> #f ($ <func-sig> () ()))
  352. x)
  353. (($ <type-use> #f ($ <func-sig> () (ret)))
  354. (let ((ret (resolve-val-type ret)))
  355. (make-type-use #f (make-func-sig '() (list ret)))))
  356. (_ (resolve-type-use-as-idx x))))
  357. (define (enumerate-locals params locals)
  358. (define table (make-hash-table))
  359. (define (visit-params)
  360. (let lp ((params params) (idx 0))
  361. (match params
  362. (() (visit-locals idx))
  363. ((($ <param> id _) . params)
  364. (when id (hashq-set! table id idx))
  365. (lp params (1+ idx))))))
  366. (define (visit-locals first-local)
  367. (let lp ((locals locals) (idx first-local))
  368. (match locals
  369. (() resolve-local)
  370. ((($ <local> id _) . locals)
  371. (when id (hashq-set! table id idx))
  372. (lp locals (1+ idx))))))
  373. (define (resolve-local id)
  374. (match id
  375. ((? exact-integer?) id)
  376. (_
  377. (or (hashq-ref table id)
  378. (error "unbound local" id locals)))))
  379. (visit-params))
  380. (define (resolve-instructions insts resolve-local)
  381. (define (resolve-i32 x)
  382. (if (< x (ash 1 31)) x (- x (ash 1 32))))
  383. (define (resolve-i64 x)
  384. (if (< x (ash 1 63)) x (- x (ash 1 64))))
  385. (define (resolve* insts labels)
  386. (map (lambda (inst) (resolve1 inst labels)) insts))
  387. (define (resolve1 inst labels)
  388. (define (resolve-label label)
  389. (match label
  390. ((? exact-integer?) label)
  391. (_
  392. (let lp ((ls labels) (idx 0))
  393. (match ls
  394. (() (error "unbound label" label labels))
  395. ((l . ls)
  396. (if (eq? l label)
  397. idx
  398. (lp ls (1+ idx)))))))))
  399. (match inst
  400. ((op . args)
  401. (match-inst inst
  402. (((or 'block 'loop) label type body)
  403. (let ((labels (cons label labels)))
  404. `(,op ,label ,(resolve-block-type type)
  405. ,(resolve* body labels))))
  406. (('if label type consequent alternate)
  407. (let ((labels (cons label labels)))
  408. `(if ,label ,(resolve-block-type type)
  409. ,(resolve* consequent labels)
  410. ,(resolve* alternate labels))))
  411. (('try label type body catches catch-all)
  412. (let ((labels (cons label labels)))
  413. `(try ,label ,(resolve-block-type type)
  414. ,(resolve* body labels)
  415. ,(map (match-lambda
  416. ((tag . body)
  417. (cons (resolve-tag tag)
  418. (resolve* body labels))))
  419. catches)
  420. ,(resolve* catch-all labels))))
  421. (('try_delegate label type body handler)
  422. (let ((labels (cons label labels)))
  423. `(try_delegate ,label ,(resolve-block-type type)
  424. ,(resolve* body labels)
  425. ,(resolve-label handler))))
  426. (('throw tag) `(,op ,(resolve-tag tag)))
  427. (((or 'br 'br_if 'rethrow) label)
  428. `(,op ,(resolve-label label)))
  429. (('br_table targets default)
  430. `(br_table ,(map resolve-label targets) ,(resolve-label default)))
  431. (((or 'call 'return_call) label)
  432. `(,op ,(resolve-func label)))
  433. (('call_indirect table type)
  434. `(call_indirect ,(resolve-table table) ,(resolve-type-use-as-idx type)))
  435. (((or 'call_ref 'return_call_ref) type)
  436. `(,op ,(resolve-type type)))
  437. (('select . _)
  438. (match args
  439. (() inst)
  440. ((types) `(select ,(map resolve-val-type types)))))
  441. (((or 'local.get 'local.set 'local.tee) local)
  442. `(,op ,(resolve-local local)))
  443. (((or 'global.get 'global.set) global)
  444. `(,op ,(resolve-global global)))
  445. (((or 'table.get 'table.set) table)
  446. `(,op ,(resolve-table table)))
  447. (((or 'memory.size 'memory.grow) mem)
  448. `(,op ,(resolve-memory mem)))
  449. (((or 'i32.load 'i64.load 'f32.load 'f64.load
  450. 'i32.load8_s 'i32.load8_u 'i32.load16_s 'i32.load16_u
  451. 'i64.load8_s 'i64.load8_u 'i64.load16_s 'i64.load16_u
  452. 'i64.load32_s 'i64.load32_u
  453. 'i32.store 'i64.store 'f32.store 'f64.store
  454. 'i32.store8 'i32.store16
  455. 'i64.store8 'i64.store16 'i64.store32)
  456. mem)
  457. `(,op ,(resolve-memarg mem)))
  458. (('i32.const x) `(i32.const ,(resolve-i32 x)))
  459. (('i64.const x) `(i64.const ,(resolve-i64 x)))
  460. (('ref.null ht) `(ref.null ,(resolve-heap-type ht)))
  461. (('ref.func f) `(ref.func ,(record-function-used-as-value
  462. (resolve-func f))))
  463. ;; GC instructions.
  464. (((or 'ref.test 'ref.cast) rt)
  465. `(,op ,(resolve-ref-type rt)))
  466. (((or 'br_on_cast 'br_on_cast_fail) label rt1 rt2)
  467. `(,op ,(resolve-label label)
  468. ,(resolve-ref-type rt1) ,(resolve-ref-type rt2)))
  469. (((or 'struct.get 'struct.get_s 'struct.get_u 'struct.set)
  470. type field)
  471. `(,op ,(resolve-type type) ,(resolve-struct-field type field)))
  472. (((or 'struct.new 'struct.new_default) type)
  473. `(,op ,(resolve-type type)))
  474. (((or 'array.get 'array.get_s 'array.get_u 'array.set) type)
  475. `(,op ,(resolve-type type)))
  476. (('array.new_fixed type len)
  477. `(array.new_fixed ,(resolve-type type) ,len))
  478. (((or 'array.new 'array.new_default) type)
  479. `(,op ,(resolve-type type)))
  480. (((or 'array.new_data 'array.init_data) type data)
  481. `(,op ,(resolve-type type) ,(resolve-data data)))
  482. (((or 'array.new_elem 'array.init_elem) type elem)
  483. `(,op ,(resolve-type type) ,(resolve-elem elem)))
  484. (('array.fill type)
  485. `(array.fill ,(resolve-type type)))
  486. (('array.copy dst src)
  487. `(array.copy ,(resolve-type dst) ,(resolve-type src)))
  488. ;; Stringref instructions.
  489. (('string.const (? string? str))
  490. `(string.const ,(intern-string str)))
  491. (((or 'string.new_utf8 'string.new_lossy_utf8 'string.new_wtf8
  492. 'string.new_wtf16
  493. 'string.encode_utf8 'string.encode_lossy_utf8
  494. 'string.encode_wtf8 'string.encode_wtf16
  495. 'stringview_wtf8.encode_utf8
  496. 'stringview_wtf8.encode_lossy_utf8
  497. 'stringview_wtf8.encode_wtf8
  498. 'stringview_wtf16.encode)
  499. mem)
  500. `(,op ,(resolve-memarg mem)))
  501. ;; Misc instructions.
  502. (('memory.init data mem)
  503. `(memory.init ,(resolve-data data) ,(resolve-memory mem)))
  504. (('data.drop data)
  505. `(data.drop ,(resolve-data data)))
  506. (('memory.copy dst src)
  507. `(memory.copy ,(resolve-memory dst) ,(resolve-memory src)))
  508. (('memory.fill mem)
  509. `(memory.fill ,(resolve-memory mem)))
  510. (('table.init table elem)
  511. `(table.init ,(resolve-table table) ,(resolve-elem elem)))
  512. (('elem.drop elem)
  513. `(elem.drop ,(resolve-elem elem)))
  514. (('table.copy dst src)
  515. `(table.copy ,(resolve-table dst) ,(resolve-table src)))
  516. (((or 'table.grow 'table.size 'table.fill) table)
  517. `(,op ,(resolve-table table)))
  518. ;; Not yet implemented: simd mem ops, atomic mem ops.
  519. (_ inst)))
  520. ((? symbol? op) (list op))))
  521. (resolve* insts '()))
  522. (define (resolve-expression insts)
  523. (define (no-locals id)
  524. (error "no locals in expression" id))
  525. (resolve-instructions insts no-locals))
  526. (define (visit-type type)
  527. (define (resolve-field field)
  528. (match field
  529. (($ <field> id mutable? type)
  530. (make-field id mutable? (resolve-storage-type type)))))
  531. (define (resolve-base type)
  532. (match type
  533. (($ <func-sig> params results)
  534. (make-func-sig (map resolve-param params)
  535. (map resolve-val-type results)))
  536. (($ <array-type> mutable? type)
  537. (make-array-type mutable? (resolve-storage-type type)))
  538. (($ <struct-type> fields)
  539. (make-struct-type (map resolve-field fields)))))
  540. (define (resolve-sub type)
  541. (match type
  542. (($ <type> id type)
  543. (make-type id
  544. (match type
  545. (($ <sub-type> final? supers type)
  546. (make-sub-type final?
  547. (map resolve-heap-type supers)
  548. (resolve-base type)))
  549. (_ (resolve-base type)))))))
  550. (match type
  551. (($ <rec-group> sub-types)
  552. (make-rec-group (map resolve-sub sub-types)))
  553. (_ (resolve-sub type))))
  554. (define (visit-import import)
  555. (match import
  556. (($ <import> mod name 'func id type)
  557. (make-import mod name 'func id (resolve-type-use type)))
  558. (($ <import> mod name 'global id ($ <global-type> mutable? type))
  559. (make-import mod name 'global id
  560. (make-global-type mutable? (resolve-val-type type))))
  561. ((and import ($ <import> mod name 'memory))
  562. import)
  563. (($ <import> mod name 'table id ($ <table-type> limits type))
  564. (make-import mod name 'table id
  565. (make-table-type limits (resolve-val-type type))))
  566. (($ <import> mod name 'tag id ($ <tag-type> attribute type))
  567. (make-import mod name 'tag id
  568. (make-tag-type attribute (resolve-type-use type))))))
  569. (define (visit-export export)
  570. (match export
  571. (($ <export> name 'func id)
  572. (make-export name 'func (resolve-func id)))
  573. (($ <export> name 'table id)
  574. (make-export name 'table (resolve-table id)))
  575. (($ <export> name 'memory id)
  576. (make-export name 'memory (resolve-memory id)))
  577. (($ <export> name 'global id)
  578. (make-export name 'global (resolve-global id)))
  579. (($ <export> name 'tag id)
  580. (make-export name 'tag (resolve-tag id)))))
  581. (define (strip-declarative-segments elems)
  582. (filter (match-lambda
  583. (($ <elem> id mode) (not (eq? mode 'declarative))))
  584. elems))
  585. (define (add-declarative-segment elems)
  586. (match (sort (hash-map->list (lambda (k v) k) functions-used-as-values)
  587. <)
  588. (() elems)
  589. (funcs
  590. (let ((declarative (make-elem #f 'declarative #f 'funcref #f
  591. (map (lambda (func-idx)
  592. `((ref.func ,func-idx)))
  593. funcs))))
  594. (append elems (list declarative))))))
  595. (define (visit-elem elem)
  596. (match elem
  597. (($ <elem> id mode table type offset init)
  598. (make-elem id mode (and table (resolve-table table))
  599. (resolve-val-type type)
  600. (and offset (resolve-expression offset))
  601. (map (lambda (init)
  602. (resolve-expression init))
  603. init)))))
  604. (define (visit-data data)
  605. (match data
  606. (($ <data> id mode mem offset init)
  607. (make-data id mode (and mem (resolve-memory mem))
  608. (and offset (resolve-expression offset))
  609. init))))
  610. (define (visit-start start)
  611. (and start (resolve-func start)))
  612. (define (visit-func func)
  613. (define (visit-local local)
  614. (match local
  615. (($ <local> id type)
  616. (make-local id (resolve-val-type type)))))
  617. (match func
  618. (($ <func> id type locals body)
  619. (match (resolve-type-use type)
  620. ((and type ($ <type-use> idx ($ <func-sig> params _)))
  621. (let ((resolve-locals (enumerate-locals params locals)))
  622. (make-func id type (map visit-local locals)
  623. (resolve-instructions body resolve-locals))))))))
  624. (define (visit-table table)
  625. (match table
  626. (($ <table> id ($ <table-type> limits type) init)
  627. (make-table id
  628. (make-table-type limits (resolve-val-type type))
  629. (and init (resolve-expression init))))))
  630. (define (visit-memory mem) mem)
  631. (define (visit-global global)
  632. (match global
  633. (($ <global> id ($ <global-type> mutable? type) init)
  634. (make-global id
  635. (make-global-type mutable? (resolve-val-type type))
  636. (resolve-expression init)))))
  637. (define (visit-tag tag)
  638. (match tag
  639. (($ <tag> id ($ <tag-type> attribute type))
  640. (make-tag id (make-tag-type attribute (resolve-type-use type))))))
  641. (let ((types (map visit-type types))
  642. (imports (map visit-import imports))
  643. (exports (map visit-export exports))
  644. (%elems (map visit-elem (strip-declarative-segments elems)))
  645. (datas (map visit-data datas))
  646. (start (visit-start start))
  647. (funcs (map visit-func funcs))
  648. (tables (map visit-table tables))
  649. (memories (map visit-memory memories))
  650. (globals (map visit-global globals))
  651. (tags (map visit-tag tags))
  652. (custom (if emit-names?
  653. (cons (generate-names) custom)
  654. custom)))
  655. (define strings
  656. (map car
  657. (sort (hash-map->list cons interned-strings)
  658. (match-lambda*
  659. (((s1 . idx1) (s2 . idx2)) (< idx1 idx2))))))
  660. (define elems (add-declarative-segment %elems))
  661. (make-wasm #f types imports funcs tables memories globals exports start
  662. elems datas tags strings custom)))))