link.scm 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807
  1. ;;; WebAssembly linker
  2. ;;; Copyright (C) 2023, 2024 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. (link-tag (lambda (id) #f)))
  100. (define (fold-instructions f body seed)
  101. (define (visit* body seed)
  102. (fold1 visit1 body seed))
  103. (define (visit1 inst seed)
  104. (let ((seed (f inst seed)))
  105. (match inst
  106. (((or 'block 'loop) label type insts)
  107. (visit* insts seed))
  108. (('if label type consequent alternate)
  109. (visit* alternate (visit* consequent seed)))
  110. (('try label type body catches catch-all)
  111. (let ((seed (if catch-all (visit* catch-all seed) seed)))
  112. (fold1 visit* catches (visit* body seed))))
  113. (('try_delegate label type body handler)
  114. (visit* body seed))
  115. (_ seed))))
  116. (visit* body seed))
  117. (define-syntax-rule (simple-lookup candidates (pat test) ...)
  118. (let lp ((candidates candidates))
  119. (match candidates
  120. (() #f)
  121. (((and candidate pat) . candidates)
  122. (if test candidate (lp candidates)))
  123. ...)))
  124. (define (compute-types types imports funcs tables globals elems tags)
  125. (define (lookup-type name types)
  126. ;; Return the whole type block, so we can revisit any
  127. ;; references within it.
  128. (or-map (lambda (type)
  129. (match type
  130. (($ <type> id _) (and (eq? id name) type))
  131. (($ <rec-group> (($ <type> id) ...))
  132. (and (or-map (lambda (id) (eq? id name)) id)
  133. type))))
  134. types))
  135. (define (visit-val-type type types)
  136. (match type
  137. ((or 'i32 'i64 'f32 'f64 'v128
  138. 'funcref 'externref 'anyref 'eqref 'i31ref
  139. 'nullexternref 'nullfuncref
  140. 'structref 'arrayref
  141. 'nullref
  142. 'stringref
  143. 'stringview_wtf8ref 'stringview_wtf16ref 'stringview_iterref)
  144. types)
  145. (($ <ref-type> nullable? ht)
  146. (visit-heap-type ht types))))
  147. (define (visit-storage-type type types)
  148. (match type
  149. ((or 'i8 'i16) types)
  150. (_ (visit-val-type type types))))
  151. (define (visit-func-sig params results types)
  152. (fold1 (lambda (param types)
  153. (match param
  154. (($ <param> id type)
  155. (visit-val-type type types))))
  156. params
  157. (fold1 visit-val-type results types)))
  158. (define (visit-type type types)
  159. (define (visit-base type types)
  160. (match type
  161. (($ <array-type> mutable? type)
  162. (visit-storage-type type types))
  163. (($ <struct-type> fields)
  164. (fold1 (lambda (field types)
  165. (match field
  166. (($ <field> id mutable? type)
  167. (visit-storage-type type types))))
  168. fields types))
  169. (($ <func-sig> params results)
  170. (visit-func-sig params results types))))
  171. (define (visit-sub type types)
  172. (match type
  173. (($ <sub-type> final? supers type)
  174. (visit-base type
  175. (fold1 visit-heap-type supers types)))
  176. (_ (visit-base type types))))
  177. (match type
  178. (($ <rec-group> (($ <type> id type) ...))
  179. (fold1 visit-sub type types))
  180. (($ <type> id type)
  181. (visit-sub type types))))
  182. (define (visit-heap-type type types)
  183. (match type
  184. ((or 'func 'extern 'any 'eq 'i31 'noextern 'nofunc 'struct 'array 'none
  185. 'string 'stringview_wtf8 'stringview_wtf16 'stringview_iter)
  186. types)
  187. (_
  188. (match (lookup-type type types)
  189. (#f (let ((type (or (link-type type)
  190. (error "unknown heap type" type))))
  191. (visit-type type (cons type types))))
  192. (type types)))))
  193. (define (visit-ref-type type types)
  194. (match type
  195. (($ <ref-type> nullable? ht)
  196. (visit-heap-type ht types))
  197. (_ types)))
  198. (define (visit-func-type type types)
  199. (visit-heap-type type types))
  200. (define (visit-type-use type types)
  201. (match type
  202. (($ <type-use> idx ($ <func-sig> params results))
  203. (let ((types (visit-func-sig params results types)))
  204. (if (symbol? idx)
  205. (visit-func-type idx types)
  206. types)))))
  207. (define (visit-body body types)
  208. (fold-instructions
  209. (lambda (inst types)
  210. (match inst
  211. (((or 'block 'loop 'if 'try 'try_delegate) label type . _)
  212. (if type
  213. (visit-type-use type types)
  214. types))
  215. (((or 'call_indirect 'return_call_indirect) table type)
  216. (visit-type-use type types))
  217. (((or 'call_ref 'return_call_ref) table type)
  218. (visit-type-use type types))
  219. (('select type ...)
  220. (fold1 visit-val-type type types))
  221. (('ref.null type)
  222. (visit-heap-type type types))
  223. (((or 'struct.get 'struct.get_s 'struct.get_u
  224. 'struct.set) type field)
  225. (visit-heap-type type types))
  226. (((or 'struct.new 'struct.new_default
  227. 'array.new 'array.new_default
  228. 'array.get 'array.get_s 'array.get_u
  229. 'array.set) type)
  230. (visit-heap-type type types))
  231. (('array.copy dst src)
  232. (visit-heap-type dst (visit-heap-type src types)))
  233. (((or 'array.new_fixed 'array.new_data 'array.new_elem
  234. 'array.init_data 'array.init_elem) type _)
  235. (visit-heap-type type types))
  236. (((or 'ref.test 'ref.cast) ($ <ref-type> nullable? type))
  237. (visit-heap-type type types))
  238. (((or 'br_on_cast 'br_on_cast_fail) idx rt1 rt2)
  239. (visit-ref-type rt1 (visit-ref-type rt2 types)))
  240. (_ types)))
  241. body types))
  242. (define (visit-function func types)
  243. (match func
  244. (($ <func> id type (($ <local> lid ltype) ...) body)
  245. (visit-body
  246. body
  247. (fold1 visit-val-type ltype
  248. (visit-type-use type types))))))
  249. (define (visit-import import types)
  250. (match import
  251. (($ <import> mod name 'func id type)
  252. (visit-type-use type types))
  253. (($ <import> mod name 'table id ($ <table-type> limits type))
  254. (visit-val-type type types))
  255. (($ <import> mod name 'memory id type)
  256. types)
  257. (($ <import> mod name 'global id ($ <global-type> mutable? type))
  258. (visit-val-type type types))
  259. (($ <import> mod name 'tag id ($ <tag-type> attribute type))
  260. (visit-type-use type types)))
  261. types)
  262. (define (visit-table table types)
  263. (match table
  264. (($ <table> id ($ <table-type> limits type) init)
  265. (visit-val-type type
  266. (if init
  267. (visit-body init types)
  268. types)))))
  269. (define (visit-global global types)
  270. (match global
  271. (($ <global> id ($ <global-type> mutable? type) init)
  272. (visit-val-type type (visit-body init types)))))
  273. (define (visit-elem elem types)
  274. (match elem
  275. (($ <elem> id mode table type offset inits)
  276. (let* ((types (fold1 visit-body inits types))
  277. (types (visit-val-type type types)))
  278. (if offset
  279. (visit-body offset types)
  280. types)))))
  281. (define (visit-tag tag types)
  282. (match tag
  283. (($ <tag> id ($ <tag-type> attribute type))
  284. (visit-type-use type types))))
  285. (sort-types
  286. (fold1 visit-function funcs
  287. (fold1 visit-import imports
  288. (fold1 visit-table tables
  289. (fold1 visit-global globals
  290. (fold1 visit-elem elems
  291. (fold1 visit-tag tags
  292. (fold1 visit-type types
  293. types)))))))))
  294. (define (compute-imports imports funcs tables memories globals exports
  295. elems tags)
  296. (define (function-locally-bound? label)
  297. (or-map (match-lambda (($ <func> id) (eqv? label id)))
  298. funcs))
  299. (define (global-locally-bound? label)
  300. (or-map (match-lambda (($ <global> id type init) (eq? id label)))
  301. globals))
  302. (define (table-locally-bound? label)
  303. (or-map (match-lambda (($ <table> id type init) (eq? id label)))
  304. tables))
  305. (define (memory-locally-bound? label)
  306. (or-map (match-lambda (($ <memory> id type) (eq? id label)))
  307. memories))
  308. (define (tag-locally-bound? label)
  309. (or-map (match-lambda (($ <tag> id type) (eq? id label)))
  310. tags))
  311. (define (add-import import kind imports)
  312. (define (lookup name imports)
  313. (simple-lookup
  314. imports
  315. (($ <import> mod' name' kind' id')
  316. (and (eq? kind' kind) (eqv? id' name)))))
  317. (match (lookup import imports)
  318. (#f (cons (or (link-import import kind)
  319. (error "unknown import" import kind))
  320. imports))
  321. (_ imports)))
  322. (define (add-imported-func label imports)
  323. (if (function-locally-bound? label)
  324. imports
  325. (add-import label 'func imports)))
  326. (define (add-imported-table label imports)
  327. (if (table-locally-bound? label)
  328. imports
  329. (add-import label 'table imports)))
  330. (define (add-imported-global label imports)
  331. (if (global-locally-bound? label)
  332. imports
  333. (add-import label 'global imports)))
  334. (define (add-imported-memory label imports)
  335. (if (memory-locally-bound? label)
  336. imports
  337. (add-import label 'memory imports)))
  338. (define (add-imported-tag label imports)
  339. (if (tag-locally-bound? label)
  340. imports
  341. (add-import label 'tag imports)))
  342. (define (visit-body body imports)
  343. (fold-instructions
  344. (lambda (inst imports)
  345. (match inst
  346. (((or 'call 'return_call 'ref.func) label)
  347. (add-imported-func label imports))
  348. (((or 'table.get 'table.set
  349. 'table.grow 'table.size 'table.fill) label)
  350. (add-imported-table label imports))
  351. (('table.init elem table)
  352. (add-imported-table table imports))
  353. (('call_indirect type table)
  354. (add-imported-table table imports))
  355. (('table.copy dst src)
  356. (add-imported-table dst (add-imported-table src imports)))
  357. (((or 'global.get 'global.set) label)
  358. (add-imported-global label imports))
  359. (((or 'i32.load 'i64.load 'f32.load 'f64.load
  360. 'i32.load8_s 'i32.load8_u 'i32.load16_s 'i32.load16_u
  361. 'i64.load8_s 'i64.load8_u 'i64.load16_s 'i64.load16_u
  362. 'i64.load32_s 'i64.load32_u
  363. 'i32.store 'i64.store 'f32.store 'f64.store
  364. 'i32.store8 'i32.store16 'i64.store8 'i64.store16
  365. 'i64.store32)
  366. ($ <mem-arg> id offset align))
  367. (add-imported-memory id imports))
  368. (((or 'memory.size 'memory.grow 'memory.init 'memory.fill) id)
  369. (add-imported-memory id imports))
  370. (('memory.copy dst src)
  371. (add-imported-memory dst (add-imported-memory src imports)))
  372. (('try _ _ _ ((tags . _) ...) _)
  373. (fold1 add-imported-tag tags imports))
  374. (('throw tag)
  375. (add-imported-tag tag imports))
  376. (_ imports)))
  377. body imports))
  378. (define (visit-func func imports)
  379. (match func
  380. (($ <func> id type locals body)
  381. (visit-body body imports))))
  382. (define (visit-table table imports)
  383. (match table
  384. (($ <table> id type init)
  385. (if init
  386. (visit-body init imports)
  387. imports))))
  388. (define (visit-global global imports)
  389. (match global
  390. (($ <global> id type init)
  391. (visit-body init imports))))
  392. (define (visit-export export imports)
  393. (match export
  394. (($ <export> name kind id)
  395. (match kind
  396. ('func (add-imported-func id imports))
  397. ('table (add-imported-table id imports))
  398. ('global (add-imported-global id imports))
  399. ('memory (add-imported-memory id imports))
  400. ('tag (add-imported-tag id imports))))))
  401. (define (visit-elem elem imports)
  402. (match elem
  403. (($ <elem> id mode table type offset inits)
  404. (let ((imports (fold1 visit-body inits imports)))
  405. (if offset
  406. (visit-body offset imports)
  407. imports)))))
  408. (reverse
  409. (fold1 visit-func funcs
  410. (fold1 visit-table tables
  411. (fold1 visit-global globals
  412. (fold1 visit-export exports
  413. (fold1 visit-elem elems
  414. (reverse imports))))))))
  415. (define (compute-funcs funcs tables globals exports elems)
  416. (define (add-func name funcs)
  417. (define (lookup name funcs)
  418. (simple-lookup funcs (($ <func> id) (eqv? id name))))
  419. (match (lookup name funcs)
  420. (#f (match (link-func name)
  421. (#f funcs)
  422. (func (visit-func func (cons func funcs)))))
  423. (_ funcs)))
  424. (define (visit-body body funcs)
  425. (fold-instructions
  426. (lambda (inst funcs)
  427. (match inst
  428. (((or 'call 'return_call 'ref.func) f)
  429. (add-func f funcs))
  430. (_ funcs)))
  431. body funcs))
  432. (define (visit-func func funcs)
  433. (match func
  434. (($ <func> id type locals body)
  435. (visit-body body funcs))))
  436. (define (visit-table table funcs)
  437. (match table
  438. (($ <table> id type init)
  439. (if init
  440. (visit-body init funcs)
  441. funcs))))
  442. (define (visit-global global funcs)
  443. (match global
  444. (($ <global> id type init)
  445. (visit-body init funcs))))
  446. (define (visit-export export funcs)
  447. (match export
  448. (($ <export> name kind id)
  449. (if (eq? kind 'func)
  450. (add-func id funcs)
  451. funcs))))
  452. (define (visit-elem elem funcs)
  453. (match elem
  454. (($ <elem> id mode table type offset inits)
  455. (let ((funcs (fold1 visit-body inits funcs)))
  456. (if offset
  457. (visit-body offset funcs)
  458. funcs)))))
  459. (reverse
  460. (fold1 visit-func funcs
  461. (fold1 visit-table tables
  462. (fold1 visit-global globals
  463. (fold1 visit-export exports
  464. (fold1 visit-elem elems
  465. (reverse funcs))))))))
  466. (define (compute-tables funcs tables exports)
  467. (define (add-table table tables)
  468. (define (lookup name tables)
  469. (simple-lookup
  470. tables
  471. (($ <table> id) (eqv? id name))))
  472. (match (lookup table tables)
  473. (#f (match (link-table table)
  474. (#f tables)
  475. (table (cons table tables))))
  476. (_ tables)))
  477. (define (visit-func func tables)
  478. (match func
  479. (($ <func> id type locals body)
  480. (fold-instructions
  481. (lambda (inst tables)
  482. (match inst
  483. (((or 'table.get 'table.set
  484. 'table.grow 'table.size 'table.fill)
  485. table)
  486. (add-table table tables))
  487. (('table.init elem table)
  488. (add-table table tables))
  489. (('table.copy dst src)
  490. (add-table dst (add-table src tables)))
  491. (('call_indirect table type)
  492. (add-table table tables))
  493. (_ tables)))
  494. body tables))))
  495. (define (visit-export export tables)
  496. (match export
  497. (($ <export> name kind id)
  498. (if (eq? kind 'table)
  499. (add-table id tables)
  500. tables))))
  501. (reverse (fold1 visit-func funcs
  502. (fold1 visit-export exports (reverse tables)))))
  503. (define (compute-memories funcs memories exports datas)
  504. (define (add-memory memory memories)
  505. (define (lookup name memories)
  506. (simple-lookup
  507. memories
  508. (($ <memory> id) (eqv? id name))))
  509. (match (lookup memory memories)
  510. (#f (match (link-memory memory)
  511. (#f memories)
  512. (memory (cons memory memories))))
  513. (_ memories)))
  514. (define (visit-body body memories)
  515. (fold-instructions
  516. (lambda (inst memories)
  517. (match inst
  518. (((or 'i32.load 'i64.load 'f32.load 'f64.load
  519. 'i32.load8_s 'i32.load8_u 'i32.load16_s 'i32.load16_u
  520. 'i64.load8_s 'i64.load8_u 'i64.load16_s 'i64.load16_u
  521. 'i64.load32_s 'i64.load32_u
  522. 'i32.store 'i64.store 'f32.store 'f64.store
  523. 'i32.store8 'i32.store16 'i64.store8 'i64.store16
  524. 'i64.store32)
  525. ($ <mem-arg> id offset align))
  526. (add-memory id memories))
  527. (((or 'memory.size 'memory.grow 'memory.init 'memory.fill) id)
  528. (add-memory id memories))
  529. (('memory.copy dst src)
  530. (add-memory dst (add-memory src memories)))
  531. (_ memories)))
  532. body memories))
  533. (define (visit-func func memories)
  534. (match func
  535. (($ <func> id type locals body)
  536. (visit-body body memories))))
  537. (define (visit-export export memories)
  538. (match export
  539. (($ <export> name kind id)
  540. (if (eq? kind 'memory)
  541. (add-memory id memories)
  542. memories))))
  543. (define (visit-data data memories)
  544. (match data
  545. (($ <data> id mode mem offset init)
  546. (if (eq? mode 'active)
  547. (add-memory mem memories)
  548. memories))))
  549. (reverse
  550. (fold1 visit-func funcs
  551. (fold1 visit-export exports
  552. (fold1 visit-data datas
  553. (reverse memories))))))
  554. (define (compute-globals funcs tables globals exports elems)
  555. (define (add-global global globals)
  556. (define (lookup name globals)
  557. (simple-lookup
  558. globals
  559. (($ <global> id) (eqv? id name))))
  560. (match (lookup global globals)
  561. (#f (match (link-global global)
  562. (#f globals)
  563. (global (visit-global global (cons global globals)))))
  564. (_ globals)))
  565. (define (visit-body body globals)
  566. (fold-instructions
  567. (lambda (inst globals)
  568. (match inst
  569. (((or 'global.get 'global.set) global)
  570. (add-global global globals))
  571. (_ globals)))
  572. body globals))
  573. (define (visit-func func globals)
  574. (match func
  575. (($ <func> id type locals body)
  576. (visit-body body globals))))
  577. (define (visit-table table globals)
  578. (match table
  579. (($ <table> id type init)
  580. (if init
  581. (visit-body init globals)
  582. globals))))
  583. (define (visit-global global globals)
  584. (match global
  585. (($ <global> id type init)
  586. (visit-body init globals))))
  587. (define (visit-export export globals)
  588. (match export
  589. (($ <export> name kind id)
  590. (if (eq? kind 'global)
  591. (add-global id globals)
  592. globals))))
  593. (define (visit-elem elem globals)
  594. (match elem
  595. (($ <elem> id mode table type offset inits)
  596. (let ((globals (fold1 visit-body inits globals)))
  597. (if offset
  598. (visit-body offset globals)
  599. globals)))))
  600. (reverse
  601. (fold1 visit-func funcs
  602. (fold1 visit-table tables
  603. (fold1 visit-global globals
  604. (fold1 visit-export exports
  605. (fold1 visit-elem elems
  606. (reverse globals))))))))
  607. (define (compute-datas funcs tables globals datas)
  608. (define (add-data data datas)
  609. (define (lookup name datas)
  610. (simple-lookup
  611. datas
  612. (($ <data> id) (eqv? id name))))
  613. (match (lookup data datas)
  614. (#f (match (link-data data)
  615. (#f datas)
  616. (data (cons data datas))))
  617. (_ datas)))
  618. (define (visit-body body datas)
  619. (fold-instructions
  620. (lambda (inst datas)
  621. (match inst
  622. (((or 'array.new_data 'array.init_data) type data)
  623. (add-data data datas))
  624. (_ datas)))
  625. body datas))
  626. (define (visit-func func datas)
  627. (match func
  628. (($ <func> id type locals body)
  629. (visit-body body datas))))
  630. (define (visit-table table datas)
  631. (match table
  632. (($ <table> id type init)
  633. (if init
  634. (visit-body init datas)
  635. datas))))
  636. (define (visit-global global datas)
  637. (match global
  638. (($ <global> id type init)
  639. (visit-body init datas))))
  640. (reverse
  641. (fold1 visit-func funcs
  642. (fold1 visit-table tables
  643. (fold1 visit-global globals
  644. (reverse datas))))))
  645. (define (compute-tags funcs exports tags)
  646. (define (add-tag tag tags)
  647. (define (lookup name tags)
  648. (simple-lookup
  649. tags
  650. (($ <tag> id) (eqv? id name))))
  651. (match (lookup tag tags)
  652. (#f (match (link-tag tag)
  653. (#f tags)
  654. (tag (cons tag tags))))
  655. (_ tags)))
  656. (define (visit-body body tags)
  657. (fold-instructions
  658. (lambda (inst tags)
  659. (match inst
  660. (('try _ _ _ ((tags* . _) ...) _)
  661. (fold1 add-tag tags* tags))
  662. (('throw tag)
  663. (add-tag tag tags))
  664. (_ tags)))
  665. body tags))
  666. (define (visit-func func tags)
  667. (match func
  668. (($ <func> id type locals body)
  669. (visit-body body tags))))
  670. (define (visit-export export tags)
  671. (match export
  672. (($ <export> name kind id)
  673. (if (eq? kind 'tag)
  674. (add-tag id tags)
  675. tags))))
  676. (reverse
  677. (fold1 visit-export exports
  678. (fold1 visit-func funcs
  679. (reverse tags)))))
  680. (match wasm
  681. (($ <wasm> id types imports funcs tables memories globals exports
  682. start elems datas tags strings custom)
  683. ;; An export can pull in funcs, tables, globals, and memories,
  684. ;; possibly imported.
  685. ;;
  686. ;; A function can pull in types, funcs, tables, globals,
  687. ;; memories, and tags from the stdlib. These fragments may be
  688. ;; locally defined or imported (except for types which are always
  689. ;; locally defined).
  690. ;;
  691. ;; A table can pull in types, globals, and functions, possibly
  692. ;; imported.
  693. ;;
  694. ;; A global can pull in types, globals, and functions, possibly
  695. ;; imported.
  696. ;;
  697. ;; An elem can pull in types and globals, possibly imported.
  698. ;;
  699. ;; An import can pull in types.
  700. ;;
  701. ;; A tag can pull in types.
  702. ;;
  703. ;; A type can pull in other types.
  704. ;;
  705. ;; Data can pull in a memory.
  706. ;;
  707. ;; Memories can't pull in anything else.
  708. ;;
  709. ;; Therefore, to allow pieces of the stdlib to lazily pull in
  710. ;; other pieces of the stdlib, we do a fixed-point on the set of
  711. ;; funcs, tables, and globals, then we compute memories, imports,
  712. ;; types, and tags.
  713. (let fixpoint ((funcs funcs) (tables tables) (globals globals))
  714. (let* ((funcs' (compute-funcs funcs tables globals exports elems))
  715. (tables' (compute-tables funcs' tables exports))
  716. (globals' (compute-globals funcs' tables' globals exports elems)))
  717. (if (and (= (length funcs') (length funcs))
  718. (= (length tables') (length tables))
  719. (= (length globals') (length globals)))
  720. (let* ((datas (compute-datas funcs tables globals datas))
  721. (memories (compute-memories funcs memories exports datas))
  722. (tags (compute-tags funcs exports tags)))
  723. (let ((imports (compute-imports imports funcs tables memories
  724. globals exports elems tags))
  725. (types (compute-types types imports funcs tables globals
  726. elems tags)))
  727. (make-wasm id types imports funcs tables memories globals
  728. exports start elems datas tags strings custom)))
  729. (fixpoint funcs' tables' globals')))))))
  730. (define* (add-stdlib wasm stdlib #:key
  731. (synthesize-type (lambda (id) #f))
  732. (synthesize-import (lambda (id kind) #f)))
  733. (match stdlib
  734. (($ <wasm> std-id std-types std-imports std-funcs std-tables std-memories
  735. std-globals std-exports std-start std-elems std-datas std-tags
  736. std-strings std-custom)
  737. (define types (make-hash-table))
  738. (define imports (make-hash-table))
  739. (define funcs (make-hash-table))
  740. (define tables (make-hash-table))
  741. (define memories (make-hash-table))
  742. (define globals (make-hash-table))
  743. (define datas (make-hash-table))
  744. (define tags (make-hash-table))
  745. (for-each (match-lambda
  746. ((and t ($ <type> id _)) (hashq-set! types id t))
  747. ((and t ($ <rec-group> (($ <type> id) ...)))
  748. (for-each (lambda (id) (hashq-set! types id t)) id)))
  749. std-types)
  750. (for-each (match-lambda
  751. ((and import ($ <import> mode name kind id type))
  752. (hash-set! imports (cons id kind) import)))
  753. std-imports)
  754. (for-each (match-lambda
  755. ((and func ($ <func> id type locals body))
  756. (hashq-set! funcs id func)))
  757. std-funcs)
  758. (for-each (match-lambda
  759. ((and table ($ <table> id type init))
  760. (hashq-set! tables id table)))
  761. std-tables)
  762. (for-each (match-lambda
  763. ((and memory ($ <memory> id type))
  764. (hashq-set! memories id memory)))
  765. std-memories)
  766. (for-each (match-lambda
  767. ((and global ($ <global> id type init))
  768. (hashq-set! globals id global)))
  769. std-globals)
  770. (for-each (match-lambda
  771. ((and data ($ <data> id mode mem offset init))
  772. (hashq-set! datas id data)))
  773. std-datas)
  774. (for-each (match-lambda
  775. ((and tag ($ <tag> id type))
  776. (hashq-set! tags id tag)))
  777. std-tags)
  778. (link wasm
  779. #:link-type (lambda (id)
  780. (or (hashq-ref types id)
  781. (synthesize-type id)))
  782. #:link-import (lambda (id kind)
  783. (or (hash-ref imports (cons id kind))
  784. (synthesize-import id kind)))
  785. #:link-func (lambda (id) (hashq-ref funcs id))
  786. #:link-table (lambda (id) (hashq-ref tables id))
  787. #:link-memory (lambda (id) (hashq-ref memories id))
  788. #:link-global (lambda (id) (hashq-ref globals id))
  789. #:link-data (lambda (id) (hashq-ref datas id))
  790. #:link-tag (lambda (id) (hashq-ref tags id))))))