disassembler.scm 24 KB

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