stack.scm 29 KB

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