stack.scm 29 KB

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