1
Fork 0
mirror of https://git.savannah.gnu.org/git/guile.git synced 2025-06-10 22:10:21 +02:00

procedure traps can fire on nested procedures

* module/system/vm/traps.scm (frame-matcher): New helper.
  (trap-at-procedure-call, trap-in-procedure, trap-in-dynamic-extent)
  (trap-calls-in-dynamic-extent, trap-instructions-in-dynamic-extent)
  (trap-instructions-in-procedure, trap-at-procedure-ip-in-range): Add
  ability to trap on procedures that are closures.

  (trap-at-source-location): Check source-closures first, to catch
  source locations that are in nested procedures.
This commit is contained in:
Andy Wingo 2010-09-23 18:09:50 +02:00
parent 783eeee657
commit f4a23f910f

View file

@ -106,14 +106,27 @@
(define (new-enabled-trap vm frame enable disable)
((new-disabled-trap vm enable disable) frame))
(define (frame-matcher proc match-objcode?)
(if match-objcode?
(lambda (frame)
(let ((frame-proc (frame-procedure frame)))
(or (eq? frame-proc proc)
(and (program? frame-proc)
(eq? (program-objcode frame-proc)
(program-objcode proc))))))
(lambda (frame)
(eq? (frame-procedure frame) proc))))
;; A basic trap, fires when a procedure is called.
;;
(define* (trap-at-procedure-call proc handler #:key (vm (the-vm)))
(define* (trap-at-procedure-call proc handler #:key (vm (the-vm))
(closure? #f)
(our-frame? (frame-matcher proc closure?)))
(arg-check proc procedure?)
(arg-check handler procedure?)
(let ()
(define (apply-hook frame)
(if (eq? (frame-procedure frame) proc)
(if (our-frame? frame)
(handler frame)))
(new-enabled-trap
@ -138,7 +151,9 @@
;; * An abort.
;;
(define* (trap-in-procedure proc enter-handler exit-handler
#:key current-frame (vm (the-vm)))
#:key current-frame (vm (the-vm))
(closure? #f)
(our-frame? (frame-matcher proc closure?)))
(arg-check proc procedure?)
(arg-check enter-handler procedure?)
(arg-check exit-handler procedure?)
@ -160,7 +175,7 @@
(define (apply-hook frame)
(if in-proc?
(exit-proc frame))
(if (eq? (frame-procedure frame) proc)
(if (our-frame? frame)
(enter-proc frame)))
(define (push-cont-hook frame)
@ -170,19 +185,19 @@
(define (pop-cont-hook frame)
(if in-proc?
(exit-proc frame))
(if (eq? (frame-procedure (frame-previous frame)) proc)
(if (our-frame? (frame-previous frame))
(enter-proc frame)))
(define (abort-hook frame)
(if in-proc?
(exit-proc frame))
(if (eq? (frame-procedure frame) proc)
(if (our-frame? frame)
(enter-proc frame)))
(define (restore-hook frame)
(if in-proc?
(exit-proc frame))
(if (eq? (frame-procedure frame) proc)
(if (our-frame? frame)
(enter-proc frame)))
(new-enabled-trap
@ -193,7 +208,7 @@
(add-hook! (vm-pop-continuation-hook vm) pop-cont-hook)
(add-hook! (vm-abort-continuation-hook vm) abort-hook)
(add-hook! (vm-restore-continuation-hook vm) restore-hook)
(if (and frame (eq? (frame-procedure frame) proc))
(if (and frame (our-frame? frame))
(enter-proc frame)))
(lambda (frame)
(if in-proc?
@ -207,13 +222,16 @@
;; Building on trap-in-procedure, we have trap-instructions-in-procedure
;;
(define* (trap-instructions-in-procedure proc next-handler exit-handler
#:key current-frame (vm (the-vm)))
#:key current-frame (vm (the-vm))
(closure? #f)
(our-frame?
(frame-matcher proc closure?)))
(arg-check proc procedure?)
(arg-check next-handler procedure?)
(arg-check exit-handler procedure?)
(let ()
(define (next-hook frame)
(if (eq? (frame-procedure frame) proc)
(if (our-frame? frame)
(next-handler frame)))
(define (enter frame)
@ -225,7 +243,8 @@
(remove-hook! (vm-next-hook vm) next-hook))
(trap-in-procedure proc enter exit
#:current-frame current-frame #:vm vm)))
#:current-frame current-frame #:vm vm
#:our-frame? our-frame?)))
(define (non-negative-integer? x)
(and (number? x) (integer? x) (exact? x) (not (negative? x))))
@ -247,7 +266,10 @@
;; trap-instructions-in-procedure.
;;
(define* (trap-at-procedure-ip-in-range proc range handler
#:key current-frame (vm (the-vm)))
#:key current-frame (vm (the-vm))
(closure? #f)
(our-frame?
(frame-matcher proc closure?)))
(arg-check proc procedure?)
(arg-check range range?)
(arg-check handler procedure?)
@ -262,7 +284,8 @@
(set! was-in-range? #f))
(trap-instructions-in-procedure proc next-handler exit-handler
#:current-frame current-frame #:vm vm)))
#:current-frame current-frame #:vm vm
#:our-frame? our-frame?)))
;; FIXME: define this in objcode somehow. We are reffing the first
;; uint32 in the objcode, which is the length of the program (without
@ -315,6 +338,12 @@
(warn "no instructions found for" file ":" line)
'())))
(define (source-closures-or-procedures file line)
(let ((closures (source-closures file line)))
(if (pair? closures)
(values closures #t)
(values (source-procedures file line) #f))))
;; Building on trap-on-instructions-in-procedure, we have
;; trap-at-source-location.
;;
@ -324,21 +353,26 @@
(arg-check line non-negative-integer?)
(arg-check handler procedure?)
(let ((traps #f))
(new-enabled-trap
vm current-frame
(lambda (frame)
(set! traps (map
(lambda (proc)
(let ((range (source->ip-range proc file line)))
(trap-at-procedure-ip-in-range proc range handler
#:current-frame current-frame
#:vm vm)))
(source-procedures file line)))
(if (null? traps)
(error "No procedures found at ~a:~a." file line)))
(lambda (frame)
(for-each (lambda (trap) (trap frame)) traps)
(set! traps #f)))))
(call-with-values
(lambda () (source-closures-or-procedures file line))
(lambda (procs closures?)
(new-enabled-trap
vm current-frame
(lambda (frame)
(set! traps
(map
(lambda (proc)
(let ((range (source->ip-range proc file line)))
(trap-at-procedure-ip-in-range proc range handler
#:current-frame current-frame
#:vm vm
#:closure? closures?)))
procs))
(if (null? traps)
(error "No procedures found at ~a:~a." file line)))
(lambda (frame)
(for-each (lambda (trap) (trap frame)) traps)
(set! traps #f)))))))
@ -382,7 +416,9 @@
;; based on the above trap-frame-finish?
;;
(define* (trap-in-dynamic-extent proc enter-handler return-handler abort-handler
#:key current-frame (vm (the-vm)))
#:key current-frame (vm (the-vm))
(closure? #f)
(our-frame? (frame-matcher proc closure?)))
(arg-check proc procedure?)
(arg-check enter-handler procedure?)
(arg-check return-handler procedure?)
@ -399,8 +435,7 @@
(abort-handler frame))
(define (apply-hook frame)
(if (and (not exit-trap)
(eq? (frame-procedure frame) proc))
(if (and (not exit-trap) (our-frame? frame))
(begin
(enter-handler frame)
(set! exit-trap
@ -421,7 +456,10 @@
;; depth of the call stack relative to the original procedure.
;;
(define* (trap-calls-in-dynamic-extent proc apply-handler return-handler
#:key current-frame (vm (the-vm)))
#:key current-frame (vm (the-vm))
(closure? #f)
(our-frame?
(frame-matcher proc closure?)))
(arg-check proc procedure?)
(arg-check apply-handler procedure?)
(arg-check return-handler procedure?)
@ -455,12 +493,16 @@
(leave frame))
(trap-in-dynamic-extent proc enter return abort
#:current-frame current-frame #:vm vm)))
#:current-frame current-frame #:vm vm
#:our-frame? our-frame?)))
;; Trapping all retired intructions within a dynamic extent.
;;
(define* (trap-instructions-in-dynamic-extent proc next-handler
#:key current-frame (vm (the-vm)))
#:key current-frame (vm (the-vm))
(closure? #f)
(our-frame?
(frame-matcher proc closure?)))
(arg-check proc procedure?)
(arg-check next-handler procedure?)
(let ()
@ -480,7 +522,8 @@
(leave frame))
(trap-in-dynamic-extent proc enter return abort
#:current-frame current-frame #:vm vm)))
#:current-frame current-frame #:vm vm
#:our-frame? our-frame?)))
;; Traps calls and returns for a given procedure, keeping track of the call depth.
;;