link.scm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749
  1. ;;; WebAssembly linker
  2. ;;; Copyright (C) 2023 Igalia, S.L.
  3. ;;;
  4. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  5. ;;; you may not use this file except in compliance with the License.
  6. ;;; You may obtain a copy of the License at
  7. ;;;
  8. ;;; http://www.apache.org/licenses/LICENSE-2.0
  9. ;;;
  10. ;;; Unless required by applicable law or agreed to in writing, software
  11. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  12. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ;;; See the License for the specific language governing permissions and
  14. ;;; limitations under the License.
  15. ;;; Commentary:
  16. ;;;
  17. ;;; Linker for WebAssembly, to augment a wasm module by pulling in
  18. ;;; missing definitions from a standard library.
  19. ;;;
  20. ;;; Code:
  21. (define-module (wasm link)
  22. #:use-module (ice-9 match)
  23. #:use-module (wasm types)
  24. #:use-module (wasm types)
  25. #:export (add-stdlib))
  26. (define (fold1 f l s0)
  27. (let lp ((l l) (s0 s0))
  28. (match l
  29. (() s0)
  30. ((elt . l) (lp l (f elt s0))))))
  31. (define (sort-types types)
  32. (define visited (make-hash-table))
  33. (define (visited? type) (hashq-ref visited type))
  34. (define (mark-visited! type) (hashq-set! visited type #t))
  35. (define (lookup-type name)
  36. ;; Return the whole type block, so we can revisit any
  37. ;; references within it.
  38. (or-map (lambda (type)
  39. (match type
  40. (($ <type> id _) (and (eq? id name) type))
  41. (($ <rec-group> (($ <type> id) ...))
  42. (and (or-map (lambda (id) (eq? id name)) id)
  43. type))))
  44. types))
  45. (define (visit-heap-type type order)
  46. (match (lookup-type type)
  47. (#f order)
  48. (type (visit-type type order))))
  49. (define (visit-val-type type order)
  50. (match type
  51. (($ <ref-type> nullable? ht)
  52. (visit-heap-type ht order))
  53. (_ order)))
  54. (define (visit-storage-type type order)
  55. (visit-val-type type order))
  56. (define (visit-successors type order)
  57. (define (visit-base type order)
  58. (match type
  59. (($ <array-type> mutable? type)
  60. (visit-storage-type type order))
  61. (($ <struct-type> fields)
  62. (fold1 (lambda (field order)
  63. (match field
  64. (($ <field> id mutable? type)
  65. (visit-storage-type type order))))
  66. fields order))
  67. (($ <func-sig> params results)
  68. (fold1 (lambda (param order)
  69. (match param
  70. (($ <param> id type)
  71. (visit-val-type type order))))
  72. params (fold1 visit-val-type results order)))))
  73. (define (visit-sub type order)
  74. (match type
  75. (($ <sub-type> final? supers type)
  76. (visit-base type (fold1 visit-heap-type supers order)))
  77. (_ (visit-base type order))))
  78. (match type
  79. (($ <rec-group> (($ <type> id type) ...))
  80. (fold1 visit-sub type order))
  81. (($ <type> id type)
  82. (visit-sub type order))))
  83. (define (visit-type type order)
  84. (cond
  85. ((visited? type) order)
  86. (else
  87. ;; After visiting successors, add label to the reverse post-order.
  88. (mark-visited! type)
  89. (cons type (visit-successors type order)))))
  90. (reverse (fold1 visit-type types '())))
  91. (define* (link wasm #:key
  92. (link-type (lambda (id) #f))
  93. (link-import (lambda (id kind) #f))
  94. (link-func (lambda (id) #f))
  95. (link-table (lambda (id) #f))
  96. (link-memory (lambda (id) #f))
  97. (link-global (lambda (id) #f))
  98. (link-data (lambda (id) #f)))
  99. (define (fold-instructions f body seed)
  100. (define (visit* body seed)
  101. (fold1 visit1 body seed))
  102. (define (visit1 inst seed)
  103. (let ((seed (f inst seed)))
  104. (match inst
  105. (((or 'block 'loop) label type insts)
  106. (visit* insts seed))
  107. (('if label type consequent alternate)
  108. (visit* alternate (visit* consequent seed)))
  109. (('try label type body catches catch-all)
  110. (let ((seed (if catch-all (visit* catch-all seed) seed)))
  111. (fold1 visit* catches (visit* body seed))))
  112. (('try_delegate label type body handler)
  113. (visit* body seed))
  114. (_ seed))))
  115. (visit* body seed))
  116. (define-syntax-rule (simple-lookup candidates (pat test) ...)
  117. (let lp ((candidates candidates))
  118. (match candidates
  119. (() #f)
  120. (((and candidate pat) . candidates)
  121. (if test candidate (lp candidates)))
  122. ...)))
  123. (define (compute-types types imports funcs tables globals elems tags)
  124. (define (lookup-type name types)
  125. ;; Return the whole type block, so we can revisit any
  126. ;; references within it.
  127. (or-map (lambda (type)
  128. (match type
  129. (($ <type> id _) (and (eq? id name) type))
  130. (($ <rec-group> (($ <type> id) ...))
  131. (and (or-map (lambda (id) (eq? id name)) id)
  132. type))))
  133. types))
  134. (define (visit-val-type type types)
  135. (match type
  136. ((or 'i32 'i64 'f32 'f64 'v128
  137. 'funcref 'externref 'anyref 'eqref 'i31ref
  138. 'nullexternref 'nullfuncref
  139. 'structref 'arrayref
  140. 'nullref
  141. 'stringref
  142. 'stringview_wtf8ref 'stringview_wtf16ref 'stringview_iterref)
  143. types)
  144. (($ <ref-type> nullable? ht)
  145. (visit-heap-type ht types))))
  146. (define (visit-storage-type type types)
  147. (match type
  148. ((or 'i8 'i16) types)
  149. (_ (visit-val-type type types))))
  150. (define (visit-func-sig params results types)
  151. (fold1 (lambda (param types)
  152. (match param
  153. (($ <param> id type)
  154. (visit-val-type type types))))
  155. params
  156. (fold1 visit-val-type results types)))
  157. (define (visit-type type types)
  158. (define (visit-base type types)
  159. (match type
  160. (($ <array-type> mutable? type)
  161. (visit-storage-type type types))
  162. (($ <struct-type> fields)
  163. (fold1 (lambda (field types)
  164. (match field
  165. (($ <field> id mutable? type)
  166. (visit-storage-type type types))))
  167. fields types))
  168. (($ <func-sig> params results)
  169. (visit-func-sig params results types))))
  170. (define (visit-sub type types)
  171. (match type
  172. (($ <sub-type> final? supers type)
  173. (visit-base type
  174. (fold1 visit-heap-type supers types)))
  175. (_ (visit-base type types))))
  176. (match type
  177. (($ <rec-group> (($ <type> id type) ...))
  178. (fold1 visit-sub type types))
  179. (($ <type> id type)
  180. (visit-sub type types))))
  181. (define (visit-heap-type type types)
  182. (match type
  183. ((or 'func 'extern 'any 'eq 'i31 'noextern 'nofunc 'struct 'array 'none
  184. 'string 'stringview_wtf8 'stringview_wtf16 'stringview_iter)
  185. types)
  186. (_
  187. (match (lookup-type type types)
  188. (#f (let ((type (or (link-type type)
  189. (error "unknown heap type" type))))
  190. (visit-type type (cons type types))))
  191. (type types)))))
  192. (define (visit-ref-type type types)
  193. (match type
  194. (($ <ref-type> nullable? ht)
  195. (visit-heap-type ht types))
  196. (_ types)))
  197. (define (visit-func-type type types)
  198. (visit-heap-type type types))
  199. (define (visit-type-use type types)
  200. (match type
  201. (($ <type-use> idx ($ <func-sig> params results))
  202. (let ((types (visit-func-sig params results types)))
  203. (if (symbol? idx)
  204. (visit-func-type idx types)
  205. types)))))
  206. (define (visit-body body types)
  207. (fold-instructions
  208. (lambda (inst types)
  209. (match inst
  210. (((or 'block 'loop 'if 'try 'try_delegate) label type . _)
  211. (if type
  212. (visit-type-use type types)
  213. types))
  214. (((or 'call_indirect 'return_call_indirect) table type)
  215. (visit-type-use type types))
  216. (((or 'call_ref 'return_call_ref) table type)
  217. (visit-type-use type types))
  218. (('select type ...)
  219. (fold1 visit-val-type type types))
  220. (('ref.null type)
  221. (visit-heap-type type types))
  222. (((or 'struct.get 'struct.get_s 'struct.get_u
  223. 'struct.set) type field)
  224. (visit-heap-type type types))
  225. (((or 'struct.new 'struct.new_default
  226. 'array.new 'array.new_default
  227. 'array.get 'array.get_s 'array.get_u
  228. 'array.set) type)
  229. (visit-heap-type type types))
  230. (('array.copy dst src)
  231. (visit-heap-type dst (visit-heap-type src types)))
  232. (((or 'array.new_fixed 'array.new_data 'array.new_elem
  233. 'array.init_data 'array.init_elem) type _)
  234. (visit-heap-type type types))
  235. (((or 'ref.test 'ref.cast) ($ <ref-type> nullable? type))
  236. (visit-heap-type type types))
  237. (((or 'br_on_cast 'br_on_cast_fail) idx rt1 rt2)
  238. (visit-ref-type rt1 (visit-ref-type rt2 types)))
  239. (_ types)))
  240. body types))
  241. (define (visit-function func types)
  242. (match func
  243. (($ <func> id type (($ <local> lid ltype) ...) body)
  244. (visit-body
  245. body
  246. (fold1 visit-val-type ltype
  247. (visit-type-use type types))))))
  248. (define (visit-import import types)
  249. (match import
  250. (($ <import> mod name 'func id type)
  251. (visit-type-use type types))
  252. (($ <import> mod name 'table id ($ <table-type> limits type))
  253. (visit-val-type type types))
  254. (($ <import> mod name 'memory id type)
  255. types)
  256. (($ <import> mod name 'global id ($ <global-type> mutable? type))
  257. (visit-val-type type types)))
  258. types)
  259. (define (visit-table table types)
  260. (match table
  261. (($ <table> id ($ <table-type> limits type) init)
  262. (visit-val-type type
  263. (if init
  264. (visit-body init types)
  265. types)))))
  266. (define (visit-global global types)
  267. (match global
  268. (($ <global> id ($ <global-type> mutable? type) init)
  269. (visit-val-type type (visit-body init types)))))
  270. (define (visit-elem elem types)
  271. (match elem
  272. (($ <elem> id mode table type offset inits)
  273. (let* ((types (fold1 visit-body inits types))
  274. (types (visit-val-type type types)))
  275. (if offset
  276. (visit-body offset types)
  277. types)))))
  278. (define (visit-tag tag types)
  279. (match tag
  280. (($ <tag> id type)
  281. (visit-type-use type types))))
  282. (sort-types
  283. (fold1 visit-function funcs
  284. (fold1 visit-import imports
  285. (fold1 visit-table tables
  286. (fold1 visit-global globals
  287. (fold1 visit-elem elems
  288. (fold1 visit-tag tags
  289. (fold1 visit-type types
  290. types)))))))))
  291. (define (compute-imports imports funcs tables memories globals exports
  292. elems)
  293. (define (function-locally-bound? label)
  294. (or-map (match-lambda (($ <func> id) (eqv? label id)))
  295. funcs))
  296. (define (global-locally-bound? label)
  297. (or-map (match-lambda (($ <global> id type init) (eq? id label)))
  298. globals))
  299. (define (table-locally-bound? label)
  300. (or-map (match-lambda (($ <table> id type init) (eq? id label)))
  301. tables))
  302. (define (memory-locally-bound? label)
  303. (or-map (match-lambda (($ <memory> id type) (eq? id label)))
  304. memories))
  305. (define (add-import import kind imports)
  306. (define (lookup name imports)
  307. (simple-lookup
  308. imports
  309. (($ <import> mod' name' kind' id')
  310. (and (eq? kind' kind) (eqv? id' name)))))
  311. (match (lookup import imports)
  312. (#f (cons (or (link-import import kind)
  313. (error "unknown import" import kind))
  314. imports))
  315. (_ imports)))
  316. (define (add-imported-func label imports)
  317. (if (function-locally-bound? label)
  318. imports
  319. (add-import label 'func imports)))
  320. (define (add-imported-table label imports)
  321. (if (table-locally-bound? label)
  322. imports
  323. (add-import label 'table imports)))
  324. (define (add-imported-global label imports)
  325. (if (global-locally-bound? label)
  326. imports
  327. (add-import label 'global imports)))
  328. (define (add-imported-memory label imports)
  329. (if (memory-locally-bound? label)
  330. imports
  331. (add-import label 'memory imports)))
  332. (define (visit-body body imports)
  333. (fold-instructions
  334. (lambda (inst imports)
  335. (match inst
  336. (((or 'call 'return_call 'ref.func) label)
  337. (add-imported-func label imports))
  338. (((or 'table.get 'table.set
  339. 'table.grow 'table.size 'table.fill) label)
  340. (add-imported-table label imports))
  341. (('table.init elem table)
  342. (add-imported-table table imports))
  343. (('call_indirect type table)
  344. (add-imported-table table imports))
  345. (('table.copy dst src)
  346. (add-imported-table dst (add-imported-table src imports)))
  347. (((or 'global.get 'global.set) label)
  348. (add-imported-global label imports))
  349. (((or 'i32.load 'i64.load 'f32.load 'f64.load
  350. 'i32.load8_s 'i32.load8_u 'i32.load16_s 'i32.load16_u
  351. 'i64.load8_s 'i64.load8_u 'i64.load16_s 'i64.load16_u
  352. 'i64.load32_s 'i64.load32_u
  353. 'i32.store 'i64.store 'f32.store 'f64.store
  354. 'i32.store8 'i32.store16 'i64.store8 'i64.store16
  355. 'i64.store32)
  356. ($ <mem-arg> id offset align))
  357. (add-imported-memory id imports))
  358. (((or 'memory.size 'memory.grow 'memory.init 'memory.fill) id)
  359. (add-imported-memory id imports))
  360. (('memory.copy dst src)
  361. (add-imported-memory dst (add-imported-memory src imports)))
  362. (_ imports)))
  363. body imports))
  364. (define (visit-func func imports)
  365. (match func
  366. (($ <func> id type locals body)
  367. (visit-body body imports))))
  368. (define (visit-table table imports)
  369. (match table
  370. (($ <table> id type init)
  371. (if init
  372. (visit-body init imports)
  373. imports))))
  374. (define (visit-global global imports)
  375. (match global
  376. (($ <global> id type init)
  377. (visit-body init imports))))
  378. (define (visit-export export imports)
  379. (match export
  380. (($ <export> name kind id)
  381. (match kind
  382. ('func (add-imported-func id imports))
  383. ('table (add-imported-table id imports))
  384. ('global (add-imported-global id imports))
  385. ('memory (add-imported-memory id imports))))))
  386. (define (visit-elem elem imports)
  387. (match elem
  388. (($ <elem> id mode table type offset inits)
  389. (let ((imports (fold1 visit-body inits imports)))
  390. (if offset
  391. (visit-body offset imports)
  392. imports)))))
  393. (reverse
  394. (fold1 visit-func funcs
  395. (fold1 visit-table tables
  396. (fold1 visit-global globals
  397. (fold1 visit-export exports
  398. (fold1 visit-elem elems
  399. (reverse imports))))))))
  400. (define (compute-funcs funcs tables globals exports elems)
  401. (define (add-func name funcs)
  402. (define (lookup name funcs)
  403. (simple-lookup funcs (($ <func> id) (eqv? id name))))
  404. (match (lookup name funcs)
  405. (#f (match (link-func name)
  406. (#f funcs)
  407. (func (visit-func func (cons func funcs)))))
  408. (_ funcs)))
  409. (define (visit-body body funcs)
  410. (fold-instructions
  411. (lambda (inst funcs)
  412. (match inst
  413. (((or 'call 'return_call 'ref.func) f)
  414. (add-func f funcs))
  415. (_ funcs)))
  416. body funcs))
  417. (define (visit-func func funcs)
  418. (match func
  419. (($ <func> id type locals body)
  420. (visit-body body funcs))))
  421. (define (visit-table table funcs)
  422. (match table
  423. (($ <table> id type init)
  424. (if init
  425. (visit-body init funcs)
  426. funcs))))
  427. (define (visit-global global funcs)
  428. (match global
  429. (($ <global> id type init)
  430. (visit-body init funcs))))
  431. (define (visit-export export funcs)
  432. (match export
  433. (($ <export> name kind id)
  434. (if (eq? kind 'func)
  435. (add-func id funcs)
  436. funcs))))
  437. (define (visit-elem elem funcs)
  438. (match elem
  439. (($ <elem> id mode table type offset inits)
  440. (let ((funcs (fold1 visit-body inits funcs)))
  441. (if offset
  442. (visit-body offset funcs)
  443. funcs)))))
  444. (reverse
  445. (fold1 visit-func funcs
  446. (fold1 visit-table tables
  447. (fold1 visit-global globals
  448. (fold1 visit-export exports
  449. (fold1 visit-elem elems
  450. (reverse funcs))))))))
  451. (define (compute-tables funcs tables exports)
  452. (define (add-table table tables)
  453. (define (lookup name tables)
  454. (simple-lookup
  455. tables
  456. (($ <table> id) (eqv? id name))))
  457. (match (lookup table tables)
  458. (#f (match (link-table table)
  459. (#f tables)
  460. (table (cons table tables))))
  461. (_ tables)))
  462. (define (visit-func func tables)
  463. (match func
  464. (($ <func> id type locals body)
  465. (fold-instructions
  466. (lambda (inst tables)
  467. (match inst
  468. (((or 'table.get 'table.set
  469. 'table.grow 'table.size 'table.fill)
  470. table)
  471. (add-table table tables))
  472. (('table.init elem table)
  473. (add-table table tables))
  474. (('table.copy dst src)
  475. (add-table dst (add-table src tables)))
  476. (('call_indirect table type)
  477. (add-table table tables))
  478. (_ tables)))
  479. body tables))))
  480. (define (visit-export export tables)
  481. (match export
  482. (($ <export> name kind id)
  483. (if (eq? kind 'table)
  484. (add-table id tables)
  485. tables))))
  486. (reverse (fold1 visit-func funcs
  487. (fold1 visit-export exports (reverse tables)))))
  488. (define (compute-memories funcs memories exports datas)
  489. (define (add-memory memory memories)
  490. (define (lookup name memories)
  491. (simple-lookup
  492. memories
  493. (($ <memory> id) (eqv? id name))))
  494. (match (lookup memory memories)
  495. (#f (match (link-memory memory)
  496. (#f memories)
  497. (memory (cons memory memories))))
  498. (_ memories)))
  499. (define (visit-body body memories)
  500. (fold-instructions
  501. (lambda (inst memories)
  502. (match inst
  503. (((or 'i32.load 'i64.load 'f32.load 'f64.load
  504. 'i32.load8_s 'i32.load8_u 'i32.load16_s 'i32.load16_u
  505. 'i64.load8_s 'i64.load8_u 'i64.load16_s 'i64.load16_u
  506. 'i64.load32_s 'i64.load32_u
  507. 'i32.store 'i64.store 'f32.store 'f64.store
  508. 'i32.store8 'i32.store16 'i64.store8 'i64.store16
  509. 'i64.store32)
  510. ($ <mem-arg> id offset align))
  511. (add-memory id memories))
  512. (((or 'memory.size 'memory.grow 'memory.init 'memory.fill) id)
  513. (add-memory id memories))
  514. (('memory.copy dst src)
  515. (add-memory dst (add-memory src memories)))
  516. (_ memories)))
  517. body memories))
  518. (define (visit-func func memories)
  519. (match func
  520. (($ <func> id type locals body)
  521. (visit-body body memories))))
  522. (define (visit-export export memories)
  523. (match export
  524. (($ <export> name kind id)
  525. (if (eq? kind 'memory)
  526. (add-memory id memories)
  527. memories))))
  528. (define (visit-data data memories)
  529. (match data
  530. (($ <data> id mode mem offset init)
  531. (if (eq? mode 'active)
  532. (add-memory mem memories)
  533. memories))))
  534. (reverse
  535. (fold1 visit-func funcs
  536. (fold1 visit-export exports
  537. (fold1 visit-data datas
  538. (reverse memories))))))
  539. (define (compute-globals funcs tables globals exports elems)
  540. (define (add-global global globals)
  541. (define (lookup name globals)
  542. (simple-lookup
  543. globals
  544. (($ <global> id) (eqv? id name))))
  545. (match (lookup global globals)
  546. (#f (match (link-global global)
  547. (#f globals)
  548. (global (visit-global global (cons global globals)))))
  549. (_ globals)))
  550. (define (visit-body body globals)
  551. (fold-instructions
  552. (lambda (inst globals)
  553. (match inst
  554. (((or 'global.get 'global.set) global)
  555. (add-global global globals))
  556. (_ globals)))
  557. body globals))
  558. (define (visit-func func globals)
  559. (match func
  560. (($ <func> id type locals body)
  561. (visit-body body globals))))
  562. (define (visit-table table globals)
  563. (match table
  564. (($ <table> id type init)
  565. (if init
  566. (visit-body init globals)
  567. globals))))
  568. (define (visit-global global globals)
  569. (match global
  570. (($ <global> id type init)
  571. (visit-body init globals))))
  572. (define (visit-export export globals)
  573. (match export
  574. (($ <export> name kind id)
  575. (if (eq? kind 'global)
  576. (add-global id globals)
  577. globals))))
  578. (define (visit-elem elem globals)
  579. (match elem
  580. (($ <elem> id mode table type offset inits)
  581. (let ((globals (fold1 visit-body inits globals)))
  582. (if offset
  583. (visit-body offset globals)
  584. globals)))))
  585. (reverse
  586. (fold1 visit-func funcs
  587. (fold1 visit-table tables
  588. (fold1 visit-global globals
  589. (fold1 visit-export exports
  590. (fold1 visit-elem elems
  591. (reverse globals))))))))
  592. (define (compute-datas funcs tables globals datas)
  593. (define (add-data data datas)
  594. (define (lookup name datas)
  595. (simple-lookup
  596. datas
  597. (($ <data> id) (eqv? id name))))
  598. (match (lookup data datas)
  599. (#f (match (link-data data)
  600. (#f datas)
  601. (data (cons data datas))))
  602. (_ datas)))
  603. (define (visit-body body datas)
  604. (fold-instructions
  605. (lambda (inst datas)
  606. (match inst
  607. (((or 'array.new_data 'array.init_data) type data)
  608. (add-data data datas))
  609. (_ datas)))
  610. body datas))
  611. (define (visit-func func datas)
  612. (match func
  613. (($ <func> id type locals body)
  614. (visit-body body datas))))
  615. (define (visit-table table datas)
  616. (match table
  617. (($ <table> id type init)
  618. (if init
  619. (visit-body init datas)
  620. datas))))
  621. (define (visit-global global datas)
  622. (match global
  623. (($ <global> id type init)
  624. (visit-body init datas))))
  625. (reverse
  626. (fold1 visit-func funcs
  627. (fold1 visit-table tables
  628. (fold1 visit-global globals
  629. (reverse datas))))))
  630. (match wasm
  631. (($ <wasm> id types imports funcs tables memories globals exports
  632. start elems datas tags strings custom)
  633. ;; An export can pull in funcs, tables, globals, and memories,
  634. ;; possibly imported.
  635. ;;
  636. ;; A function can pull in types, funcs, tables, globals and
  637. ;; memories from the stdlib. These fragments may be locally
  638. ;; defined or imported (except for types which are always
  639. ;; locally defined).
  640. ;;
  641. ;; A table can pull in types, globals, and functions, possibly
  642. ;; imported.
  643. ;;
  644. ;; A global can pull in types, globals, and functions, possibly
  645. ;; imported.
  646. ;;
  647. ;; An elem can pull in types and globals, possibly imported.
  648. ;;
  649. ;; An import can pull in types.
  650. ;;
  651. ;; A tag can pull in types.
  652. ;;
  653. ;; A type can pull in other types.
  654. ;;
  655. ;; Data can pull in a memory.
  656. ;;
  657. ;; Memories can't pull in anything else.
  658. ;;
  659. ;; Therefore, to allow pieces of the stdlib to lazily pull in
  660. ;; other pieces of the stdlib, we do a fixed-point on the set of
  661. ;; funcs, tables, and globals, then we compute memories, imports
  662. ;; and types.
  663. (let fixpoint ((funcs funcs) (tables tables) (globals globals))
  664. (let* ((funcs' (compute-funcs funcs tables globals exports elems))
  665. (tables' (compute-tables funcs' tables exports))
  666. (globals' (compute-globals funcs' tables' globals exports elems)))
  667. (if (and (= (length funcs') (length funcs))
  668. (= (length tables') (length tables))
  669. (= (length globals') (length globals)))
  670. (let* ((datas (compute-datas funcs tables globals datas))
  671. (memories (compute-memories funcs memories exports datas)))
  672. (let ((imports (compute-imports imports funcs tables memories
  673. globals exports elems))
  674. (types (compute-types types imports funcs tables globals
  675. elems tags)))
  676. (make-wasm id types imports funcs tables memories globals
  677. exports start elems datas tags strings custom)))
  678. (fixpoint funcs' tables' globals')))))))
  679. (define* (add-stdlib wasm stdlib #:key
  680. (synthesize-type (lambda (id) #f))
  681. (synthesize-import (lambda (id kind) #f)))
  682. (match stdlib
  683. (($ <wasm> std-id std-types std-imports std-funcs std-tables std-memories
  684. std-globals std-exports std-start std-elems std-datas std-tags
  685. std-strings std-custom)
  686. (define types (make-hash-table))
  687. (define imports (make-hash-table))
  688. (define funcs (make-hash-table))
  689. (define tables (make-hash-table))
  690. (define memories (make-hash-table))
  691. (define globals (make-hash-table))
  692. (define datas (make-hash-table))
  693. (for-each (match-lambda
  694. ((and t ($ <type> id _)) (hashq-set! types id t))
  695. ((and t ($ <rec-group> (($ <type> id) ...)))
  696. (for-each (lambda (id) (hashq-set! types id t)) id)))
  697. std-types)
  698. (for-each (match-lambda
  699. ((and import ($ <import> mode name kind id type))
  700. (hash-set! imports (cons id kind) import)))
  701. std-imports)
  702. (for-each (match-lambda
  703. ((and func ($ <func> id type locals body))
  704. (hashq-set! funcs id func)))
  705. std-funcs)
  706. (for-each (match-lambda
  707. ((and table ($ <table> id type init))
  708. (hashq-set! tables id table)))
  709. std-tables)
  710. (for-each (match-lambda
  711. ((and memory ($ <memory> id type))
  712. (hashq-set! memories id memory)))
  713. std-memories)
  714. (for-each (match-lambda
  715. ((and global ($ <global> id type init))
  716. (hashq-set! globals id global)))
  717. std-globals)
  718. (for-each (match-lambda
  719. ((and data ($ <data> id mode mem offset init))
  720. (hashq-set! datas id data)))
  721. std-datas)
  722. (link wasm
  723. #:link-type (lambda (id)
  724. (or (hashq-ref types id)
  725. (synthesize-type id)))
  726. #:link-import (lambda (id kind)
  727. (or (hash-ref imports (cons id kind))
  728. (synthesize-import id kind)))
  729. #:link-func (lambda (id) (hashq-ref funcs id))
  730. #:link-table (lambda (id) (hashq-ref tables id))
  731. #:link-memory (lambda (id) (hashq-ref memories id))
  732. #:link-global (lambda (id) (hashq-ref globals id))
  733. #:link-data (lambda (id) (hashq-ref datas id))))))