stack.scm 31 KB

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