1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-05-29 16:30:19 +02:00
guile/module/system/vm/trace.scm
Andy Wingo b636cdb0f3 Frame pointer points to local 0 instead of local 1
* libguile/frames.h: Change so that fp points at local 0 instead of
  local 1, and clean up a bit.
  (struct scm_vm_frame): Remove program, and rename stack to locals.
  (SCM_FRAME_DATA_ADDRESS): Remove; it was redundant with
  SCM_FRAME_LOWER_ADDRESS.
  (SCM_FRAME_STACK_ADDRESS): Remove; replace with the new
  SCM_FRAME_LOCALS_ADDRESS.
  (SCM_FRAME_UPPER_ADDRESS): Remove; unused.
  (SCM_FRAME_NUM_LOCALS, SCM_FRAME_PREVIOUS_SP): New defines.
  (SCM_FRAME_BYTE_CAST, SCM_FRAME_STACK_CAST): Remove; unused;
  (SCM_FRAME_LOCAL): New define, replaces SCM_FRAME_VARIABLE.
  (SCM_FRAME_PROGRAM): Add cautionary commentary.

* libguile/frames.c: Adapt static asserts.
  (scm_frame_num_locals, scm_frame_local_ref, scm_frame_local_set_x):
  Adapt.  This means that frame-local-ref 0 now returns the procedure.

* libguile/vm-engine.c (ALLOC_FRAME, RESET_FRAME)
  (FRAME_LOCALS_COUNT, LOCAL_REF, LOCAL_SET, RETURN_VALUE_LIST): Adapt
  to change in fp.
  (LOCAL_ADDRESS): New helper.
  (POP_CONTINUATION_HOOK): Reimplement, taking the previous FP as an
  argument.
  (ABORT_CONTINUATION_HOOK): Reimplement, taking no arguments.
  (RETURN_ONE_VALUE): Reimplement.
  (RETURN_VALUE_LIST): Adapt to FP change.
  (halt, return-values, subr-call, foreign-call, prompt)
  (continuation-call, compose-continuation, call/cc, abort): Adapt to FP
  change, mostly via using LOCAL_ADDRESS, etc abstractions instead of
  using the raw frame pointer.

* libguile/control.c (reify_partial_continuation): Update for fp
  change.

* libguile/vm.c (vm_reinstate_partial_continuation): Adapt to removal of
  SCM_FRAME_UPPER_ADDRESS.

* module/system/vm/frame.scm (frame-call-representation): Adapt to
  frame-local-ref change.

* module/system/vm/trace.scm (print-return): Remove unused
  frame-num-locals call.
2013-11-17 22:07:44 +01:00

125 lines
5 KiB
Scheme

;;; Guile VM tracer
;; Copyright (C) 2001, 2009, 2010, 2012, 2013 Free Software Foundation, Inc.
;;; This library is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU Lesser General Public
;;; License as published by the Free Software Foundation; either
;;; version 3 of the License, or (at your option) any later version.
;;;
;;; This library is distributed in the hope that it will be useful,
;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
;;; Lesser General Public License for more details.
;;;
;;; You should have received a copy of the GNU Lesser General Public
;;; License along with this library; if not, write to the Free Software
;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
;;; Code:
(define-module (system vm trace)
#:use-module (system base syntax)
#:use-module (system vm vm)
#:use-module (system vm frame)
#:use-module (system vm program)
#:use-module (system vm traps)
#:use-module (rnrs bytevectors)
#:use-module (system vm instruction)
#:use-module (ice-9 format)
#:export (trace-calls-in-procedure
trace-calls-to-procedure
trace-instructions-in-procedure
call-with-trace))
(define (build-prefix prefix depth infix numeric-format max-indent)
(let lp ((indent "") (n 0))
(cond
((= n depth)
(string-append prefix indent))
((< (+ (string-length indent) (string-length infix)) max-indent)
(lp (string-append indent infix) (1+ n)))
(else
(string-append prefix indent (format #f numeric-format depth))))))
(define (print-application frame depth width prefix max-indent)
(let ((prefix (build-prefix prefix depth "| " "~d> " max-indent)))
(format (current-error-port) "~a~v:@y\n"
prefix
width
(frame-call-representation frame))))
(define* (print-return frame depth width prefix max-indent values)
(let ((prefix (build-prefix prefix depth "| " "~d< "max-indent)))
(case (length values)
((0)
(format (current-error-port) "~ano values\n" prefix))
((1)
(format (current-error-port) "~a~v:@y\n"
prefix
width
(car values)))
(else
;; this should work, but there appears to be a bug
;; "~a~d values:~:{ ~v:@y~}\n"
(format (current-error-port) "~a~d values:~{ ~a~}\n"
prefix (length values)
(map (lambda (val)
(format #f "~v:@y" width val))
values))))))
(define* (trace-calls-to-procedure proc #:key (width 80) (vm (the-vm))
(prefix "trace: ")
(max-indent (- width 40)))
(define (apply-handler frame depth)
(print-application frame depth width prefix max-indent))
(define (return-handler frame depth . values)
(print-return frame depth width prefix max-indent values))
(trap-calls-to-procedure proc apply-handler return-handler
#:vm vm))
(define* (trace-calls-in-procedure proc #:key (width 80) (vm (the-vm))
(prefix "trace: ")
(max-indent (- width 40)))
(define (apply-handler frame depth)
(print-application frame depth width prefix max-indent))
(define (return-handler frame depth . values)
(print-return frame depth width prefix max-indent values))
(trap-calls-in-dynamic-extent proc apply-handler return-handler
#:vm vm))
(define* (trace-instructions-in-procedure proc #:key (width 80) (vm (the-vm))
(max-indent (- width 40)))
(define (trace-next frame)
;; FIXME: We could disassemble this instruction here.
(let ((ip (frame-instruction-pointer frame)))
(format #t "0x~x\n" ip)))
(trap-instructions-in-dynamic-extent proc trace-next
#:vm vm))
;; Note that because this procedure manipulates the VM trace level
;; directly, it doesn't compose well with traps at the REPL.
;;
(define* (call-with-trace thunk #:key (calls? #t) (instructions? #f)
(width 80) (vm (the-vm)) (max-indent (- width 40)))
(let ((call-trap #f)
(inst-trap #f))
(dynamic-wind
(lambda ()
(if calls?
(set! call-trap
(trace-calls-in-procedure thunk #:vm vm #:width width
#:max-indent max-indent)))
(if instructions?
(set! inst-trap
(trace-instructions-in-procedure thunk #:vm vm #:width width
#:max-indent max-indent)))
(set-vm-trace-level! vm (1+ (vm-trace-level vm))))
thunk
(lambda ()
(set-vm-trace-level! vm (1- (vm-trace-level vm)))
(if call-trap (call-trap))
(if inst-trap (inst-trap))
(set! call-trap #f)
(set! inst-trap #f)))))