disassembler.scm 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. ;;; Guile bytecode disassembler
  2. ;;; Copyright (C) 2001, 2009-2010, 2012-2015, 2017-2020 Free Software Foundation, Inc.
  3. ;;;
  4. ;;; This library is free software; you can redistribute it and/or
  5. ;;; modify it under the terms of the GNU Lesser General Public
  6. ;;; License as published by the Free Software Foundation; either
  7. ;;; version 3 of the License, or (at your option) any later version.
  8. ;;;
  9. ;;; This library is distributed in the hope that it will be useful,
  10. ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;; Lesser General Public License for more details.
  13. ;;;
  14. ;;; You should have received a copy of the GNU Lesser General Public
  15. ;;; License along with this library; if not, write to the Free Software
  16. ;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  17. ;;; Code:
  18. (define-module (system vm disassembler)
  19. #:use-module (language bytecode)
  20. #:use-module (system vm elf)
  21. #:use-module (system vm debug)
  22. #:use-module (system vm program)
  23. #:use-module (system vm loader)
  24. #:use-module (system base types internal)
  25. #:use-module (system foreign)
  26. #:use-module (rnrs bytevectors)
  27. #:use-module (ice-9 format)
  28. #:use-module (ice-9 match)
  29. #:use-module (ice-9 vlist)
  30. #:use-module (srfi srfi-1)
  31. #:use-module (srfi srfi-4)
  32. #:export (disassemble-program
  33. fold-program-code
  34. disassemble-image
  35. disassemble-file
  36. instruction-length
  37. instruction-has-fallthrough?
  38. instruction-relative-jump-targets
  39. instruction-stack-size-after
  40. instruction-slot-clobbers))
  41. (define (unpack-scm n)
  42. (pointer->scm (make-pointer n)))
  43. (define (unpack-s24 s)
  44. (if (zero? (logand s (ash 1 23)))
  45. s
  46. (- s (ash 1 24))))
  47. (define (unpack-s12 s)
  48. (if (zero? (logand s (ash 1 11)))
  49. s
  50. (- s (ash 1 12))))
  51. (define (unpack-s32 s)
  52. (if (zero? (logand s (ash 1 31)))
  53. s
  54. (- s (ash 1 32))))
  55. (eval-when (expand)
  56. (define-syntax-rule (u32-ref buf n)
  57. (bytevector-u32-native-ref buf (* n 4)))
  58. (define-syntax-rule (s32-ref buf n)
  59. (bytevector-s32-native-ref buf (* n 4)))
  60. (define-syntax-rule (define-op-handlers handlers make-handler)
  61. (define handlers
  62. (let ((handlers (make-vector 256 #f)))
  63. (define-syntax init-handlers
  64. (lambda (stx)
  65. #`(begin
  66. #,@(filter-map
  67. (match-lambda
  68. ((name opcode kind . word-types)
  69. (match (make-handler name kind word-types)
  70. (#f #f)
  71. (init #`(vector-set! handlers #,opcode #,init)))))
  72. (instruction-list)))))
  73. (init-handlers)
  74. handlers))))
  75. (define-op-handlers disassemblers
  76. (lambda (name kind word-types)
  77. (define (parse-first-word word type)
  78. (with-syntax ((word word))
  79. (case type
  80. ((X32)
  81. #'())
  82. ((X8_S24 X8_F24 X8_C24)
  83. #'((ash word -8)))
  84. ((X8_L24)
  85. #'((unpack-s24 (ash word -8))))
  86. ((X8_S8_I16 X8_S8_ZI16)
  87. #'((logand (ash word -8) #xff)
  88. (ash word -16)))
  89. ((X8_S12_S12
  90. X8_S12_C12
  91. X8_C12_C12
  92. X8_F12_F12)
  93. #'((logand (ash word -8) #xfff)
  94. (ash word -20)))
  95. ((X8_S12_Z12)
  96. #'((logand (ash word -8) #xfff)
  97. (unpack-s12 (ash word -20))))
  98. ((X8_S8_S8_S8
  99. X8_S8_S8_C8
  100. X8_S8_C8_S8)
  101. #'((logand (ash word -8) #xff)
  102. (logand (ash word -16) #xff)
  103. (ash word -24)))
  104. (else
  105. (error "bad head kind" type)))))
  106. (define (parse-tail-word word type n)
  107. (with-syntax ((word word) (n n))
  108. (case type
  109. ((C32 I32 A32 B32 AU32 BU32 AS32 BS32 AF32 BF32)
  110. #'(1 word))
  111. ((N32 R32 L32 LO32)
  112. #'(1 (unpack-s32 word)))
  113. ((C8_C24 C8_S24)
  114. #'(1
  115. (logand word #xff)
  116. (ash word -8)))
  117. ((C16_C16)
  118. #'(1
  119. (logand word #xffff)
  120. (ash word -16)))
  121. ((B1_C7_L24)
  122. #'(1
  123. (not (zero? (logand word #x1)))
  124. (logand (ash word -1) #x7f)
  125. (unpack-s24 (ash word -8))))
  126. ((B1_X7_S24 B1_X7_F24 B1_X7_C24)
  127. #'(1
  128. (not (zero? (logand word #x1)))
  129. (ash word -8)))
  130. ((B1_X7_L24)
  131. #'(1
  132. (not (zero? (logand word #x1)))
  133. (unpack-s24 (ash word -8))))
  134. ((B1_X31)
  135. #'(1 (not (zero? (logand word #x1)))))
  136. ((X8_S24 X8_F24 X8_C24)
  137. #'(1 (ash word -8)))
  138. ((X8_L24)
  139. #'(1 (unpack-s24 (ash word -8))))
  140. ((V32_X8_L24)
  141. #'((+ 1 word)
  142. (let ((v (make-vector word))
  143. (base (+ offset n 1)))
  144. (let lp ((i 0))
  145. (when (< i word)
  146. (vector-set! v i
  147. (unpack-s24 (ash (u32-ref buf (+ base i)) -8)))
  148. (lp (1+ i))))
  149. v)))
  150. (else
  151. (error "bad tail kind" type)))))
  152. (match word-types
  153. ((first-word . tail-words)
  154. (let ((vars (generate-temporaries tail-words))
  155. (word-offsets (map 1+ (iota (length tail-words)))))
  156. (with-syntax ((name (datum->syntax #'nowhere name))
  157. ((word* ...) vars)
  158. ((n ...) word-offsets)
  159. ((asm ...)
  160. (parse-first-word #'first first-word))
  161. (((len asm* ...) ...)
  162. (map parse-tail-word vars tail-words word-offsets)))
  163. #'(lambda (buf offset first)
  164. (let ((word* (u32-ref buf (+ offset n)))
  165. ...)
  166. (values (+ 1 len ...)
  167. (list 'name asm ... asm* ... ...))))))))))
  168. ;; -> len list
  169. (define (disassemble-one buf offset)
  170. (let ((first (u32-ref buf offset)))
  171. (match (vector-ref disassemblers (logand first #xff))
  172. (#f (error "bad instruction" (logand first #xff) first buf offset))
  173. (disassemble (disassemble buf offset first)))))
  174. (define (u32-offset->addr offset context)
  175. "Given an offset into an image in 32-bit units, return the absolute
  176. address of that offset."
  177. (+ (debug-context-base context) (* offset 4)))
  178. (define immediate-tag-annotations '())
  179. (define-syntax-rule (define-immediate-tag-annotation name pred mask tag)
  180. (set! immediate-tag-annotations
  181. (cons `((,mask ,tag)
  182. ,(cond
  183. ('pred => symbol->string)
  184. (else (string-append "eq-" (symbol->string 'name) "?"))))
  185. immediate-tag-annotations)))
  186. (visit-immediate-tags define-immediate-tag-annotation)
  187. (define heap-tag-annotations '())
  188. (define-syntax-rule (define-heap-tag-annotation name pred mask tag)
  189. (set! heap-tag-annotations
  190. (cons `((,mask ,tag) ,(symbol->string 'pred)) heap-tag-annotations)))
  191. (visit-heap-tags define-heap-tag-annotation)
  192. (define (sign-extended-immediate uimm n)
  193. (unpack-scm
  194. (if (>= uimm (ash 1 (- n 1)))
  195. (let ((word-bits (* (sizeof '*) 8))) ; FIXME
  196. (logand (1- (ash 1 word-bits))
  197. (- uimm (ash 1 n))))
  198. uimm)))
  199. (define (code-annotation code len offset start labels context push-addr!)
  200. ;; FIXME: Print names for register loads and stores that correspond to
  201. ;; access to named locals.
  202. (define (reference-scm target)
  203. (unpack-scm (u32-offset->addr (+ offset target) context)))
  204. (define (dereference-scm target)
  205. (let ((addr (u32-offset->addr (+ offset target)
  206. context)))
  207. (pointer->scm
  208. (dereference-pointer (make-pointer addr)))))
  209. (match code
  210. (((or 'j 'je 'jl 'jge 'jne 'jnl 'jnge) target)
  211. (list "-> ~A" (vector-ref labels (- (+ offset target) start))))
  212. (('immediate-tag=? _ mask tag)
  213. (assoc-ref immediate-tag-annotations (list mask tag)))
  214. (('heap-tag=? _ mask tag)
  215. (assoc-ref heap-tag-annotations (list mask tag)))
  216. (('prompt tag escape-only? proc-slot handler)
  217. ;; The H is for handler.
  218. (list "H -> ~A" (vector-ref labels (- (+ offset handler) start))))
  219. (((or 'make-immediate 'eq-immediate?) _ imm)
  220. (list "~S" (sign-extended-immediate imm 16)))
  221. (((or 'make-short-immediate 'make-long-immediate) _ imm)
  222. (list "~S" (unpack-scm imm)))
  223. (('make-long-long-immediate _ high low)
  224. (list "~S" (unpack-scm (logior (ash high 32) low))))
  225. (('assert-nargs-ee/locals nargs locals)
  226. ;; The nargs includes the procedure.
  227. (list "~a slot~:p (~a arg~:p)" (+ locals nargs) (1- nargs)))
  228. (('bind-optionals nargs)
  229. (list "~a args~:p" (1- nargs)))
  230. (('alloc-frame nlocals)
  231. (list "~a slot~:p" nlocals))
  232. (('reset-frame nlocals)
  233. (list "~a slot~:p" nlocals))
  234. (('bind-rest dst)
  235. (list "~a slot~:p" (1+ dst)))
  236. (('make-closure dst target nfree)
  237. (let* ((addr (u32-offset->addr (+ offset target) context))
  238. (pdi (find-program-debug-info addr context))
  239. (name (or (and pdi (program-debug-info-name pdi))
  240. "anonymous procedure")))
  241. (push-addr! addr name)
  242. (list "~A at #x~X (~A free var~:p)" name addr nfree)))
  243. (('load-label dst src)
  244. (let* ((addr (u32-offset->addr (+ offset src) context))
  245. (pdi (find-program-debug-info addr context))
  246. (name (or (and pdi (program-debug-info-name pdi))
  247. "anonymous procedure")))
  248. (push-addr! addr name)
  249. (list "~A at #x~X" name addr)))
  250. (('call-label closure nlocals target)
  251. (let* ((addr (u32-offset->addr (+ offset target) context))
  252. (pdi (find-program-debug-info addr context))
  253. (name (or (and pdi (program-debug-info-name pdi))
  254. "anonymous procedure")))
  255. (push-addr! addr name)
  256. (list "~A at #x~X" name addr)))
  257. (('tail-call-label target)
  258. (let* ((addr (u32-offset->addr (+ offset target) context))
  259. (pdi (find-program-debug-info addr context))
  260. (name (or (and pdi (program-debug-info-name pdi))
  261. "anonymous procedure")))
  262. (push-addr! addr name)
  263. (list "~A at #x~X" name addr)))
  264. (('make-non-immediate dst target)
  265. (let ((val (reference-scm target)))
  266. (when (program? val)
  267. (push-addr! (program-code val) val))
  268. (list "~@Y" val)))
  269. (((or 'throw/value 'throw/value+data) dst target)
  270. (list "~@Y" (reference-scm target)))
  271. (('builtin-ref dst idx)
  272. (list "~A" (builtin-index->name idx)))
  273. (((or 'static-ref 'static-set!) _ target)
  274. (list "~@Y" (dereference-scm target)))
  275. (('resolve-module dst name public)
  276. (list "~a" (if (zero? public) "private" "public")))
  277. (('load-typed-array dst type shape target len)
  278. (let ((addr (u32-offset->addr (+ offset target) context)))
  279. (list "~a bytes from #x~X" len addr)))
  280. (_ #f)))
  281. (define (compute-labels bv start end)
  282. (let ((labels (make-vector (- end start) #f)))
  283. (define (add-label! pos header)
  284. (unless (vector-ref labels (- pos start))
  285. (vector-set! labels (- pos start) header)))
  286. (let lp ((offset start))
  287. (when (< offset end)
  288. (call-with-values (lambda () (disassemble-one bv offset))
  289. (lambda (len elt)
  290. (match elt
  291. ((inst arg ...)
  292. (case inst
  293. ((j je jl jge jne jnl jnge)
  294. (match arg
  295. ((_ ... target)
  296. (add-label! (+ offset target) "L"))))
  297. ((prompt)
  298. (match arg
  299. ((_ ... target)
  300. (add-label! (+ offset target) "H"))))
  301. ((jtable)
  302. (match arg
  303. ((_ ... targets)
  304. (let ((len (vector-length targets)))
  305. (let lp ((i 0))
  306. (when (< i len)
  307. (add-label! (+ offset (vector-ref targets i)) "L")
  308. (lp (1+ i)))))))))))
  309. (lp (+ offset len))))))
  310. (let lp ((offset start) (n 1))
  311. (when (< offset end)
  312. (let* ((pos (- offset start))
  313. (label (vector-ref labels pos)))
  314. (if label
  315. (begin
  316. (vector-set! labels
  317. pos
  318. (string->symbol
  319. (string-append label (number->string n))))
  320. (lp (1+ offset) (1+ n)))
  321. (lp (1+ offset) n)))))
  322. labels))
  323. (define (print-info port addr label info extra src)
  324. (when label
  325. (format port "~A:\n" label))
  326. (format port "~4@S ~32S~@[;; ~1{~@?~}~]~@[~61t at ~a~]\n"
  327. addr info extra src))
  328. (define (disassemble-buffer port bv start end context push-addr!)
  329. (let ((labels (compute-labels bv start end))
  330. (sources (find-program-sources (u32-offset->addr start context)
  331. context)))
  332. (define (lookup-source addr)
  333. (let lp ((sources sources))
  334. (match sources
  335. (() #f)
  336. ((source . sources)
  337. (let ((pc (source-pre-pc source)))
  338. (cond
  339. ((< pc addr) (lp sources))
  340. ((= pc addr)
  341. (format #f "~a:~a:~a"
  342. (or (source-file source) "(unknown file)")
  343. (source-line-for-user source)
  344. (source-column source)))
  345. (else #f)))))))
  346. (let lp ((offset start))
  347. (when (< offset end)
  348. (call-with-values (lambda () (disassemble-one bv offset))
  349. (lambda (len elt)
  350. (let ((pos (- offset start))
  351. (addr (u32-offset->addr offset context))
  352. (annotation (code-annotation elt len offset start labels
  353. context push-addr!)))
  354. (print-info port pos (vector-ref labels pos) elt annotation
  355. (lookup-source addr))
  356. (lp (+ offset len)))))))))
  357. (define* (disassemble-addr addr label port #:optional (seen (make-hash-table)))
  358. (format port "Disassembly of ~A at #x~X:\n\n" label addr)
  359. (cond
  360. ((find-program-debug-info addr)
  361. => (lambda (pdi)
  362. (let ((worklist '()))
  363. (define (push-addr! addr label)
  364. (unless (hashv-ref seen addr)
  365. (hashv-set! seen addr #t)
  366. (set! worklist (acons addr label worklist))))
  367. (disassemble-buffer port
  368. (program-debug-info-image pdi)
  369. (program-debug-info-u32-offset pdi)
  370. (program-debug-info-u32-offset-end pdi)
  371. (program-debug-info-context pdi)
  372. push-addr!)
  373. (for-each (match-lambda
  374. ((addr . label)
  375. (display "\n----------------------------------------\n"
  376. port)
  377. (disassemble-addr addr label port seen)))
  378. worklist))))
  379. (else
  380. (format port "Debugging information unavailable.~%")))
  381. (values))
  382. (define* (disassemble-program program #:optional (port (current-output-port)))
  383. (disassemble-addr (program-code program) program port))
  384. (define (fold-code-range proc seed bv start end context raw?)
  385. (define (cook code offset)
  386. (define (reference-scm target)
  387. (unpack-scm (u32-offset->addr (+ offset target) context)))
  388. (define (dereference-scm target)
  389. (let ((addr (u32-offset->addr (+ offset target)
  390. context)))
  391. (pointer->scm
  392. (dereference-pointer (make-pointer addr)))))
  393. (match code
  394. (((or 'make-short-immediate 'make-long-immediate) dst imm)
  395. `(,(car code) ,dst ,(unpack-scm imm)))
  396. (('make-long-long-immediate dst high low)
  397. `(make-long-long-immediate ,dst
  398. ,(unpack-scm (logior (ash high 32) low))))
  399. (('make-closure dst target nfree)
  400. `(make-closure ,dst
  401. ,(u32-offset->addr (+ offset target) context)
  402. ,nfree))
  403. (('load-label dst src)
  404. `(load-label ,dst ,(u32-offset->addr (+ offset src) context)))
  405. (('make-non-immediate dst target)
  406. `(make-non-immediate ,dst ,(reference-scm target)))
  407. (('builtin-ref dst idx)
  408. `(builtin-ref ,dst ,(builtin-index->name idx)))
  409. (((or 'static-ref 'static-set!) dst target)
  410. `(,(car code) ,dst ,(dereference-scm target)))
  411. (_ code)))
  412. (let lp ((offset start) (seed seed))
  413. (cond
  414. ((< offset end)
  415. (call-with-values (lambda () (disassemble-one bv offset))
  416. (lambda (len elt)
  417. (lp (+ offset len)
  418. (proc (if raw? elt (cook elt offset))
  419. seed)))))
  420. (else seed))))
  421. (define* (fold-program-code proc seed program-or-addr #:key raw?)
  422. (cond
  423. ((find-program-debug-info (if (program? program-or-addr)
  424. (program-code program-or-addr)
  425. program-or-addr))
  426. => (lambda (pdi)
  427. (fold-code-range proc seed
  428. (program-debug-info-image pdi)
  429. (program-debug-info-u32-offset pdi)
  430. (program-debug-info-u32-offset-end pdi)
  431. (program-debug-info-context pdi)
  432. raw?)))
  433. (else seed)))
  434. (define* (disassemble-image bv #:optional (port (current-output-port)))
  435. (let* ((ctx (debug-context-from-image bv))
  436. (base (debug-context-text-base ctx)))
  437. (for-each-elf-symbol
  438. ctx
  439. (lambda (sym)
  440. (let ((name (elf-symbol-name sym))
  441. (value (elf-symbol-value sym))
  442. (size (elf-symbol-size sym)))
  443. (format port "Disassembly of ~A at #x~X:\n\n"
  444. (if (and (string? name) (not (string-null? name)))
  445. name
  446. "<unnamed function>")
  447. (+ base value))
  448. (disassemble-buffer port
  449. bv
  450. (/ (+ base value) 4)
  451. (/ (+ base value size) 4)
  452. ctx
  453. (lambda (addr name) #t))
  454. (display "\n\n" port)))))
  455. (values))
  456. (define* (disassemble-file file #:optional (port (current-output-port)))
  457. (let* ((thunk (load-thunk-from-file file))
  458. (elf (find-mapped-elf-image (program-code thunk))))
  459. (disassemble-image elf port)))
  460. (define-syntax instruction-lengths-vector
  461. (lambda (x)
  462. (syntax-case x ()
  463. ((_)
  464. (let ((lengths (make-vector 256 #f)))
  465. (for-each (match-lambda
  466. ((name opcode kind word ... 'V32_X8_L24)
  467. ;; Indicate variable-length instruction by setting
  468. ;; statically known length to 0.
  469. (vector-set! lengths opcode 0))
  470. ((name opcode kind words ...)
  471. (vector-set! lengths opcode (* 4 (length words)))))
  472. (instruction-list))
  473. (datum->syntax x lengths))))))
  474. (define (instruction-length code pos)
  475. (unless (zero? (modulo pos 4))
  476. (error "invalid pos"))
  477. (let ((opcode (logand (bytevector-u32-native-ref code pos) #xff)))
  478. (match (vector-ref (instruction-lengths-vector) opcode)
  479. (#f (error "Unknown opcode" opcode))
  480. (0 (call-with-values (lambda ()
  481. (let ((offset (/ pos 4)))
  482. (disassemble-one code offset)))
  483. (lambda (u32-len disasm)
  484. (* u32-len 4))))
  485. (len len))))
  486. (define-syntax static-opcode-set
  487. (lambda (x)
  488. (define (instruction-opcode inst)
  489. (cond
  490. ((assq inst (instruction-list))
  491. => (match-lambda ((name opcode . _) opcode)))
  492. (else
  493. (error "unknown instruction" inst))))
  494. (syntax-case x ()
  495. ((static-opcode-set inst ...)
  496. (let ((bv (make-bitvector 256 #f)))
  497. (for-each (lambda (inst)
  498. (bitvector-set-bit! bv (instruction-opcode inst)))
  499. (syntax->datum #'(inst ...)))
  500. (datum->syntax #'static-opcode-set bv))))))
  501. (define (instruction-has-fallthrough? code pos)
  502. (define non-fallthrough-set
  503. (static-opcode-set halt
  504. throw throw/value throw/value+data
  505. tail-call tail-call-label
  506. return-values
  507. subr-call foreign-call continuation-call
  508. j jtable))
  509. (let ((opcode (logand (bytevector-u32-native-ref code pos) #xff)))
  510. (bitvector-bit-clear? non-fallthrough-set opcode)))
  511. (define (word-offset->byte-offset n)
  512. (* n 4))
  513. (define-op-handlers jump-parsers
  514. (lambda (op kind word-types)
  515. (case op
  516. ((prompt j je jl jge jne jnl jnge)
  517. #'(lambda (code pos)
  518. (call-with-values (lambda () (disassemble-one code (/ pos 4)))
  519. (lambda (len disasm)
  520. (match disasm
  521. ;; Assume that the target is in the last word, as a
  522. ;; word offset.
  523. ((_ ___ target) (list (word-offset->byte-offset target))))))))
  524. ((jtable)
  525. #'(lambda (code pos)
  526. (call-with-values (lambda () (disassemble-one code (/ pos 4)))
  527. (lambda (len disasm)
  528. (match disasm
  529. ;; Assume that the target is in the last word, as a
  530. ;; vector of word offsets.
  531. ((_ ___ targets)
  532. (map word-offset->byte-offset (vector->list targets))))))))
  533. (else #f))))
  534. (define (instruction-relative-jump-targets code pos)
  535. (let ((opcode (logand (bytevector-u32-native-ref code pos) #xff)))
  536. (match (vector-ref jump-parsers opcode)
  537. (#f '())
  538. (proc (proc code pos)))))
  539. (define-op-handlers stack-effect-parsers
  540. (lambda (name kind word-types)
  541. (case name
  542. ((push)
  543. #'(lambda (code pos size) (and size (+ size 1))))
  544. ((pop)
  545. #'(lambda (code pos size) (and size (- size 1))))
  546. ((drop)
  547. #'(lambda (code pos size)
  548. (let ((count (ash (bytevector-u32-native-ref code pos) -8)))
  549. (and size (- size count)))))
  550. ((alloc-frame reset-frame bind-optionals)
  551. #'(lambda (code pos size)
  552. (let ((nlocals (ash (bytevector-u32-native-ref code pos) -8)))
  553. nlocals)))
  554. ((receive)
  555. #'(lambda (code pos size)
  556. (let ((nlocals (ash (bytevector-u32-native-ref code (+ pos 4))
  557. -8)))
  558. nlocals)))
  559. ((bind-kwargs)
  560. #'(lambda (code pos size)
  561. (let ((ntotal (ash (bytevector-u32-native-ref code (+ pos 8)) -8)))
  562. ntotal)))
  563. ((bind-rest)
  564. #'(lambda (code pos size)
  565. (let ((dst (ash (bytevector-u32-native-ref code pos) -8)))
  566. (+ dst 1))))
  567. ((assert-nargs-ee/locals)
  568. #'(lambda (code pos size)
  569. (let ((nargs (logand (ash (bytevector-u32-native-ref code pos) -8)
  570. #xfff))
  571. (nlocals (ash (bytevector-u32-native-ref code pos) -20)))
  572. (+ nargs nlocals))))
  573. ((call call-label tail-call tail-call-label expand-apply-argument)
  574. #'(lambda (code pos size) #f))
  575. ((shuffle-down)
  576. #'(lambda (code pos size)
  577. (let ((from (logand (ash (bytevector-u32-native-ref code pos) -8)
  578. #xfff))
  579. (to (ash (bytevector-u32-native-ref code pos) -20)))
  580. (and size (- size (- from to))))))
  581. (else
  582. #f))))
  583. (define (instruction-stack-size-after code pos size)
  584. (let ((opcode (logand (bytevector-u32-native-ref code pos) #xff)))
  585. (match (vector-ref stack-effect-parsers opcode)
  586. (#f size)
  587. (proc (proc code pos size)))))
  588. (define-op-handlers clobber-parsers
  589. (lambda (name kind word-types)
  590. (match kind
  591. ('!
  592. (case name
  593. ((call call-label)
  594. #'(lambda (code pos nslots-in nslots-out)
  595. (call-with-values
  596. (lambda ()
  597. (disassemble-one code (/ pos 4)))
  598. (lambda (len elt)
  599. (define frame-size 3)
  600. (match elt
  601. ((_ proc . _)
  602. (let lp ((slot (- proc frame-size)))
  603. (if (and nslots-in (< slot nslots-in))
  604. (cons slot (lp (1+ slot)))
  605. '()))))))))
  606. (else #f)))
  607. ('<-
  608. #`(lambda (code pos nslots-in nslots-out)
  609. (call-with-values (lambda ()
  610. (disassemble-one code (/ pos 4)))
  611. (lambda (len elt)
  612. (match elt
  613. ((_ dst . _)
  614. #,(match word-types
  615. (((or 'X8_F24 'X8_F12_F12) . _)
  616. #'(list dst))
  617. (else
  618. #'(if nslots-out
  619. (list (- nslots-out 1 dst))
  620. '()))))))))))))
  621. (define (instruction-slot-clobbers code pos nslots-in nslots-out)
  622. (let ((opcode (logand (bytevector-u32-native-ref code pos) #xff)))
  623. (match (vector-ref clobber-parsers opcode)
  624. (#f '())
  625. (proc (proc code pos nslots-in nslots-out)))))