disassembler.scm 25 KB

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