repl.scm 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598
  1. ;;; REPL commands
  2. ;;; Copyright (C) 2023 David Thompson <dave@spritely.institute>
  3. ;;;
  4. ;;; Licensed under the Apache License, Version 2.0 (the "License");
  5. ;;; you may not use this file except in compliance with the License.
  6. ;;; You may obtain a copy of the License at
  7. ;;;
  8. ;;; http://www.apache.org/licenses/LICENSE-2.0
  9. ;;;
  10. ;;; Unless required by applicable law or agreed to in writing, software
  11. ;;; distributed under the License is distributed on an "AS IS" BASIS,
  12. ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. ;;; See the License for the specific language governing permissions and
  14. ;;; limitations under the License.
  15. ;;; Commentary:
  16. ;;;
  17. ;;; Handy REPL commands for development.
  18. ;;;
  19. ;;; Code:
  20. (define-module (hoot repl)
  21. #:use-module (hoot reflect)
  22. #:use-module (ice-9 control)
  23. #:use-module (ice-9 match)
  24. #:use-module (ice-9 pretty-print)
  25. #:use-module (srfi srfi-1)
  26. #:use-module (srfi srfi-9)
  27. #:use-module (system repl command)
  28. #:use-module (system repl common)
  29. #:use-module (system repl debug)
  30. #:use-module (system repl repl)
  31. #:use-module (wasm dump)
  32. #:use-module (wasm resolve)
  33. #:use-module (wasm types)
  34. #:use-module (wasm vm)
  35. #:use-module (wasm wat))
  36. (define (make-id prefix idx)
  37. (string->symbol
  38. (string-append "$" prefix (number->string idx))))
  39. (define (name-ref name-map idx)
  40. (and name-map (assq-ref name-map idx)))
  41. (define (indirect-name-ref iname-map parent-idx idx)
  42. (and iname-map (name-ref (assq-ref iname-map parent-idx) idx)))
  43. (define-syntax-rule (define-name-ref name getter prefix)
  44. (define (name names idx)
  45. (or (and names (name-ref (getter names) idx))
  46. (make-id prefix idx))))
  47. (define-syntax-rule (define-indirect-name-ref name getter prefix)
  48. (define (name names parent-idx idx)
  49. (or (and names (indirect-name-ref (getter names) parent-idx idx))
  50. (make-id prefix idx))))
  51. (define-name-ref func-name names-func "func")
  52. (define-indirect-name-ref local-name names-local "var")
  53. (define-name-ref type-name names-type "type")
  54. (define-name-ref table-name names-table "table")
  55. (define-name-ref memory-name names-memory "memory")
  56. (define-name-ref global-name names-global "global")
  57. (define-name-ref elem-name names-elem "elem")
  58. (define-name-ref data-name names-data "data")
  59. (define-indirect-name-ref field-name names-field "field")
  60. (define-name-ref tag-name names-tag "tag")
  61. (define (heap-type-repr names ht)
  62. (match ht
  63. ((or 'func 'extern
  64. 'any 'eq 'i31 'noextern 'nofunc 'struct 'array 'none
  65. 'string 'stringview_wtf8 'stringview_wtf16 'stringview_iter)
  66. ht)
  67. (_ (type-name names ht))))
  68. (define (ref-type-repr names rt)
  69. (match rt
  70. (($ <ref-type> nullable? ht)
  71. `(ref ,@(if nullable? '(null) '()) ,(heap-type-repr names ht)))))
  72. (define (val-type-repr names vt)
  73. (match vt
  74. ((or 'i32 'i64 'f32 'f64 'v128
  75. 'funcref 'externref 'anyref 'eqref 'i31ref
  76. 'nullexternref 'nullfuncref
  77. 'structref 'arrayref 'nullref
  78. 'stringref
  79. 'stringview_wtf8ref 'stringview_wtf16ref 'stringview_iterref)
  80. vt)
  81. ((? ref-type? rt)
  82. (ref-type-repr names rt))))
  83. (define (memarg-repr names memarg)
  84. (define (make-prefix-arg prefix x)
  85. (if (zero? x)
  86. '()
  87. (list (string->symbol (string-append prefix (number->string x))))))
  88. (match memarg
  89. (($ <mem-arg> memory offset align)
  90. `(,(memory-name names memory)
  91. ,@(make-prefix-arg "offset=" offset)
  92. ,@(make-prefix-arg "align=" align)))))
  93. (define (block-type-repr names bt)
  94. (match bt
  95. (#f
  96. '())
  97. ((? symbol?)
  98. `(,bt))
  99. (($ <type-use> _ ($ <func-sig> params results))
  100. (append (map (match-lambda
  101. (($ <param> _ type)
  102. `(param ,(val-type-repr names type))))
  103. params)
  104. (map (lambda (vt)
  105. `(result ,(val-type-repr names vt)))
  106. results)))
  107. ((? ref-type? rt)
  108. `(,(ref-type-repr names rt)))))
  109. ;; TODO: Label names. We don't have control stack info here.
  110. (define (instruction-repr instr names strings func-idx)
  111. (match instr
  112. (((and op (or 'local.get 'local.set 'local.tee)) local)
  113. `(,op ,(local-name names func-idx local)))
  114. (((and op (or 'global.get 'global.set)) global)
  115. `(,op ,(global-name names global)))
  116. (((and inst (or 'throw 'rethrow)) tag)
  117. `(,inst ,(tag-name names tag)))
  118. (((and inst (or 'call 'return_call)) func)
  119. `(,inst ,(func-name names func)))
  120. (('call_indirect table ($ <type-use> type))
  121. `(call_indirect ,(table-name names table) ,(type-name names type)))
  122. (((and inst (or 'call_ref 'return_call_ref)) type)
  123. `(,inst ,(type-name names type)))
  124. (('select types) `(select ,(map val-type-repr types)))
  125. (('ref.null ht) `(ref.null ,(heap-type-repr names ht)))
  126. (('ref.func f) `(ref.func ,(func-name names f)))
  127. ;; Memories
  128. (((and op (or 'i32.load 'i32.load16_s 'i32.load16_u 'i32.load8_s
  129. 'i32.load8_u 'i32.store 'i32.store16 'i32.store8
  130. 'i64.load 'i64.load32_s 'i64.load32_u 'i64.load16_s
  131. 'i64.load16_u 'i64.load8_s 'i64.load8_u 'f32.load
  132. 'f64.load 'i64.store 'i64.store32 'i64.store16
  133. 'i64.store8 'f32.store 'f64.store))
  134. memarg)
  135. `(,op ,@(memarg-repr names memarg)))
  136. (((and inst (or 'memory.size 'memory.grow)) mem)
  137. `(,inst ,(memory-name names mem)))
  138. (('memory.init data mem)
  139. `(memory.init ,(data-name names data) ,(memory-name names mem)))
  140. (('memory.copy dst src)
  141. `(memory.copy ,(memory-name names dst) ,(memory-name names src)))
  142. (('memory.fill mem)
  143. `(memory.fill ,(memory-name names mem)))
  144. (('data.drop data)
  145. `(data.drop ,(data-name names data)))
  146. ;; Tables
  147. (((and op (or 'table.get 'table.set 'table.grow 'table.size 'table.fill)) table)
  148. `(,op ,(table-name names table)))
  149. (('table.init table elem)
  150. `(table.init ,(table-name names table) ,(elem-name names elem)))
  151. (('table.copy dst src)
  152. `(table.copy ,(table-name names dst) ,(table-name names src)))
  153. (('elem.drop elem)
  154. `(elem.drop ,(elem-name names elem)))
  155. ;; GC
  156. (((and op (or 'ref.test 'ref.cast)) rt)
  157. `(,op ,@(ref-type-repr names rt)))
  158. (((and op (or 'br_on_cast 'br_on_cast_fail)) label rt1 rt2)
  159. `(,op ,label ,@(ref-type-repr names rt1) ,@(ref-type-repr names rt2)))
  160. (((and op (or 'struct.get 'struct.get_s 'struct.get_u 'struct.set)) type field)
  161. `(,op ,(type-name names type) ,(field-name names type field)))
  162. (((and op (or 'struct.new 'struct.new_default)) type)
  163. `(,op ,(type-name names type)))
  164. (((and op (or 'array.get 'array.get_s 'array.get_u 'array.set)) type)
  165. `(,op ,(type-name names type)))
  166. (('array.new_fixed type len)
  167. `(array.new_fixed ,(type-name names type) ,len))
  168. (((and op (or 'array.new 'array.new_default)) type)
  169. `(,op ,(type-name names type)))
  170. (((and op (or 'array.new_data 'array.init_data)) type data)
  171. `(,op ,(type-name names type) ,(data-name names data)))
  172. (((and op (or 'array.new_elem 'array.init_elem)) type elem)
  173. `(,op ,(type-name names type) ,(elem-name names elem)))
  174. (('array.fill type)
  175. `(array.fill ,(type-name names type)))
  176. (('array.copy dst src)
  177. `(array.copy ,(type-name names dst) ,(type-name names src)))
  178. ;; Stringref
  179. (('string.const idx)
  180. `(string.const (list-ref strings idx)))
  181. (((and op (or 'string.new_utf8 'string.new_lossy_utf8 'string.new_wtf8
  182. 'string.new_wtf16
  183. 'string.encode_utf8 'string.encode_lossy_utf8
  184. 'string.encode_wtf8 'string.encode_wtf16
  185. 'stringview_wtf8.encode_utf8
  186. 'stringview_wtf8.encode_lossy_utf8
  187. 'stringview_wtf8.encode_wtf8
  188. 'stringview_wtf16.encode))
  189. mem)
  190. `(,op ,@(memarg-repr names mem)))
  191. (_ instr)))
  192. (define (for-each/index proc lst)
  193. (let loop ((lst lst) (i 0))
  194. (match lst
  195. (() *unspecified*)
  196. ((x . rest)
  197. (proc i x)
  198. (loop rest (+ i 1))))))
  199. (define (print-list proc title items)
  200. (format #t "~a:\n" title)
  201. (for-each/index (lambda (i item)
  202. (format #t " ~a:\t" i)
  203. (proc item))
  204. items))
  205. (define (print-stack stack)
  206. (match (wasm-stack-items stack)
  207. (() (display "Empty stack.\n"))
  208. (items
  209. (print-list (lambda (x) (format #t "~s\n" x))
  210. "Value stack"
  211. items))))
  212. (define (print-locals locals)
  213. (if (zero? (vector-length locals))
  214. (display "No locals.\n")
  215. (print-list (lambda (x) (format #t "~s\n" x))
  216. "Locals"
  217. (vector->list locals))))
  218. (define (print-runtime-error e)
  219. (print-exception (current-output-port) #f
  220. (exception-kind e)
  221. (exception-args e))
  222. (newline)
  223. (print-stack (wasm-runtime-error-stack e))
  224. (newline)
  225. (print-locals (wasm-runtime-error-locals e))
  226. (newline)
  227. (print-location (validated-wasm-ref
  228. (wasm-instance-module
  229. (wasm-runtime-error-instance e)))
  230. (wasm-runtime-error-position e)))
  231. (define-syntax-rule (with-exception-handling body ...)
  232. (with-exception-handler (lambda (e) (print-runtime-error e))
  233. (lambda () body ...)
  234. #:unwind? #t
  235. #:unwind-for-type &wasm-runtime-error))
  236. (define (print-location wasm path)
  237. (define invalid-path '(-1))
  238. (define (path-remainder path i)
  239. (match path
  240. ((idx . rest)
  241. (if (and (= idx i) (not (null? rest))) rest invalid-path))))
  242. (define (here? path i)
  243. (match path
  244. ((idx) (= i idx))
  245. (_ #f)))
  246. (define (indent level)
  247. (unless (= level 0)
  248. (display " ")
  249. (indent (- level 1))))
  250. (define (print-block-type type)
  251. (for-each (lambda (x)
  252. (format #t " ~s" x))
  253. (block-type-repr #f type)))
  254. (define (print-instr level instr path)
  255. (match instr
  256. (((and op (or 'block 'loop)) _ (or ($ <type-use> _ sig) sig) body)
  257. (format #t "(~a" op)
  258. (print-block-type sig)
  259. (newline)
  260. (print-instrs (+ level 1) body path)
  261. (display ")"))
  262. (('if _ (or ($ <type-use> _ sig) sig) consequent alternate)
  263. (display "(if")
  264. (print-block-type sig)
  265. (unless (null? consequent)
  266. (newline)
  267. (indent (+ level 1))
  268. (display "(then\n")
  269. (print-instrs (+ level 2) consequent
  270. (path-remainder path 0))
  271. (display ")"))
  272. (unless (null? alternate)
  273. (newline)
  274. (indent (+ level 1))
  275. (display "(else\n")
  276. (print-instrs (+ level 2) alternate
  277. (path-remainder path 1))
  278. (display ")"))
  279. (display ")"))
  280. (_
  281. (write instr))))
  282. (define (print-instrs level instrs path)
  283. (indent level)
  284. (let loop ((instrs instrs)
  285. (i 0))
  286. (match instrs
  287. (() #t)
  288. ((instr . rest)
  289. (if (here? path i)
  290. (begin
  291. (display "<<< ")
  292. (print-instr level instr (path-remainder path i))
  293. (display " >>>"))
  294. (print-instr level instr (path-remainder path i)))
  295. (unless (null? rest)
  296. (newline)
  297. (indent level)
  298. (loop rest (+ i 1)))))))
  299. (define (count-imports kind)
  300. (fold (lambda (i sum)
  301. (match i
  302. (($ <import> _ _ k)
  303. (if (eq? kind k) (+ sum 1) sum))))
  304. 0 (wasm-imports wasm)))
  305. (match path
  306. (('func idx . path*)
  307. (match (list-ref (wasm-funcs wasm) (- idx (count-imports 'func)))
  308. (($ <func> id ($ <type-use> _ sig) locals body)
  309. (format #t "(func ~a" idx)
  310. (print-block-type sig)
  311. (newline)
  312. (print-instrs 1 body path*)
  313. (display ")"))))
  314. (('global idx . path*)
  315. (match (list-ref (wasm-globals wasm) (- idx (count-imports 'global)))
  316. (($ <global> id ($ <global-type> mutable? type) init)
  317. (let ((t (val-type-repr #f type)))
  318. (format #t "(global ~a " idx)
  319. (write (if mutable? `(mut ,t) t))
  320. (newline)
  321. (print-instrs 1 init path*)
  322. (display ")")))))
  323. (('data idx . path*)
  324. (match (list-ref (wasm-datas wasm) idx)
  325. (($ <data> id mode mem offset init)
  326. (format #t "(data ~a ~a ~a ~a\n" idx mode mem offset)
  327. (print-instrs 1 init path*)
  328. (display ")"))))
  329. (('elem idx j . path*)
  330. (match (list-ref (wasm-elems wasm) idx)
  331. (($ <elem> id mode table type offset inits)
  332. (let ((t (val-type-repr #f type)))
  333. (format #t "(elem ~a ~a ~a ~a" idx mode table t)
  334. (when offset
  335. (newline)
  336. (print-instrs 1 offset (if (= j 0) path* invalid-path)))
  337. (let loop ((inits inits) (i 1))
  338. (match inits
  339. (() #t)
  340. ((init . rest)
  341. (newline)
  342. (print-instrs 1 init (if (= j 1) path* invalid-path))
  343. (loop rest (+ i 1)))))
  344. (display ")"))))))
  345. (newline))
  346. (define (wasm-trace path instr instance stack blocks locals)
  347. (define (obj-abbrev obj)
  348. (match obj
  349. ((? wasm-func?) 'func)
  350. ((? wasm-null?) 'null)
  351. ((? wasm-struct?) 'struct)
  352. ((? wasm-array?) 'array)
  353. (_ obj)))
  354. (let* ((wasm (validated-wasm-ref (wasm-instance-module instance)))
  355. (names (find names? (wasm-custom wasm)))
  356. (strings (wasm-strings wasm))
  357. (path (reverse path))
  358. (where (match path
  359. (('func idx . _)
  360. (func-name names idx))
  361. (('global idx . _)
  362. (global-name names idx))
  363. (('data idx . _)
  364. (data-name names idx))
  365. (('elem idx . _)
  366. (elem-name names idx))))
  367. (func-idx (match path
  368. (('func idx . _) idx)
  369. (_ #f)))
  370. (instr (match instr
  371. ;; Abbreviate blocks.
  372. (((and (or 'block 'loop) op) label type body)
  373. `(,op ,@(block-type-repr names type) ...))
  374. (('if label type consequent alternate)
  375. `(if ,@(block-type-repr names type) ...))
  376. (('try label type body catches catch-all)
  377. `(try ,@(block-type-repr names type) ...))
  378. (('try_delegate label type body handler)
  379. `(try_delegate ,@(block-type-repr names type) ...))
  380. (_ (instruction-repr instr names strings func-idx)))))
  381. (format #t "⌄ instr: ~a\n" instr)
  382. (format #t " where: ~a @ ~a\n" instance where)
  383. (format #t " stack: ~s\n" (map obj-abbrev (wasm-stack-items stack)))
  384. (format #t " locals: ~a\n" (map obj-abbrev (vector->list locals)))))
  385. (define (->wasm x)
  386. (match x
  387. ((? wasm? wasm) wasm)
  388. ((? validated-wasm? mod) (validated-wasm-ref mod))
  389. ((? wasm-instance? instance)
  390. (validated-wasm-ref (wasm-instance-module instance)))
  391. ((? hoot-module? mod)
  392. (validated-wasm-ref
  393. (wasm-instance-module
  394. (hoot-module-instance mod))))))
  395. (define-record-type <wasm-debug>
  396. (make-wasm-debug position instruction instance stack blocks locals)
  397. wasm-debug?
  398. (position wasm-debug-position)
  399. (instruction wasm-debug-instruction)
  400. (instance wasm-debug-instance)
  401. (stack wasm-debug-stack)
  402. (blocks wasm-debug-blocks)
  403. (locals wasm-debug-locals)
  404. (continue? wasm-debug-continue? set-wasm-debug-continue!))
  405. (define current-wasm-debug (make-parameter #f))
  406. (define-syntax-rule (when-debugging body ...)
  407. (if (current-wasm-debug)
  408. (begin body ...)
  409. (error "not in a WASM debugger")))
  410. ;; This code is based on error-string in (system repl
  411. ;; exception-handling) and adapted to work with Guile's new exception
  412. ;; objects.
  413. (define (error-message exn stack)
  414. (let ((key (exception-kind exn))
  415. (args (exception-args exn)))
  416. (call-with-output-string
  417. (lambda (port)
  418. (let ((frame (and (< 0 (vector-length stack)) (vector-ref stack 0))))
  419. (print-exception port frame key args))))))
  420. (define (enter-wasm-debugger exn)
  421. (let* ((tag (and (pair? (fluid-ref %stacks))
  422. (cdr (fluid-ref %stacks))))
  423. (stack (stack->vector (make-stack #t 3 tag 0 1)))
  424. (msg (error-message exn stack))
  425. (wasm-debug (make-wasm-debug (wasm-runtime-error-position exn)
  426. (wasm-runtime-error-instruction exn)
  427. (wasm-runtime-error-instance exn)
  428. (wasm-runtime-error-stack exn)
  429. (wasm-runtime-error-blocks exn)
  430. (wasm-runtime-error-locals exn))))
  431. (parameterize ((current-wasm-debug wasm-debug))
  432. (format #t "~a\n" msg)
  433. (format #t "Entering WASM debug prompt. ")
  434. (format #t "Type `,help wasm' for info or `,q' to continue.\n")
  435. (start-repl #:debug (make-debug stack 0 msg))
  436. (wasm-debug-continue? wasm-debug))))
  437. (define (wasm-step position instruction instance stack blocks locals)
  438. (let ((wasm-debug (make-wasm-debug (reverse position) instruction instance stack
  439. blocks locals)))
  440. (parameterize ((current-wasm-debug wasm-debug))
  441. (format #t "Instruction: ~a\n" instruction)
  442. (format #t "Location: ~a\n" (reverse position))
  443. (start-repl))))
  444. (define (reset-instruction-listener)
  445. (current-instruction-listener
  446. (lambda (position instr instance stack blocks locals) #t)))
  447. (define (continue)
  448. (set-wasm-debug-continue! (current-wasm-debug) #t)
  449. (throw 'quit))
  450. (define-meta-command ((wasm-dump wasm) repl #:optional exp)
  451. "wasm-dump [WASM]
  452. Display information about WASM, or the current WASM instance when debugging."
  453. (dump-wasm (->wasm
  454. (cond
  455. (exp (repl-eval repl exp))
  456. ((current-wasm-debug) => wasm-debug-instance)
  457. (else (error "no WASM object specified"))))
  458. #:dump-func-defs? #f))
  459. (define-meta-command ((wasm-disassemble wasm) repl #:optional exp)
  460. "wasm-disassemble [WASM]
  461. Display the disassembly of WASM, or the current WASM instance when debugging."
  462. (pretty-print
  463. (wasm->wat
  464. (unresolve-wasm
  465. (->wasm
  466. (cond
  467. (exp (repl-eval repl exp))
  468. ((current-wasm-debug) => wasm-debug-instance)
  469. (else (error "no WASM object specified"))))))))
  470. (define-meta-command ((wasm-trace wasm) repl exp)
  471. "wasm-trace EXP
  472. Evaluate EXP with verbose WASM tracing enabled."
  473. (with-exception-handling
  474. (parameterize ((current-instruction-listener wasm-trace))
  475. (call-with-values (lambda () (repl-eval repl exp))
  476. (lambda vals
  477. (for-each (lambda (v) (repl-print repl v)) vals))))))
  478. (define-meta-command ((wasm-freq wasm) repl exp)
  479. "wasm-freq EXP
  480. Evaluate EXP and count how many times each WASM instruction is evaluated."
  481. (let ((count 0)
  482. (histogram (make-hash-table)))
  483. (define (wasm-stats path instr instance stack blocks locals)
  484. (set! count (+ count 1))
  485. (match instr
  486. ((op . _)
  487. (hashq-set! histogram op (+ (hashq-ref histogram op 0) 1)))))
  488. (with-exception-handling
  489. (parameterize ((current-instruction-listener wasm-stats))
  490. (call-with-values (lambda () (repl-eval repl exp))
  491. (lambda vals
  492. (display "op\tcount\n")
  493. (display "--\t-----\n")
  494. (for-each (match-lambda
  495. ((op . k)
  496. (format #t "~a\t~a\n" op k)))
  497. (sort (hash-fold alist-cons '() histogram)
  498. (lambda (a b) (< (cdr a) (cdr b)))))
  499. (format #t "\n~a instructions total\n\n" count)
  500. (for-each (lambda (v) (repl-print repl v)) vals)))))))
  501. (define-meta-command ((wasm-catch wasm) repl exp)
  502. "wasm-catch EXP
  503. Catch and debug WASM runtime errors that are raised by evaluating EXP."
  504. (let ((thunk (repl-prepare-eval-thunk repl exp)))
  505. (call/ec
  506. (lambda (return)
  507. (with-exception-handler (lambda (exn)
  508. (if (wasm-runtime-error? exn)
  509. (unless (enter-wasm-debugger exn)
  510. (reset-instruction-listener)
  511. (return))
  512. (raise-exception exn)))
  513. (lambda ()
  514. (call-with-values (lambda () (%start-stack #t thunk))
  515. (lambda vals
  516. (reset-instruction-listener)
  517. (for-each (lambda (v) (repl-print repl v)) vals)))))))))
  518. (define-meta-command ((wasm-stack wasm) repl)
  519. "wasm-stack
  520. Print the state of the WASM stack in the current context."
  521. (when-debugging
  522. (print-stack (wasm-debug-stack (current-wasm-debug)))))
  523. (define-meta-command ((wasm-locals wasm) repl)
  524. "wasm-locals
  525. Print the state of the WASM locals in the current context."
  526. (when-debugging
  527. (print-locals (wasm-debug-locals (current-wasm-debug)))))
  528. (define-meta-command ((wasm-pos wasm) repl)
  529. "wasm-pos
  530. Highlight the instruction where WASM execution has paused."
  531. (when-debugging
  532. (let ((debug (current-wasm-debug)))
  533. (print-location (->wasm (wasm-debug-instance debug)) (wasm-debug-position debug)))))
  534. (define-meta-command ((wasm-eval wasm) repl instr)
  535. "wasm-eval INSTR
  536. Evaluate the WASM instruction INSTR in the current debug context."
  537. (when-debugging
  538. (let ((execute (@@ (wasm vm) execute)))
  539. (match (current-wasm-debug)
  540. (($ <wasm-debug> position _ instance stack blocks locals)
  541. (execute (repl-eval repl instr) position instance stack blocks locals))))))
  542. (define-meta-command ((wasm-continue wasm) repl)
  543. "wasm-continue
  544. Set WASM execution to continue without interruption until the next error."
  545. (when-debugging
  546. (reset-instruction-listener)
  547. (when (current-wasm-debug)
  548. (continue))))
  549. (define-meta-command ((wasm-step wasm) repl)
  550. "wasm-step
  551. Set WASM execution to pause before each instruction."
  552. (when-debugging
  553. (current-instruction-listener wasm-step)
  554. (when (current-wasm-debug)
  555. (continue))))