stack.scm 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888
  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 (ref-type-difference rt1 rt2)
  250. (match rt1
  251. (($ <ref-type> nullable1? ht1)
  252. (match rt2
  253. (($ <ref-type> nullable2? ht2)
  254. (if nullable2?
  255. (make-ref-type #f ht1)
  256. (make-ref-type nullable1? ht1)))))))
  257. (define (compute-stack-effect ctx inst)
  258. (define (-> params results)
  259. (make-stack-effect params results #f))
  260. (define (branch-arg-types target)
  261. (block-branch-arg-types (lookup-block ctx target)))
  262. (define (block-stack-effect type)
  263. (match type
  264. (#f (-> '() '()))
  265. ;; Lookup signature by index in func info.
  266. ((? exact-integer? idx)
  267. (match ctx
  268. ((or ($ <ctx> ($ <func-info> types))
  269. ($ <unreachable-ctx> ($ <func-info> types)))
  270. (match (vector-ref types idx)
  271. ((_ . ($ <func-sig> (($ <param> _ params) ...) results))
  272. (-> params results))))))
  273. (($ <type-use> _
  274. ($ <func-sig> (($ <param> _ params) ...) results))
  275. (-> params results))
  276. ((or (? symbol?) ($ <ref-type>))
  277. (-> '() (list type)))))
  278. (define (global-type global)
  279. (match (lookup-global ctx global)
  280. (($ <global-type> mutable? type) type)))
  281. (define (table-type def)
  282. (match (lookup-table ctx def)
  283. (($ <table-type> limits elem-type) elem-type)))
  284. (match inst
  285. ((op . args)
  286. (match op
  287. ('unreachable (-> '() #f))
  288. ('nop (-> '() '()))
  289. ((or 'block 'loop 'try 'try_delegate)
  290. (match args
  291. ((label type . _)
  292. (block-stack-effect type))))
  293. ('if
  294. (match args
  295. ((label type _ _)
  296. (match (block-stack-effect type)
  297. (($ <stack-effect> params results)
  298. (-> (append params '(i32)) results))))))
  299. ('throw
  300. (match args
  301. ((tag)
  302. (match (lookup-tag ctx tag)
  303. (($ <tag-type>
  304. _ ($ <type-use>
  305. _ ($ <func-sig> (($ <param> _ type) ...))))
  306. (-> type #f))))))
  307. ('rethrow
  308. (-> '() #f))
  309. ('br
  310. (match args
  311. ((target)
  312. (-> (branch-arg-types target) #f))))
  313. ('br_if
  314. (match args
  315. ((target)
  316. (let ((types (branch-arg-types target)))
  317. (-> (append types '(i32)) types)))))
  318. ('br_table
  319. (match args
  320. ((_ target)
  321. (-> (append (branch-arg-types target) '(i32)) #f))))
  322. ('return
  323. (-> (lookup-return-type ctx) #f))
  324. ('call
  325. (match args
  326. ((callee)
  327. (match (lookup-func-type-use ctx callee)
  328. (($ <type-use> _
  329. ($ <func-sig> (($ <param> id type) ...) results))
  330. (-> type results))))))
  331. ('call_indirect
  332. (match args
  333. ((table type)
  334. (match (lookup-func-sig ctx type)
  335. (($ <func-sig> (($ <param> id type) ...) results)
  336. (-> (append type '(i32)) results))))))
  337. ('return_call
  338. (match args
  339. ((callee)
  340. (match (lookup-func-type-use ctx callee)
  341. (($ <type-use> _
  342. ($ <func-sig> (($ <param> id type) ...) results))
  343. (-> type #f))))))
  344. ('return_call_indirect
  345. (match args
  346. ((type)
  347. (match (lookup-func-sig ctx type)
  348. (($ <func-sig> (($ <param> id type) ...) results)
  349. (-> (append type '(i32)) #f))))))
  350. ('call_ref
  351. (match args
  352. ((type)
  353. (match (lookup-func-sig ctx type)
  354. (($ <func-sig> (($ <param> id params) ...) results)
  355. (-> (append params (list (make-ref-type #t type))) results))))))
  356. ('return_call_ref
  357. (match args
  358. ((type)
  359. (match (lookup-func-sig ctx type)
  360. (($ <func-sig> (($ <param> id params) ...) results)
  361. (-> (append params (list (make-ref-type #t type))) #f))))))
  362. ('drop (-> (list (peek ctx)) '()))
  363. ('select (match args
  364. (()
  365. (let ((top (peek ctx)))
  366. (-> (list top top 'i32) (list top))))
  367. ((type ...)
  368. (-> (append type type '(i32)) type))))
  369. ('local.get (match args
  370. ((local)
  371. (let ((type (lookup-local ctx local)))
  372. (-> '() (list type))))))
  373. ('local.set (match args
  374. ((local)
  375. (let ((type (lookup-local ctx local)))
  376. (-> (list type) '())))))
  377. ('local.tee (match args
  378. ((local)
  379. (let ((type (lookup-local ctx local)))
  380. (-> (list type) (list type))))))
  381. ('global.get (match args
  382. ((global)
  383. (-> '() (list (global-type global))))))
  384. ('global.set (match args
  385. ((global)
  386. (-> (list (global-type global)) '()))))
  387. ('table.get (match args
  388. ((table)
  389. (-> '(i32) (list (table-type table))))))
  390. ('table.set (match args
  391. ((table)
  392. (-> (list 'i32 (table-type table)) '()))))
  393. ('table.size (-> '() '(i32)))
  394. ('table.init (-> '(i32 i32 i32) '()))
  395. ('table.copy (-> '(i32 i32 i32) '()))
  396. ('table.fill (match args
  397. ((table)
  398. (-> (list 'i32 (table-type table) 'i32) '()))))
  399. ('table.grow (match args
  400. ((table)
  401. (-> (list (table-type table) 'i32) '(i32)))))
  402. ('elem.drop (-> '() '()))
  403. ('memory.size (-> '() '(i32)))
  404. ('memory.grow (-> '(i32) '(i32)))
  405. ('memory.fill (-> '(i32 i32 i32) '()))
  406. ('memory.copy (-> '(i32 i32 i32) '()))
  407. ('memory.init (-> '(i32 i32 i32) '()))
  408. ('data.drop (-> '() '()))
  409. ('i32.const (-> '() '(i32)))
  410. ('i64.const (-> '() '(i64)))
  411. ('f32.const (-> '() '(f32)))
  412. ('f64.const (-> '() '(f64)))
  413. ((or 'i32.load
  414. 'i32.load8_s 'i32.load8_u 'i32.load16_s 'i32.load16_u)
  415. (-> '(i32) '(i32)))
  416. ((or 'i64.load
  417. 'i64.load8_s 'i64.load8_u 'i64.load16_s 'i64.load16_u
  418. 'i64.load32_s 'i64.load32_u)
  419. (-> '(i32) '(i64)))
  420. ('f32.load (-> '(i32) '(f32)))
  421. ('f64.load (-> '(i32) '(f64)))
  422. ((or 'i32.store 'i32.store8 'i32.store16)
  423. (-> '(i32 i32) '()))
  424. ((or 'i64.store 'i64.store8 'i64.store16 'i64.store32)
  425. (-> '(i32 i64) '()))
  426. ('f32.store (-> '(i32 f32) '()))
  427. ('f64.store (-> '(i32 f64) '()))
  428. ('i32.eqz (-> '(i32) '(i32)))
  429. ((or 'i32.eq 'i32.ne 'i32.lt_s 'i32.lt_u 'i32.gt_s
  430. 'i32.gt_u 'i32.le_s 'i32.le_u 'i32.ge_s 'i32.ge_u)
  431. (-> '(i32 i32) '(i32)))
  432. ('i64.eqz (-> '(i64) '(i32)))
  433. ((or 'i64.eq 'i64.ne 'i64.lt_s 'i64.lt_u 'i64.gt_s
  434. 'i64.gt_u 'i64.le_s 'i64.le_u 'i64.ge_s 'i64.ge_u)
  435. (-> '(i64 i64) '(i32)))
  436. ((or 'f32.eq 'f32.ne 'f32.lt 'f32.gt 'f32.le 'f32.ge)
  437. (-> '(f32 f32) '(i32)))
  438. ((or 'f64.eq 'f64.ne 'f64.lt 'f64.gt 'f64.le 'f64.ge)
  439. (-> '(f64 f64) '(i32)))
  440. ((or 'i32.clz 'i32.ctz 'i32.popcnt
  441. 'i32.extend8_s 'i32.extend16_s)
  442. (-> '(i32) '(i32)))
  443. ((or 'i32.add 'i32.sub 'i32.mul 'i32.div_s 'i32.div_u
  444. 'i32.rem_s 'i32.rem_u
  445. 'i32.and 'i32.or 'i32.xor 'i32.shl 'i32.shr_s 'i32.shr_u
  446. 'i32.rotl 'i32.rotr)
  447. (-> '(i32 i32) '(i32)))
  448. ('i32.wrap_i64
  449. (-> '(i64) '(i32)))
  450. ((or 'i32.trunc_f32_s 'i32.trunc_f32_u
  451. 'i32.trunc_sat_f32_s 'i32.trunc_sat_f32_u
  452. 'i32.reinterpret_f32)
  453. (-> '(f32) '(i32)))
  454. ((or 'i32.trunc_f64_s 'i32.trunc_f64_u
  455. 'i32.trunc_sat_f64_s 'i32.trunc_sat_f64_u)
  456. (-> '(f64) '(i32)))
  457. ((or 'i64.clz 'i64.ctz 'i64.popcnt
  458. 'i64.extend8_s 'i64.extend16_s 'i64.extend32_s)
  459. (-> '(i64) '(i64)))
  460. ((or 'i64.add 'i64.sub 'i64.mul 'i64.div_s 'i64.div_u
  461. 'i64.rem_s 'i64.rem_u
  462. 'i64.and 'i64.or 'i64.xor 'i64.shl 'i64.shr_s 'i64.shr_u
  463. 'i64.rotl 'i64.rotr)
  464. (-> '(i64 i64) '(i64)))
  465. ((or 'i64.extend_i32_s 'i64.extend_i32_u)
  466. (-> '(i32) '(i64)))
  467. ((or 'i64.trunc_f32_s 'i64.trunc_f32_u
  468. 'i64.trunc_sat_f32_s 'i64.trunc_sat_f32_u)
  469. (-> '(f32) '(i64)))
  470. ((or 'i64.trunc_f64_s 'i64.trunc_f64_u
  471. 'i64.trunc_sat_f64_s 'i64.trunc_sat_f64_u
  472. 'i64.reinterpret_f64)
  473. (-> '(f64) '(i64)))
  474. ((or 'f32.abs 'f32.neg 'f32.ceil 'f32.floor 'f32.trunc 'f32.nearest
  475. 'f32.sqrt)
  476. (-> '(f32) '(f32)))
  477. ((or 'f32.add 'f32.sub 'f32.mul 'f32.div 'f32.min 'f32.max
  478. 'f32.copysign)
  479. (-> '(f32 f32) '(f32)))
  480. ((or 'f32.convert_i32_s 'f32.convert_i32_u
  481. 'f32.reinterpret_i32)
  482. (-> '(i32) '(f32)))
  483. ((or 'f32.convert_i64_s 'f32.convert_i64_u)
  484. (-> '(i64) '(f32)))
  485. ('f32.demote_f64
  486. (-> '(f64) '(f32)))
  487. ((or 'f64.abs 'f64.neg 'f64.ceil 'f64.floor 'f64.trunc 'f64.nearest
  488. 'f64.sqrt)
  489. (-> '(f64) '(f64)))
  490. ((or 'f64.add 'f64.sub 'f64.mul 'f64.div 'f64.min 'f64.max
  491. 'f64.copysign)
  492. (-> '(f64 f64) '(f64)))
  493. ((or 'f64.convert_i32_s 'f64.convert_i32_u)
  494. (-> '(i32) '(f64)))
  495. ((or 'f64.convert_i64_s 'f64.convert_i64_u
  496. 'f64.reinterpret_i64)
  497. (-> '(i64) '(f64)))
  498. ('f64.promote_f32
  499. (-> '(f32) '(f64)))
  500. ('ref.null
  501. (match args
  502. ((ht)
  503. (-> '() (list (make-ref-type #t ht))))))
  504. ((or 'ref.is_null 'ref.test)
  505. ;; FIXME: ref.is_null only valid on ref types
  506. ;; FIXME: ref.test only valid if tested type matches top
  507. (-> (list (peek ctx)) '(i32)))
  508. ('ref.eq
  509. (-> (list (make-ref-type #t 'eq) (make-ref-type #t 'eq)) '(i32)))
  510. ('ref.func
  511. (match args
  512. ((callee)
  513. (match (lookup-func-type-use ctx callee)
  514. (($ <type-use> id sig)
  515. (-> '() (list (make-ref-type #f id))))))))
  516. ('ref.as_non_null
  517. (match (peek ctx)
  518. ((and top ($ <ref-type> nullable? ht))
  519. (-> (list top)
  520. (list (make-ref-type #f ht))))))
  521. ('ref.cast
  522. (match args
  523. ((($ <ref-type> nullable? ht))
  524. (match (peek ctx)
  525. ((and top ($ <ref-type> nullable?* ht*))
  526. ;; FIXME: assert that (nullable?,ht) <= (nullable?*,ht*)
  527. (-> (list top) (list (make-ref-type nullable? ht))))))))
  528. ((or 'br_on_cast 'br_on_cast_fail)
  529. (match args
  530. ((target rt1 rt2)
  531. ;; FIXME: assert that last type is rt1.
  532. (match (branch-arg-types target)
  533. ((first ... last)
  534. (-> (append first (list rt1))
  535. (append first (list (if (eq? op 'br_on_cast)
  536. (ref-type-difference rt1 rt2)
  537. rt2)))))))))
  538. ('struct.get
  539. (match args
  540. ((ht field)
  541. (-> (list (make-ref-type #t ht))
  542. (list (lookup-struct-field-type ctx ht field))))))
  543. ((or 'struct.get_s 'struct.get_u)
  544. (match args
  545. ((ht field)
  546. (-> (list (make-ref-type #t ht)) '(i32)))))
  547. ('struct.set
  548. (match args
  549. ((ht field)
  550. (-> (list (make-ref-type #t ht)
  551. (lookup-struct-field-type ctx ht field))
  552. '()))))
  553. ('struct.new
  554. (match args
  555. ((ht)
  556. (-> (lookup-struct-field-types ctx ht)
  557. (list (make-ref-type #f ht))))))
  558. ('struct.new_default
  559. (match args
  560. ((ht)
  561. (-> '() (list (make-ref-type #f ht))))))
  562. ('array.get
  563. (match args
  564. ((ht)
  565. (-> (list (make-ref-type #t ht) 'i32)
  566. (list (lookup-array-type ctx ht))))))
  567. ((or 'array.get_s 'array.get_u)
  568. (match args
  569. ((ht)
  570. (-> (list (make-ref-type #t ht) 'i32) '(i32)))))
  571. ('array.set
  572. (match args
  573. ((ht)
  574. (-> (list (make-ref-type #t ht) 'i32 (lookup-array-type ctx ht))
  575. '()))))
  576. ('array.fill
  577. (match args
  578. ((ht)
  579. (-> (list (make-ref-type #t ht) 'i32 (lookup-array-type ctx ht) 'i32)
  580. '()))))
  581. ('array.copy
  582. (match args
  583. ((ht1 ht2)
  584. (-> (list (make-ref-type #t ht1) 'i32
  585. (make-ref-type #t ht2) 'i32 'i32)
  586. '()))))
  587. ('array.len
  588. (-> (list (make-ref-type #t 'array)) '(i32)))
  589. ('array.new
  590. (match args
  591. ((ht)
  592. (-> (list (lookup-array-type ctx ht) 'i32)
  593. (list (make-ref-type #f ht))))))
  594. ('array.new_fixed
  595. (match args
  596. ((ht len)
  597. (-> (make-list len (lookup-array-type ctx ht))
  598. (list (make-ref-type #f ht))))))
  599. ('array.new_default
  600. (match args
  601. ((ht)
  602. (-> '(i32) (list (make-ref-type #f ht))))))
  603. ((or 'array.new_data 'array.new_elem)
  604. (match args
  605. ((ht idx)
  606. (-> '(i32 i32) (list (make-ref-type #f ht))))))
  607. ((or 'array.init_data 'array.init_elem)
  608. (match args
  609. ((ht idx)
  610. (-> (list (make-ref-type #t ht) 'i32 'i32 'i32) '()))))
  611. ('ref.i31
  612. (-> '(i32) (list (make-ref-type #f 'i31))))
  613. ((or 'i31.get_s 'i31.get_u)
  614. (-> (list (make-ref-type #f 'i31)) '(i32)))
  615. ('extern.internalize
  616. (match (peek ctx)
  617. (($ <ref-type> nullable? _)
  618. (-> (list (make-ref-type nullable? 'extern))
  619. (list (make-ref-type nullable? 'any))))))
  620. ('extern.externalize
  621. (match (peek ctx)
  622. (($ <ref-type> nullable? _)
  623. (-> (list (make-ref-type nullable? 'any))
  624. (list (make-ref-type nullable? 'extern))))))
  625. ((or 'string.new_utf8 'string.new_lossy_utf8 'string.new_wtf8
  626. 'string.new_wtf16)
  627. (-> '(i32 i32)
  628. (list (make-ref-type #f 'string))))
  629. ((or 'string.new_utf8_array 'string.new_lossy_utf8_array
  630. 'string.new_wtf8_array)
  631. (-> (list (make-ref-type #t $i8-array) 'i32 'i32)
  632. (list (make-ref-type #f 'string))))
  633. ((or 'string.new_wtf16_array)
  634. (-> (list (make-ref-type #t $i16-array) 'i32 'i32)
  635. (list (make-ref-type #f 'string))))
  636. ((or 'string.measure_utf8 'string.measure_wtf8
  637. 'string.measure_wtf16)
  638. (-> (list (make-ref-type #t 'string))
  639. '(i32)))
  640. ((or 'string.encode_utf8 'string.encode_lossy_utf8 'string.encode_wtf8
  641. 'string.encode_wtf16)
  642. (-> (list (make-ref-type #t 'string) 'i32)
  643. '(i32)))
  644. ((or 'string.encode_utf8_array 'string.encode_lossy_utf8_array
  645. 'string.encode_wtf8_array)
  646. (-> (list (make-ref-type #t 'string)
  647. (make-ref-type #t $i8-array)
  648. 'i32)
  649. '(i32)))
  650. ('string.encode_wtf16_array
  651. (-> (list (make-ref-type #t 'string)
  652. (make-ref-type #t $i16-array)
  653. 'i32)
  654. '(i32)))
  655. ('string.const
  656. (-> '() (list (make-ref-type #f 'string))))
  657. ('string.concat
  658. (-> (list (make-ref-type #t 'string)
  659. (make-ref-type #t 'string))
  660. (list (make-ref-type #f 'string))))
  661. ((or 'string.eq 'string.compare)
  662. (-> (list (make-ref-type #t 'string)
  663. (make-ref-type #t 'string))
  664. '(i32)))
  665. ('string.is_usv_sequence
  666. (-> (list (make-ref-type #t 'string))
  667. '(i32)))
  668. ('string.from_code_point
  669. (-> (list 'i32)
  670. (list (make-ref-type #f 'string))))
  671. ('string.as_wtf8
  672. (-> (list (make-ref-type #t 'string))
  673. (list (make-ref-type #f 'stringview_wtf8))))
  674. ((or 'stringview_wtf8.encode_utf8
  675. 'stringview_wtf8.encode_lossy_utf8
  676. 'stringview_wtf8.encode_wtf8)
  677. (-> (list (make-ref-type #t 'stringview_wtf8)
  678. 'i32 'i32 'i32)
  679. '(i32 i32)))
  680. ('stringview_wtf8.advance
  681. (-> (list (make-ref-type #t 'stringview_wtf8)
  682. 'i32 'i32)
  683. '(i32)))
  684. ('stringview_wtf8.slice
  685. (-> (list (make-ref-type #t 'stringview_wtf8)
  686. 'i32 'i32)
  687. (list (make-ref-type #f 'string))))
  688. ('string.as_wtf16
  689. (-> (list (make-ref-type #t 'string))
  690. (list (make-ref-type #f 'stringview_wtf16))))
  691. ('stringview_wtf16.length
  692. (-> (list (make-ref-type #t 'stringview_wtf16))
  693. '(i32)))
  694. ('stringview_wtf16.get_codeunit
  695. (-> (list (make-ref-type #t 'stringview_wtf16) 'i32)
  696. '(i32)))
  697. ('stringview_wtf16.encode
  698. (-> (list (make-ref-type #t 'stringview_wtf16) 'i32 'i32 'i32)
  699. '(i32)))
  700. ('stringview_wtf16.slice
  701. (-> (list (make-ref-type #t 'stringview_wtf16)
  702. 'i32 'i32)
  703. (list (make-ref-type #f 'string))))
  704. ('string.as_iter
  705. (-> (list (make-ref-type #t 'string))
  706. (list (make-ref-type #f 'stringview_iter))))
  707. ('stringview_iter.next
  708. (-> (list (make-ref-type #t 'stringview_iter))
  709. '(i32)))
  710. ((or 'stringview_iter.advance 'stringview_iter.rewind)
  711. (-> (list (make-ref-type #t 'stringview_iter) 'i32)
  712. '(i32)))
  713. ('stringview_iter.slice
  714. (-> (list (make-ref-type #t 'stringview_iter)
  715. 'i32)
  716. (list (make-ref-type #f 'string))))
  717. ((or 'i8x16.splat 'i16x8.splat 'i32x4.splat)
  718. (-> '(i32) '(i128)))
  719. ('i64x2.splat (-> '(i64) '(i128)))
  720. ('f32x4.splat (-> '(f32) '(i128)))
  721. ('f64x2.splat (-> '(f64) '(i128)))
  722. (_ (error "unhandled instruction" op))))))
  723. (define (apply-stack-effect ctx effect)
  724. (define (resolve-type x)
  725. (match x
  726. ((? promise?) (force x))
  727. ((? exact-integer?) (lookup-type ctx x))
  728. (_ x)))
  729. (define (heap-type-sub-type? sub super)
  730. (let ((sub (resolve-type sub))
  731. (super (resolve-type super)))
  732. (or (eq? sub super)
  733. (let lp ((sub sub))
  734. (match sub
  735. ('any (eq? super 'any))
  736. ('i31 (memq super '(i31 eq any)))
  737. ('eq (memq super '(eq any)))
  738. (($ <sub-type> _ ((= resolve-type supers) ...) (= resolve-type type))
  739. (or (and supers (memq super supers))
  740. (lp type)))
  741. (($ <array-type> mutable? type)
  742. (memq super '(array eq any)))
  743. (($ <struct-type>)
  744. (memq super '(struct eq any)))
  745. (($ <func-sig>)
  746. (eq? super 'func)))))))
  747. (define (is-subtype? sub super)
  748. (cond
  749. ((eq? sub super) #t)
  750. ((and (eq? sub 'i32) (memq super '(i32 i16 i8))) #t)
  751. ((and (ref-type? sub) (ref-type? super))
  752. (and (or (ref-type-nullable? super)
  753. (not (ref-type-nullable? sub)))
  754. (heap-type-sub-type? (ref-type-heap-type sub)
  755. (ref-type-heap-type super))))
  756. ;; The funcref type works for any function reference.
  757. ((and (eq? super 'funcref) (ref-type? sub)
  758. (heap-type-sub-type? (ref-type-heap-type sub) 'func))
  759. #t)
  760. (else #f)))
  761. (match ctx
  762. (($ <invalid-ctx>) ctx)
  763. (($ <unreachable-ctx> info block stack)
  764. (match effect
  765. (($ <stack-effect> params results block-end?)
  766. (let lp ((params (reverse params)) (stack stack))
  767. (match params
  768. ((param . params)
  769. (match stack
  770. ;; The bottom of the unreachable stack is treated as a
  771. ;; polymorphic stack that contains any type, so there
  772. ;; is no reason to continue type checking.
  773. (()
  774. (lp '() '()))
  775. ;; Peeking at the unreachable stack may return #f,
  776. ;; which can stand in for any type.
  777. ((#f . stack)
  778. (lp params stack))
  779. ;; A proper type is on top of the stack, type checking
  780. ;; happens the same as in <ctx>.
  781. ((top . stack)
  782. (if (is-subtype? top param)
  783. (lp params stack)
  784. (make-invalid-ctx
  785. (format #f "expected ~a, got ~a" param top))))))
  786. (()
  787. (if (and block-end? (not (null? stack)))
  788. (make-invalid-ctx
  789. (format #f "extra values on stack at block end ~a" stack))
  790. (match results
  791. (#f (make-unreachable-ctx info block '()))
  792. ((result ...)
  793. (make-unreachable-ctx info block (append (reverse result) stack)))))))))))
  794. (($ <ctx> info block stack)
  795. (match effect
  796. (($ <stack-effect> params results block-end?)
  797. (let lp ((params (reverse params)) (stack stack))
  798. (match params
  799. ((param . params)
  800. (match stack
  801. (()
  802. (make-invalid-ctx
  803. (format #f "expected ~a, got empty stack" param)))
  804. ((top . stack)
  805. (if (is-subtype? top param)
  806. (lp params stack)
  807. ;; FIXME: more info here.
  808. (make-invalid-ctx
  809. (format #f "expected ~a, got ~a" param top))))))
  810. (()
  811. (if (and block-end? (not (null? stack)))
  812. (make-invalid-ctx
  813. (format #f "extra values on stack at block end ~a" stack))
  814. (match results
  815. (#f (make-unreachable-ctx info block '()))
  816. ((result ...)
  817. (make-ctx info block (append (reverse result) stack)))))))))))))
  818. (define (fallthrough-stack-effect ctx)
  819. (let ((types
  820. (match ctx
  821. (($ <unreachable-ctx> _ ($ <block> _ _ _ types)) types)
  822. (($ <ctx> _ ($ <block> _ _ _ types)) types))))
  823. (make-stack-effect types #f #t)))
  824. (define (fallthrough ctx)
  825. (apply-stack-effect ctx (fallthrough-stack-effect ctx)))