effects.scm 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  1. ;;; WebAssembly effects analysis
  2. ;;; Copyright (C) 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. ;;; Effects analysis for WebAssembly. Compute a simple approximation of
  18. ;;; the side effects for each WebAssembly instruction.
  19. ;;;
  20. ;;; We model three kinds of effects: control effects, reads, and writes.
  21. ;;; Stack effects are excluded; for that, see (wasm stack) instead.
  22. ;;;
  23. ;;; A control effect is a potential nonlocal branch. The current
  24. ;;; analysis just notes the possible presence or definite absence of
  25. ;;; these effects.
  26. ;;;
  27. ;;; A read is a is either *, indicating that the instruction reads from
  28. ;;; potentially all mutable locations, or a list of specific mutable
  29. ;;; locations. A mutable location is either:
  30. ;;;
  31. ;;; - (global ID): a global named ID
  32. ;;; - (table ID): a table named ID
  33. ;;; - (memory ID): a memory named ID (either contents or size)
  34. ;;; - (table ID): a table named ID (either contents or size)
  35. ;;; - (struct TYPE FIELD): a field named FIELD of a struct of type TYPE
  36. ;;; - (array TYPE): a field of an array of type TYPE
  37. ;;;
  38. ;;; This pass assumes that all ID's denote distinct entities. This is
  39. ;;; the case if there are no duplicate types in the module, and no
  40. ;;; duplicate imports, and if all names are symbolified instead of
  41. ;;; referred to by index. See (wasm symbolify).
  42. ;;;
  43. ;;; This pass also assumes the absence of traps. For example, we assume
  44. ;;; that `table.get` will not issue an out-of-bounds trap, that
  45. ;;; `ref.cast` will not trap, and so on.
  46. ;;;
  47. ;;; As a limitation, we currently do not consider subtyping: reading
  48. ;;; e.g. a field from a given struct type and a subtype are considered
  49. ;;; separate locations. We should instead canonicalize types and
  50. ;;; compute the array type that defines the given field.
  51. ;;;
  52. ;;; Code:
  53. (define-module (wasm effects)
  54. #:use-module (ice-9 match)
  55. #:use-module (srfi srfi-9)
  56. #:use-module (wasm types)
  57. #:export (compute-effect
  58. <effect>
  59. effect-control?
  60. effect-reads
  61. effect-writes
  62. nofx))
  63. (define-record-type <effect>
  64. (make-effect control? reads writes)
  65. effect?
  66. (control? effect-control?)
  67. (reads effect-reads)
  68. (writes effect-writes))
  69. (define nofx (make-effect #f '() '()))
  70. ;; Assumptions:
  71. ;; - no table get/set traps
  72. ;; - no memory load/store traps
  73. ;; - tables and memories do not alias: distinct identifiers denote
  74. ;; different entities
  75. ;; - no arithmetic traps (division by zero etc)
  76. ;; - types do not alias. subtyping??
  77. ;; - no array access traps
  78. ;; - no ref.cast / ref.as_non_null traps
  79. ;; - no wtf8 traps or other string traps
  80. (define (compute-effect inst)
  81. (define-syntax fx-access
  82. (syntax-rules (global
  83. memory
  84. table
  85. struct
  86. array)
  87. ((_ (global id)) `(global ,id))
  88. ((_ (memory id)) `(memory ,id))
  89. ((_ (table id)) `(table ,id))
  90. ((_ (struct type field)) `(struct ,type ,field))
  91. ((_ (array type)) `(array ,type))))
  92. (define-syntax fx-accesses
  93. (syntax-rules (*)
  94. ((_ *) '*)
  95. ((_ (access ...)) (list (fx-access access) ...))))
  96. (define-syntax-rule (%fx control? reads writes)
  97. (make-effect control? (fx-accesses reads) (fx-accesses writes)))
  98. (define-syntax-rule (fx reads writes) (%fx #f reads writes))
  99. (define-syntax-rule (fx! reads writes) (%fx #t reads writes))
  100. (match inst
  101. ((op . args)
  102. (match op
  103. ('unreachable (fx! () ()))
  104. ('nop (fx () ()))
  105. ('block (fx! * *))
  106. ('loop (fx! * *))
  107. ('if (fx! * *))
  108. ('try (fx! * *))
  109. ('try_delegate (fx! * *))
  110. ('throw (fx! () ()))
  111. ('rethrow (fx! () ()))
  112. ('br (fx! () ()))
  113. ('br_if (fx! () ()))
  114. ('br_table (fx! () ()))
  115. ('return (fx! () ()))
  116. ('call (fx! * *))
  117. ('call_indirect (fx! * *))
  118. ('return_call (fx! * *))
  119. ('return_call_indirect (fx! * *))
  120. ('call_ref (fx! * *))
  121. ('return_call_ref (fx! * *))
  122. ('drop (fx () ()))
  123. ('select (fx () ()))
  124. ('local.get (fx () ()))
  125. ('local.set (fx () ()))
  126. ('local.tee (fx () ()))
  127. ('global.get (match args
  128. ((id) (fx ((global id)) ()))))
  129. ('global.set (match args
  130. ((id) (fx () ((global id))))))
  131. ('table.copy (match args
  132. ((dst src)
  133. (fx ((table src)) ((table dst))))))
  134. ('table.fill (match args
  135. ((id)
  136. (fx () ((table id))))))
  137. ('table.grow (match args
  138. ((id)
  139. (fx ((table id))
  140. ((table id))))))
  141. ('table.init (match args
  142. ((id elem)
  143. (fx () ((table id))))))
  144. ('table.size (match args
  145. ((id)
  146. (fx ((table id)) ()))))
  147. ('table.get (match args
  148. ((id)
  149. (fx ((table id)) ()))))
  150. ('table.set (match args
  151. ((id)
  152. (fx () ((table id))))))
  153. ('memory.size (match args
  154. ((id)
  155. (fx ((memory id)) ()))))
  156. ('memory.grow (match args
  157. ((id)
  158. (fx ((memory id))
  159. ((memory id) (memory id))))))
  160. ('memory.copy (match args
  161. ((dst src)
  162. (fx ((memory src)) ((memory dst))))))
  163. ('memory.fill (match args
  164. ((id)
  165. (fx () ((memory id))))))
  166. ('memory.init (match args
  167. ((id data)
  168. (fx () ((memory id))))))
  169. ((or 'i32.load
  170. 'i64.load
  171. 'f32.load
  172. 'f64.load
  173. 'i32.load8_s
  174. 'i32.load8_u
  175. 'i32.load16_s
  176. 'i32.load16_u
  177. 'i64.load8_s
  178. 'i64.load8_u
  179. 'i64.load16_s
  180. 'i64.load16_u
  181. 'i64.load32_s
  182. 'i64.load32_u) (match args
  183. ((($ <mem-arg> id offset align))
  184. (fx ((memory id)) ()))))
  185. ((or 'i32.store
  186. 'i64.store
  187. 'f32.store
  188. 'f64.store
  189. 'i32.store8
  190. 'i32.store16
  191. 'i64.store8
  192. 'i64.store16
  193. 'i64.store32) (match args
  194. ((($ <mem-arg> id offset align))
  195. (fx () ((memory id))))))
  196. ((or 'i32.const
  197. 'i64.const
  198. 'f32.const
  199. 'f64.const) (fx () ()))
  200. ((or 'i32.eqz
  201. 'i32.eq
  202. 'i32.ne
  203. 'i32.lt_s
  204. 'i32.lt_u
  205. 'i32.gt_s
  206. 'i32.gt_u
  207. 'i32.le_s
  208. 'i32.le_u
  209. 'i32.ge_s
  210. 'i32.ge_u
  211. 'i64.eqz
  212. 'i64.eq
  213. 'i64.ne
  214. 'i64.lt_s
  215. 'i64.lt_u
  216. 'i64.gt_s
  217. 'i64.gt_u
  218. 'i64.le_s
  219. 'i64.le_u
  220. 'i64.ge_s
  221. 'i64.ge_u
  222. 'f32.eq
  223. 'f32.ne
  224. 'f32.lt
  225. 'f32.gt
  226. 'f32.le
  227. 'f32.ge
  228. 'f64.eq
  229. 'f64.ne
  230. 'f64.lt
  231. 'f64.gt
  232. 'f64.le
  233. 'f64.ge
  234. 'i32.clz
  235. 'i32.ctz
  236. 'i32.popcnt
  237. 'i32.add
  238. 'i32.sub
  239. 'i32.mul
  240. 'i32.div_s
  241. 'i32.div_u
  242. 'i32.rem_s
  243. 'i32.rem_u
  244. 'i32.and
  245. 'i32.or
  246. 'i32.xor
  247. 'i32.shl
  248. 'i32.shr_s
  249. 'i32.shr_u
  250. 'i32.rotl
  251. 'i32.rotr
  252. 'i64.clz
  253. 'i64.ctz
  254. 'i64.popcnt
  255. 'i64.add
  256. 'i64.sub
  257. 'i64.mul
  258. 'i64.div_s
  259. 'i64.div_u
  260. 'i64.rem_s
  261. 'i64.rem_u
  262. 'i64.and
  263. 'i64.or
  264. 'i64.xor
  265. 'i64.shl
  266. 'i64.shr_s
  267. 'i64.shr_u
  268. 'i64.rotl
  269. 'i64.rotr
  270. 'f32.abs
  271. 'f32.neg
  272. 'f32.ceil
  273. 'f32.floor
  274. 'f32.trunc
  275. 'f32.nearest
  276. 'f32.sqrt
  277. 'f32.add
  278. 'f32.sub
  279. 'f32.mul
  280. 'f32.div
  281. 'f32.min
  282. 'f32.max
  283. 'f32.copysign
  284. 'f64.abs
  285. 'f64.neg
  286. 'f64.ceil
  287. 'f64.floor
  288. 'f64.trunc
  289. 'f64.nearest
  290. 'f64.sqrt
  291. 'f64.add
  292. 'f64.sub
  293. 'f64.mul
  294. 'f64.div
  295. 'f64.min
  296. 'f64.max
  297. 'f64.copysign
  298. 'i32.wrap_i64
  299. 'i32.trunc_f32_s
  300. 'i32.trunc_f32_u
  301. 'i32.trunc_f64_s
  302. 'i32.trunc_f64_u
  303. 'i64.extend_i32_s
  304. 'i64.extend_i32_u
  305. 'i64.trunc_f32_s
  306. 'i64.trunc_f32_u
  307. 'i64.trunc_f64_s
  308. 'i64.trunc_f64_u
  309. 'f32.convert_i32_s
  310. 'f32.convert_i32_u
  311. 'f32.convert_i64_s
  312. 'f32.convert_i64_u
  313. 'f32.demote_f64
  314. 'f64.convert_i32_s
  315. 'f64.convert_i32_u
  316. 'f64.convert_i64_s
  317. 'f64.convert_i64_u
  318. 'f64.promote_f32
  319. 'i32.reinterpret_f32
  320. 'i64.reinterpret_f64
  321. 'f32.reinterpret_i32
  322. 'f64.reinterpret_i64
  323. 'i32.extend8_s
  324. 'i32.extend16_s
  325. 'i64.extend8_s
  326. 'i64.extend16_s
  327. 'i64.extend32_s
  328. 'i32.trunc_sat_f32_s
  329. 'i32.trunc_sat_f32_u
  330. 'i32.trunc_sat_f64_s
  331. 'i32.trunc_sat_f64_u
  332. 'i64.trunc_sat_f32_s
  333. 'i64.trunc_sat_f32_u
  334. 'i64.trunc_sat_f64_s
  335. 'i64.trunc_sat_f64_u) (fx () ()))
  336. ;; GC.
  337. ('ref.null (fx () ()))
  338. ('ref.is_null (fx () ()))
  339. ('ref.func (fx () ()))
  340. ('ref.eq (fx () ()))
  341. ('ref.as_non_null (fx! () ()))
  342. ('struct.new (fx () ()))
  343. ('struct.new_default (fx () ()))
  344. ((or 'struct.get
  345. 'struct.get_s
  346. 'struct.get_u) (match args
  347. ((type field)
  348. (fx ((struct type field)) ()))))
  349. ('struct.set (match args
  350. ((type field)
  351. (fx () ((struct type field))))))
  352. ('array.new (fx () ()))
  353. ('array.new_default (fx () ()))
  354. ('array.new_fixed (fx () ()))
  355. ('array.new_data (fx () ()))
  356. ('array.new_elem (fx () ()))
  357. ((or 'array.get
  358. 'array.get_s
  359. 'array.get_u) (match args
  360. ((type)
  361. (fx ((array type)) ()))))
  362. ('array.set (match args
  363. ((type)
  364. (fx () ((array type))))))
  365. ('array.len (fx () ()))
  366. ('array.fill (match args
  367. ((type)
  368. (fx () ((array type))))))
  369. ('array.copy (match args
  370. ((dst src)
  371. (fx ((array src)) ((array dst))))))
  372. ('array.init_data (match args
  373. ((type data)
  374. (fx () ((array type))))))
  375. ('array.init_elem (match args
  376. ((type elem)
  377. (fx () ((array type))))))
  378. ('ref.test (fx () ()))
  379. ('ref.cast (fx () ()))
  380. ('br_on_cast (fx! () ()))
  381. ('br_on_cast_fail (fx! () ()))
  382. ('extern.internalize (fx () ()))
  383. ('extern.externalize (fx () ()))
  384. ('ref.i31 (fx () ()))
  385. ('i31.get_s (fx () ()))
  386. ('i31.get_u (fx () ()))
  387. ;; Stringref.
  388. ((or 'string.new_utf8
  389. 'string.new_lossy_utf8
  390. 'string.new_wtf8
  391. 'string.new_wtf16) (match args
  392. ((id)
  393. (fx ((memory id)) ()))))
  394. ('string.const (fx () ()))
  395. ((or 'string.measure_utf8
  396. 'string.measure_wtf8
  397. 'string.measure_wtf16) (fx () ()))
  398. ((or 'string.encode_utf8
  399. 'string.encode_lossy_utf8
  400. 'string.encode_wtf8
  401. 'string.encode_wtf16) (match args
  402. ((id)
  403. (fx () ((memory id))))))
  404. ('string.concat (fx () ()))
  405. ('string.eq (fx () ()))
  406. ('string.is_usv_sequence (fx () ()))
  407. ('string.compare (fx () ()))
  408. ('string.from_code_point (fx () ()))
  409. ('string.as_wtf8 (fx () ()))
  410. ('stringview_wtf8.advance (fx () ()))
  411. ((or 'stringview_wtf8.encode_utf8
  412. 'stringview_wtf8.encode_lossy_utf8
  413. 'stringview_wtf8.encode_wtf8) (match args
  414. ((id)
  415. (fx () ((memory id))))))
  416. ('stringview_wtf8.slice (fx () ()))
  417. ('string.as_wtf16 (fx () ()))
  418. ('stringview_wtf16.length (fx () ()))
  419. ('stringview_wtf16.get_codeunit (fx () ()))
  420. ('stringview_wtf16.encode (match args
  421. ((id)
  422. (fx () ((memory id))))))
  423. ('stringview_wtf16.slice (fx () ()))
  424. ('string.as_iter (fx () ()))
  425. ('stringview_iter.next (fx () ()))
  426. ('stringview_iter.advance (fx () ()))
  427. ('stringview_iter.rewind (fx () ()))
  428. ('stringview_iter.slice (fx () ()))
  429. ((or 'string.new_utf8_array
  430. 'string.new_lossy_utf8_array
  431. 'string.new_wtf8_array) (fx ((array 'i8)) ()))
  432. ('string.new_wtf16_array (fx ((array 'i16)) ()))
  433. ((or 'string.encode_utf8_array
  434. 'string.encode_lossy_utf8_array
  435. 'string.encode_wtf8_array) (fx () ((array 'i8))))
  436. ('string.encode_wtf16_array (fx () ((array 'i16))))
  437. ;; Vector opcodes.
  438. ('i8x16.splat (fx () ()))
  439. ('i16x8.splat (fx () ()))
  440. ('i32x4.splat (fx () ()))
  441. ('i64x2.splat (fx () ()))
  442. ('f32x4.splat (fx () ()))
  443. ('f64x2.splat (fx () ()))
  444. ('data.drop (fx! () ()))
  445. ('elem.drop (fx! () ()))
  446. (_ (error "unhandled instruction" inst))))))