stack.scm 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877
  1. ;;; Stack effects for instruction validation
  2. ;;; Copyright (C) 2023, 2024 Igalia, S.L.
  3. ;;; Copyright (C) 2023 David Thompson <dave@spritely.institute>
  4. ;;;
  5. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  6. ;;; you may not use this file except in compliance with the License.
  7. ;;; You may obtain a copy of the License at
  8. ;;;
  9. ;;; http://www.apache.org/licenses/LICENSE-2.0
  10. ;;;
  11. ;;; Unless required by applicable law or agreed to in writing, software
  12. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  13. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. ;;; See the License for the specific language governing permissions and
  15. ;;; limitations under the License.
  16. ;;; Commentary:
  17. ;;;
  18. ;;; Computes and applies stack effects for individual instructions for
  19. ;;; the purposes of validation.
  20. ;;;
  21. ;;; Code:
  22. (define-module (wasm stack)
  23. #:use-module (ice-9 match)
  24. #:use-module ((srfi srfi-1) #:select (append-map filter-map))
  25. #:use-module (srfi srfi-9)
  26. #:use-module (wasm canonical-types)
  27. #:use-module (wasm types)
  28. #:export (<ctx>
  29. ctx?
  30. ctx-func-info
  31. ctx-block
  32. ctx-stack
  33. <unreachable-ctx>
  34. unreachable-ctx?
  35. unreachable-ctx-block
  36. unreachable-ctx-stack
  37. <invalid-ctx>
  38. invalid-ctx?
  39. invalid-ctx-reason
  40. <block>
  41. block?
  42. block-id
  43. block-type
  44. block-branch-arg-types
  45. block-result-types
  46. block-parent
  47. <stack-effect>
  48. stack-effect?
  49. stack-effect-params
  50. stack-effect-results
  51. stack-effect-block-end?
  52. initial-ctx
  53. push-block
  54. lookup-block
  55. lookup-tag
  56. compute-stack-effect
  57. apply-stack-effect
  58. fallthrough-stack-effect
  59. fallthrough))
  60. (define-record-type <func-info>
  61. (%make-func-info types funcs globals tables tags locals)
  62. func-info?
  63. (types func-info-types)
  64. (funcs func-info-funcs)
  65. (globals func-info-globals)
  66. (tables func-info-tables)
  67. (tags func-info-tags)
  68. (locals func-info-locals))
  69. (define-record-type <ctx>
  70. (make-ctx func-info block stack)
  71. ctx?
  72. (func-info ctx-func-info)
  73. (block ctx-block)
  74. (stack ctx-stack))
  75. (define-record-type <unreachable-ctx>
  76. (make-unreachable-ctx func-info block stack)
  77. unreachable-ctx?
  78. (func-info unreachable-ctx-func-info)
  79. (block unreachable-ctx-block)
  80. (stack unreachable-ctx-stack))
  81. (define-record-type <invalid-ctx>
  82. (make-invalid-ctx reason)
  83. invalid-ctx?
  84. (reason invalid-ctx-reason))
  85. (define-record-type <block>
  86. (make-block id type branch-arg-types result-types parent)
  87. block?
  88. (id block-id)
  89. (type block-type) ; 'block', 'loop', 'try', 'catch', etc.
  90. ;; If you jump to this block's label, what types do you pass? Usually
  91. ;; the block results, but for loops it's the loop parameters.
  92. (branch-arg-types block-branch-arg-types)
  93. ;; When control falls through the end of a block, what types must be
  94. ;; on the stack?
  95. (result-types block-result-types)
  96. (parent block-parent))
  97. (define-record-type <stack-effect>
  98. (make-stack-effect params results block-end?)
  99. stack-effect?
  100. (params stack-effect-params)
  101. ;; Results can be #f if the effect causes an exit.
  102. (results stack-effect-results)
  103. ;; The stack at the end of a block is expected to contain the param
  104. ;; types and nothing else below them.
  105. (block-end? stack-effect-block-end?))
  106. (define (make-func-info wasm func)
  107. (define types
  108. (list->vector
  109. (map (match-lambda
  110. (($ <type> id type)
  111. (cons id type)))
  112. (canonicalize-types! (wasm-types wasm)))))
  113. (define (select-imports kind)
  114. (filter-map (lambda (import)
  115. (and (eq? (import-kind import) kind)
  116. (cons (import-id import) (import-type import))))
  117. (wasm-imports wasm)))
  118. (define funcs
  119. (list->vector
  120. (append (select-imports 'func)
  121. (map (lambda (def)
  122. (cons (func-id def) (func-type def)))
  123. (wasm-funcs wasm)))))
  124. (define globals
  125. (list->vector
  126. (append (select-imports 'global)
  127. (map (lambda (def)
  128. (cons (global-id def) (global-type def)))
  129. (wasm-globals wasm)))))
  130. (define tables
  131. (list->vector
  132. (append (select-imports 'table)
  133. (map (lambda (def)
  134. (cons (table-id def) (table-type def)))
  135. (wasm-tables wasm)))))
  136. (define tags
  137. (list->vector
  138. (append (select-imports 'tag)
  139. (map (lambda (def)
  140. (cons (tag-id def) (tag-type def)))
  141. (wasm-tags wasm)))))
  142. (define locals
  143. (match func
  144. (($ <func>
  145. id
  146. ($ <type-use>
  147. _
  148. ($ <func-sig>
  149. (($ <param> param-id param-type) ...)
  150. (result-type ...)))
  151. (($ <local> local-id local-type) ...)
  152. body)
  153. (list->vector
  154. (append (map cons param-id param-type)
  155. (map cons local-id local-type))))))
  156. (%make-func-info types funcs globals tables tags locals))
  157. (define (initial-ctx module func)
  158. (match func
  159. (($ <func> _ ($ <type-use> _ ($ <func-sig> _ results)))
  160. (make-ctx (make-func-info module func)
  161. (make-block 'func #f results results #f)
  162. '()))))
  163. (define (push-block ctx id type param-types result-types)
  164. (match ctx
  165. (($ <ctx> info block _)
  166. (let ((branch-arg-types (if (eq? type 'loop) param-types result-types)))
  167. (make-ctx info
  168. (make-block id type branch-arg-types result-types block)
  169. (reverse param-types))))))
  170. (define (peek ctx)
  171. (match ctx
  172. ((or ($ <ctx> _ _ stack)
  173. ($ <unreachable-ctx> _ _ stack))
  174. (match stack
  175. ((top . stack) top)
  176. (() #f)))
  177. (($ <invalid-ctx>) #f)))
  178. (define (vector-assq v k)
  179. (let lp ((i 0))
  180. (and (< i (vector-length v))
  181. (let ((pair (vector-ref v i)))
  182. (if (eq? k (car pair))
  183. pair
  184. (lp (1+ i)))))))
  185. (define (vector-lookup v k)
  186. (if (integer? k)
  187. (vector-ref v k)
  188. (vector-assq v k)))
  189. (define (ctx-info-lookup ctx getter def)
  190. (match ctx
  191. (($ <ctx> info)
  192. (cdr (vector-lookup (getter info) def)))
  193. (($ <unreachable-ctx> info)
  194. (cdr (vector-lookup (getter info) def)))))
  195. (define (lookup-type ctx def)
  196. (ctx-info-lookup ctx func-info-types def))
  197. (define (lookup-func-type-use ctx def)
  198. (ctx-info-lookup ctx func-info-funcs def))
  199. (define (lookup-global ctx def)
  200. (ctx-info-lookup ctx func-info-globals def))
  201. (define (lookup-table ctx def)
  202. (ctx-info-lookup ctx func-info-tables def))
  203. (define (lookup-tag ctx def)
  204. (ctx-info-lookup ctx func-info-tags def))
  205. (define (lookup-local ctx def)
  206. (ctx-info-lookup ctx func-info-locals def))
  207. (define (lookup-func-sig ctx def)
  208. (match (lookup-type ctx def)
  209. (($ <sub-type> _ _ (and sig ($ <func-sig>))) sig)
  210. ((and sig ($ <func-sig>)) sig)
  211. (x (error "unexpected type" def x))))
  212. (define (lookup-struct-fields ctx def)
  213. (match (lookup-type ctx def)
  214. (($ <sub-type> _ _ ($ <struct-type> fields)) fields)
  215. (($ <struct-type> fields) fields)))
  216. (define (lookup-struct-field-types ctx struct-type)
  217. (map field-type (lookup-struct-fields ctx struct-type)))
  218. (define (lookup-struct-field-type ctx struct-type field)
  219. (match (lookup-struct-fields ctx struct-type)
  220. ((($ <field> id mutable? type) ...)
  221. (vector-lookup (list->vector type) field))))
  222. (define (lookup-array-type ctx def)
  223. (match (lookup-type ctx def)
  224. (($ <sub-type> _ _ ($ <array-type> mutable? type)) type)
  225. (($ <array-type> mutable? type) type)))
  226. (define (lookup-return-type ctx)
  227. (let lp ((block (ctx-block ctx)))
  228. (cond
  229. ((block-parent block) => lp)
  230. (else (block-branch-arg-types block)))))
  231. (define (lookup-block ctx target)
  232. (match ctx
  233. ((or ($ <ctx> _ block) ($ <unreachable-ctx> _ block))
  234. (if (integer? target)
  235. (let lp ((block block) (target target))
  236. (match block
  237. (($ <block> id _ _ _ parent)
  238. (if (zero? target)
  239. block
  240. (lp parent (1- target))))))
  241. (let lp ((block block))
  242. (match block
  243. (($ <block> id _ _ _ parent)
  244. (if (eq? target id)
  245. block
  246. (lp parent)))))))))
  247. (define $i8-array (canonicalize-type! (make-array-type #t 'i8)))
  248. (define $i16-array (canonicalize-type! (make-array-type #t 'i16)))
  249. (define (compute-stack-effect ctx inst)
  250. (define (-> params results)
  251. (make-stack-effect params results #f))
  252. (define (branch-arg-types target)
  253. (block-branch-arg-types (lookup-block ctx target)))
  254. (define (block-stack-effect type)
  255. (match type
  256. (#f (-> '() '()))
  257. ;; Lookup signature by index in func info.
  258. ((? exact-integer? idx)
  259. (match ctx
  260. ((or ($ <ctx> ($ <func-info> types))
  261. ($ <unreachable-ctx> ($ <func-info> types)))
  262. (match (vector-ref types idx)
  263. ((_ . ($ <func-sig> (($ <param> _ params) ...) results))
  264. (-> params results))))))
  265. (($ <type-use> _
  266. ($ <func-sig> (($ <param> _ params) ...) results))
  267. (-> params results))
  268. ((or (? symbol?) ($ <ref-type>))
  269. (-> '() (list type)))))
  270. (define (global-type global)
  271. (match (lookup-global ctx global)
  272. (($ <global-type> mutable? type) type)))
  273. (define (table-type def)
  274. (match (lookup-table ctx def)
  275. (($ <table-type> limits elem-type) elem-type)))
  276. (match inst
  277. ((op . args)
  278. (match op
  279. ('unreachable (-> '() #f))
  280. ('nop (-> '() '()))
  281. ((or 'block 'loop 'try 'try_delegate)
  282. (match args
  283. ((label type . _)
  284. (block-stack-effect type))))
  285. ('if
  286. (match args
  287. ((label type _ _)
  288. (match (block-stack-effect type)
  289. (($ <stack-effect> params results)
  290. (-> (append params '(i32)) results))))))
  291. ('throw
  292. (match args
  293. ((tag)
  294. (match (lookup-tag ctx tag)
  295. (($ <tag-type>
  296. _ ($ <type-use>
  297. _ ($ <func-sig> (($ <param> _ type) ...))))
  298. (-> type #f))))))
  299. ('rethrow
  300. (-> '() #f))
  301. ('br
  302. (match args
  303. ((target)
  304. (-> (branch-arg-types target) #f))))
  305. ('br_if
  306. (match args
  307. ((target)
  308. (let ((types (branch-arg-types target)))
  309. (-> (append types '(i32)) types)))))
  310. ('br_table
  311. (match args
  312. ((_ target)
  313. (-> (append (branch-arg-types target) '(i32)) #f))))
  314. ('return
  315. (-> (lookup-return-type ctx) #f))
  316. ('call
  317. (match args
  318. ((callee)
  319. (match (lookup-func-type-use ctx callee)
  320. (($ <type-use> _
  321. ($ <func-sig> (($ <param> id type) ...) results))
  322. (-> type results))))))
  323. ('call_indirect
  324. (match args
  325. ((table type)
  326. (match (lookup-func-sig ctx type)
  327. (($ <func-sig> (($ <param> id type) ...) results)
  328. (-> (append type '(i32)) results))))))
  329. ('return_call
  330. (match args
  331. ((callee)
  332. (match (lookup-func-type-use ctx callee)
  333. (($ <type-use> _
  334. ($ <func-sig> (($ <param> id type) ...) results))
  335. (-> type #f))))))
  336. ('return_call_indirect
  337. (match args
  338. ((type)
  339. (match (lookup-func-sig ctx type)
  340. (($ <func-sig> (($ <param> id type) ...) results)
  341. (-> (append type '(i32)) #f))))))
  342. ('call_ref
  343. (match args
  344. ((type)
  345. (match (lookup-func-sig ctx type)
  346. (($ <func-sig> (($ <param> id params) ...) results)
  347. (-> (append params (list (make-ref-type #t type))) results))))))
  348. ('return_call_ref
  349. (match args
  350. ((type)
  351. (match (lookup-func-sig ctx type)
  352. (($ <func-sig> (($ <param> id params) ...) results)
  353. (-> (append params (list (make-ref-type #t type))) #f))))))
  354. ('drop (-> (list (peek ctx)) '()))
  355. ('select (match args
  356. (()
  357. (let ((top (peek ctx)))
  358. (-> (list top top 'i32) (list top))))
  359. ((type ...)
  360. (-> (append type type '(i32)) type))))
  361. ('local.get (match args
  362. ((local)
  363. (let ((type (lookup-local ctx local)))
  364. (-> '() (list type))))))
  365. ('local.set (match args
  366. ((local)
  367. (let ((type (lookup-local ctx local)))
  368. (-> (list type) '())))))
  369. ('local.tee (match args
  370. ((local)
  371. (let ((type (lookup-local ctx local)))
  372. (-> (list type) (list type))))))
  373. ('global.get (match args
  374. ((global)
  375. (-> '() (list (global-type global))))))
  376. ('global.set (match args
  377. ((global)
  378. (-> (list (global-type global)) '()))))
  379. ('table.get (match args
  380. ((table)
  381. (-> '(i32) (list (table-type table))))))
  382. ('table.set (match args
  383. ((table)
  384. (-> (list 'i32 (table-type table)) '()))))
  385. ('table.size (-> '() '(i32)))
  386. ('table.init (-> '(i32 i32 i32) '()))
  387. ('table.copy (-> '(i32 i32 i32) '()))
  388. ('table.fill (match args
  389. ((table)
  390. (-> (list 'i32 (table-type table) 'i32) '()))))
  391. ('table.grow (match args
  392. ((table)
  393. (-> (list (table-type table) 'i32) '(i32)))))
  394. ('elem.drop (-> '() '()))
  395. ('memory.size (-> '() '(i32)))
  396. ('memory.grow (-> '(i32) '(i32)))
  397. ('memory.fill (-> '(i32 i32 i32) '()))
  398. ('memory.copy (-> '(i32 i32 i32) '()))
  399. ('memory.init (-> '(i32 i32 i32) '()))
  400. ('data.drop (-> '() '()))
  401. ('i32.const (-> '() '(i32)))
  402. ('i64.const (-> '() '(i64)))
  403. ('f32.const (-> '() '(f32)))
  404. ('f64.const (-> '() '(f64)))
  405. ((or 'i32.load
  406. 'i32.load8_s 'i32.load8_u 'i32.load16_s 'i32.load16_u)
  407. (-> '(i32) '(i32)))
  408. ((or 'i64.load
  409. 'i64.load8_s 'i64.load8_u 'i64.load16_s 'i64.load16_u
  410. 'i64.load32_s 'i64.load32_u)
  411. (-> '(i32) '(i64)))
  412. ('f32.load (-> '(i32) '(f32)))
  413. ('f64.load (-> '(i32) '(f64)))
  414. ((or 'i32.store 'i32.store8 'i32.store16)
  415. (-> '(i32 i32) '()))
  416. ((or 'i64.store 'i64.store8 'i64.store16 'i64.store32)
  417. (-> '(i32 i64) '()))
  418. ('f32.store (-> '(i32 f32) '()))
  419. ('f64.store (-> '(i32 f64) '()))
  420. ('i32.eqz (-> '(i32) '(i32)))
  421. ((or 'i32.eq 'i32.ne 'i32.lt_s 'i32.lt_u 'i32.gt_s
  422. 'i32.gt_u 'i32.le_s 'i32.le_u 'i32.ge_s 'i32.ge_u)
  423. (-> '(i32 i32) '(i32)))
  424. ('i64.eqz (-> '(i64) '(i32)))
  425. ((or 'i64.eq 'i64.ne 'i64.lt_s 'i64.lt_u 'i64.gt_s
  426. 'i64.gt_u 'i64.le_s 'i64.le_u 'i64.ge_s 'i64.ge_u)
  427. (-> '(i64 i64) '(i32)))
  428. ((or 'f32.eq 'f32.ne 'f32.lt 'f32.gt 'f32.le 'f32.ge)
  429. (-> '(f32 f32) '(i32)))
  430. ((or 'f64.eq 'f64.ne 'f64.lt 'f64.gt 'f64.le 'f64.ge)
  431. (-> '(f64 f64) '(i32)))
  432. ((or 'i32.clz 'i32.ctz 'i32.popcnt
  433. 'i32.extend8_s 'i32.extend16_s)
  434. (-> '(i32) '(i32)))
  435. ((or 'i32.add 'i32.sub 'i32.mul 'i32.div_s 'i32.div_u
  436. 'i32.rem_s 'i32.rem_u
  437. 'i32.and 'i32.or 'i32.xor 'i32.shl 'i32.shr_s 'i32.shr_u
  438. 'i32.rotl 'i32.rotr)
  439. (-> '(i32 i32) '(i32)))
  440. ('i32.wrap_i64
  441. (-> '(i64) '(i32)))
  442. ((or 'i32.trunc_f32_s 'i32.trunc_f32_u
  443. 'i32.trunc_sat_f32_s 'i32.trunc_sat_f32_u
  444. 'i32.reinterpret_f32)
  445. (-> '(f32) '(i32)))
  446. ((or 'i32.trunc_f64_s 'i32.trunc_f64_u
  447. 'i32.trunc_sat_f64_s 'i32.trunc_sat_f64_u)
  448. (-> '(f64) '(i32)))
  449. ((or 'i64.clz 'i64.ctz 'i64.popcnt
  450. 'i64.extend8_s 'i64.extend16_s 'i64.extend32_s)
  451. (-> '(i64) '(i64)))
  452. ((or 'i64.add 'i64.sub 'i64.mul 'i64.div_s 'i64.div_u
  453. 'i64.rem_s 'i64.rem_u
  454. 'i64.and 'i64.or 'i64.xor 'i64.shl 'i64.shr_s 'i64.shr_u
  455. 'i64.rotl 'i64.rotr)
  456. (-> '(i64 i64) '(i64)))
  457. ((or 'i64.extend_i32_s 'i64.extend_i32_u)
  458. (-> '(i32) '(i64)))
  459. ((or 'i64.trunc_f32_s 'i64.trunc_f32_u
  460. 'i64.trunc_sat_f32_s 'i64.trunc_sat_f32_u)
  461. (-> '(f32) '(i64)))
  462. ((or 'i64.trunc_f64_s 'i64.trunc_f64_u
  463. 'i64.trunc_sat_f64_s 'i64.trunc_sat_f64_u
  464. 'i64.reinterpret_f64)
  465. (-> '(f64) '(i64)))
  466. ((or 'f32.abs 'f32.neg 'f32.ceil 'f32.floor 'f32.trunc 'f32.nearest
  467. 'f32.sqrt)
  468. (-> '(f32) '(f32)))
  469. ((or 'f32.add 'f32.sub 'f32.mul 'f32.div 'f32.min 'f32.max
  470. 'f32.copysign)
  471. (-> '(f32 f32) '(f32)))
  472. ((or 'f32.convert_i32_s 'f32.convert_i32_u
  473. 'f32.reinterpret_i32)
  474. (-> '(i32) '(f32)))
  475. ((or 'f32.convert_i64_s 'f32.convert_i64_u)
  476. (-> '(i64) '(f32)))
  477. ('f32.demote_f64
  478. (-> '(f64) '(f32)))
  479. ((or 'f64.abs 'f64.neg 'f64.ceil 'f64.floor 'f64.trunc 'f64.nearest
  480. 'f64.sqrt)
  481. (-> '(f64) '(f64)))
  482. ((or 'f64.add 'f64.sub 'f64.mul 'f64.div 'f64.min 'f64.max
  483. 'f64.copysign)
  484. (-> '(f64 f64) '(f64)))
  485. ((or 'f64.convert_i32_s 'f64.convert_i32_u)
  486. (-> '(i32) '(f64)))
  487. ((or 'f64.convert_i64_s 'f64.convert_i64_u
  488. 'f64.reinterpret_i64)
  489. (-> '(i64) '(f64)))
  490. ('f64.promote_f32
  491. (-> '(f32) '(f64)))
  492. ('ref.null
  493. (match args
  494. ((ht)
  495. (-> '() (list (make-ref-type #t ht))))))
  496. ((or 'ref.is_null 'ref.test)
  497. ;; FIXME: ref.is_null only valid on ref types
  498. ;; FIXME: ref.test only valid if tested type matches top
  499. (-> (list (peek ctx)) '(i32)))
  500. ('ref.eq
  501. (-> (list (make-ref-type #t 'eq) (make-ref-type #t 'eq)) '(i32)))
  502. ('ref.func
  503. (match args
  504. ((callee)
  505. (match (lookup-func-type-use ctx callee)
  506. (($ <type-use> id sig)
  507. (-> '() (list (make-ref-type #f id))))))))
  508. ('ref.as_non_null
  509. (match (peek ctx)
  510. ((and top ($ <ref-type> nullable? ht))
  511. (-> (list top)
  512. (list (make-ref-type #f ht))))))
  513. ('ref.cast
  514. (match args
  515. ((($ <ref-type> nullable? ht))
  516. (match (peek ctx)
  517. ((and top ($ <ref-type> nullable?* ht*))
  518. ;; FIXME: assert that (nullable?,ht) <= (nullable?*,ht*)
  519. (-> (list top) (list (make-ref-type nullable? ht))))))))
  520. ((or 'br_on_cast 'br_on_cast_fail)
  521. (match args
  522. ((target rt1 rt2)
  523. ;; FIXME: assert that last type is rt1.
  524. (match (branch-arg-types target)
  525. ((and types (first ... last))
  526. (-> types
  527. (append first (list (if (eq? op 'br_on_cast) rt1 rt2)))))))))
  528. ('struct.get
  529. (match args
  530. ((ht field)
  531. (-> (list (make-ref-type #t ht))
  532. (list (lookup-struct-field-type ctx ht field))))))
  533. ((or 'struct.get_s 'struct.get_u)
  534. (match args
  535. ((ht field)
  536. (-> (list (make-ref-type #t ht)) '(i32)))))
  537. ('struct.set
  538. (match args
  539. ((ht field)
  540. (-> (list (make-ref-type #t ht)
  541. (lookup-struct-field-type ctx ht field))
  542. '()))))
  543. ('struct.new
  544. (match args
  545. ((ht)
  546. (-> (lookup-struct-field-types ctx ht)
  547. (list (make-ref-type #f ht))))))
  548. ('struct.new_default
  549. (match args
  550. ((ht)
  551. (-> '() (list (make-ref-type #f ht))))))
  552. ('array.get
  553. (match args
  554. ((ht)
  555. (-> (list (make-ref-type #t ht) 'i32)
  556. (list (lookup-array-type ctx ht))))))
  557. ((or 'array.get_s 'array.get_u)
  558. (match args
  559. ((ht)
  560. (-> (list (make-ref-type #t ht) 'i32) '(i32)))))
  561. ('array.set
  562. (match args
  563. ((ht)
  564. (-> (list (make-ref-type #t ht) 'i32 (lookup-array-type ctx ht))
  565. '()))))
  566. ('array.fill
  567. (match args
  568. ((ht)
  569. (-> (list (make-ref-type #t ht) 'i32 (lookup-array-type ctx ht) 'i32)
  570. '()))))
  571. ('array.copy
  572. (match args
  573. ((ht1 ht2)
  574. (-> (list (make-ref-type #t ht1) 'i32
  575. (make-ref-type #t ht2) 'i32 'i32)
  576. '()))))
  577. ('array.len
  578. (-> (list (make-ref-type #t 'array)) '(i32)))
  579. ('array.new
  580. (match args
  581. ((ht)
  582. (-> (list (lookup-array-type ctx ht) 'i32)
  583. (list (make-ref-type #f ht))))))
  584. ('array.new_fixed
  585. (match args
  586. ((ht len)
  587. (-> (make-list len (lookup-array-type ctx ht))
  588. (list (make-ref-type #f ht))))))
  589. ('array.new_default
  590. (match args
  591. ((ht)
  592. (-> '(i32) (list (make-ref-type #f ht))))))
  593. ((or 'array.new_data 'array.new_elem)
  594. (match args
  595. ((ht idx)
  596. (-> '(i32 i32) (list (make-ref-type #f ht))))))
  597. ((or 'array.init_data 'array.init_elem)
  598. (match args
  599. ((ht idx)
  600. (-> (list (make-ref-type #t ht) 'i32 'i32 'i32) '()))))
  601. ('ref.i31
  602. (-> '(i32) (list (make-ref-type #f 'i31))))
  603. ((or 'i31.get_s 'i31.get_u)
  604. (-> (list (make-ref-type #f 'i31)) '(i32)))
  605. ('extern.internalize
  606. (match (peek ctx)
  607. (($ <ref-type> nullable? _)
  608. (-> (list (make-ref-type nullable? 'extern))
  609. (list (make-ref-type nullable? 'any))))))
  610. ('extern.externalize
  611. (match (peek ctx)
  612. (($ <ref-type> nullable? _)
  613. (-> (list (make-ref-type nullable? 'any))
  614. (list (make-ref-type nullable? 'extern))))))
  615. ((or 'string.new_utf8 'string.new_lossy_utf8 'string.new_wtf8
  616. 'string.new_wtf16)
  617. (-> '(i32 i32)
  618. (list (make-ref-type #f 'string))))
  619. ((or 'string.new_utf8_array 'string.new_lossy_utf8_array
  620. 'string.new_wtf8_array)
  621. (-> (list (make-ref-type #t $i8-array) 'i32 'i32)
  622. (list (make-ref-type #f 'string))))
  623. ((or 'string.new_wtf16_array)
  624. (-> (list (make-ref-type #t $i16-array) 'i32 'i32)
  625. (list (make-ref-type #f 'string))))
  626. ((or 'string.measure_utf8 'string.measure_wtf8
  627. 'string.measure_wtf16)
  628. (-> (list (make-ref-type #t 'string))
  629. '(i32)))
  630. ((or 'string.encode_utf8 'string.encode_lossy_utf8 'string.encode_wtf8
  631. 'string.encode_wtf16)
  632. (-> (list (make-ref-type #t 'string) 'i32)
  633. '(i32)))
  634. ((or 'string.encode_utf8_array 'string.encode_lossy_utf8_array
  635. 'string.encode_wtf8_array)
  636. (-> (list (make-ref-type #t 'string)
  637. (make-ref-type #t $i8-array)
  638. 'i32)
  639. '(i32)))
  640. ('string.encode_wtf16_array
  641. (-> (list (make-ref-type #t 'string)
  642. (make-ref-type #t $i16-array)
  643. 'i32)
  644. '(i32)))
  645. ('string.const
  646. (-> '() (list (make-ref-type #f 'string))))
  647. ('string.concat
  648. (-> (list (make-ref-type #t 'string)
  649. (make-ref-type #t 'string))
  650. (list (make-ref-type #f 'string))))
  651. ((or 'string.eq 'string.compare)
  652. (-> (list (make-ref-type #t 'string)
  653. (make-ref-type #t 'string))
  654. '(i32)))
  655. ('string.is_usv_sequence
  656. (-> (list (make-ref-type #t 'string))
  657. '(i32)))
  658. ('string.from_code_point
  659. (-> (list 'i32)
  660. (list (make-ref-type #f 'string))))
  661. ('string.as_wtf8
  662. (-> (list (make-ref-type #t 'string))
  663. (list (make-ref-type #f 'stringview_wtf8))))
  664. ((or 'stringview_wtf8.encode_utf8
  665. 'stringview_wtf8.encode_lossy_utf8
  666. 'stringview_wtf8.encode_wtf8)
  667. (-> (list (make-ref-type #t 'stringview_wtf8)
  668. 'i32 'i32 'i32)
  669. '(i32 i32)))
  670. ('stringview_wtf8.advance
  671. (-> (list (make-ref-type #t 'stringview_wtf8)
  672. 'i32 'i32)
  673. '(i32)))
  674. ('stringview_wtf8.slice
  675. (-> (list (make-ref-type #t 'stringview_wtf8)
  676. 'i32 'i32)
  677. (list (make-ref-type #f 'string))))
  678. ('string.as_wtf16
  679. (-> (list (make-ref-type #t 'string))
  680. (list (make-ref-type #f 'stringview_wtf16))))
  681. ('stringview_wtf16.length
  682. (-> (list (make-ref-type #t 'stringview_wtf16))
  683. '(i32)))
  684. ('stringview_wtf16.get_codeunit
  685. (-> (list (make-ref-type #t 'stringview_wtf16) 'i32)
  686. '(i32)))
  687. ('stringview_wtf16.encode
  688. (-> (list (make-ref-type #t 'stringview_wtf16) 'i32 'i32 'i32)
  689. '(i32)))
  690. ('stringview_wtf16.slice
  691. (-> (list (make-ref-type #t 'stringview_wtf16)
  692. 'i32 'i32)
  693. (list (make-ref-type #f 'string))))
  694. ('string.as_iter
  695. (-> (list (make-ref-type #t 'string))
  696. (list (make-ref-type #f 'stringview_iter))))
  697. ('stringview_iter.next
  698. (-> (list (make-ref-type #t 'stringview_iter))
  699. '(i32)))
  700. ((or 'stringview_iter.advance 'stringview_iter.rewind)
  701. (-> (list (make-ref-type #t 'stringview_iter) 'i32)
  702. '(i32)))
  703. ('stringview_iter.slice
  704. (-> (list (make-ref-type #t 'stringview_iter)
  705. 'i32)
  706. (list (make-ref-type #f 'string))))
  707. ((or 'i8x16.splat 'i16x8.splat 'i32x4.splat)
  708. (-> '(i32) '(i128)))
  709. ('i64x2.splat (-> '(i64) '(i128)))
  710. ('f32x4.splat (-> '(f32) '(i128)))
  711. ('f64x2.splat (-> '(f64) '(i128)))
  712. (_ (error "unhandled instruction" op))))))
  713. (define (apply-stack-effect ctx effect)
  714. (define (resolve-type x)
  715. (match x
  716. ((? promise?) (force x))
  717. ((? exact-integer?) (lookup-type ctx x))
  718. (_ x)))
  719. (define (heap-type-sub-type? sub super)
  720. (let ((sub (resolve-type sub))
  721. (super (resolve-type super)))
  722. (or (eq? sub super)
  723. (let lp ((sub sub))
  724. (match sub
  725. ('any (eq? super 'any))
  726. ('i31 (memq super '(i31 eq any)))
  727. ('eq (memq super '(eq any)))
  728. (($ <sub-type> _ ((= resolve-type supers) ...) (= resolve-type type))
  729. (or (and supers (memq super supers))
  730. (lp type)))
  731. (($ <array-type> mutable? type)
  732. (memq super '(array eq any)))
  733. (($ <struct-type>)
  734. (memq super '(struct eq any)))
  735. (($ <func-sig>)
  736. (eq? super 'func)))))))
  737. (define (is-subtype? sub super)
  738. (cond
  739. ((eq? sub super) #t)
  740. ((and (eq? sub 'i32) (memq super '(i32 i16 i8))) #t)
  741. ((and (ref-type? sub) (ref-type? super))
  742. (and (or (ref-type-nullable? super)
  743. (not (ref-type-nullable? sub)))
  744. (heap-type-sub-type? (ref-type-heap-type sub)
  745. (ref-type-heap-type super))))
  746. ;; The funcref type works for any function reference.
  747. ((and (eq? super 'funcref) (ref-type? sub)
  748. (heap-type-sub-type? (ref-type-heap-type sub) 'func))
  749. #t)
  750. (else #f)))
  751. (match ctx
  752. (($ <invalid-ctx>) ctx)
  753. (($ <unreachable-ctx> info block stack)
  754. (match effect
  755. (($ <stack-effect> params results block-end?)
  756. (let lp ((params (reverse params)) (stack stack))
  757. (match params
  758. ((param . params)
  759. (match stack
  760. ;; The bottom of the unreachable stack is treated as a
  761. ;; polymorphic stack that contains any type, so there
  762. ;; is no reason to continue type checking.
  763. (()
  764. (lp '() '()))
  765. ;; Peeking at the unreachable stack may return #f,
  766. ;; which can stand in for any type.
  767. ((#f . stack)
  768. (lp params stack))
  769. ;; A proper type is on top of the stack, type checking
  770. ;; happens the same as in <ctx>.
  771. ((top . stack)
  772. (if (is-subtype? top param)
  773. (lp params stack)
  774. (make-invalid-ctx
  775. (format #f "expected ~a, got ~a" param top))))))
  776. (()
  777. (if (and block-end? (not (null? stack)))
  778. (make-invalid-ctx
  779. (format #f "extra values on stack at block end ~a" stack))
  780. (match results
  781. (#f (make-unreachable-ctx info block '()))
  782. ((result ...)
  783. (make-unreachable-ctx info block (append (reverse result) stack)))))))))))
  784. (($ <ctx> info block stack)
  785. (match effect
  786. (($ <stack-effect> params results block-end?)
  787. (let lp ((params (reverse params)) (stack stack))
  788. (match params
  789. ((param . params)
  790. (match stack
  791. (()
  792. (make-invalid-ctx
  793. (format #f "expected ~a, got empty stack" param)))
  794. ((top . stack)
  795. (if (is-subtype? top param)
  796. (lp params stack)
  797. ;; FIXME: more info here.
  798. (make-invalid-ctx
  799. (format #f "expected ~a, got ~a" param top))))))
  800. (()
  801. (if (and block-end? (not (null? stack)))
  802. (make-invalid-ctx
  803. (format #f "extra values on stack at block end ~a" stack))
  804. (match results
  805. (#f (make-unreachable-ctx info block '()))
  806. ((result ...)
  807. (make-ctx info block (append (reverse result) stack)))))))))))))
  808. (define (fallthrough-stack-effect ctx)
  809. (let ((types
  810. (match ctx
  811. (($ <unreachable-ctx> _ ($ <block> _ _ _ types)) types)
  812. (($ <ctx> _ ($ <block> _ _ _ types)) types))))
  813. (make-stack-effect types #f #t)))
  814. (define (fallthrough ctx)
  815. (apply-stack-effect ctx (fallthrough-stack-effect ctx)))