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

pop-continuation abort-continuation hooks pass return vals directly

* doc/ref/api-debug.texi (VM Hooks): Update documentation.

* libguile/vm.c (vm_dispatch_hook):
* libguile/vm-engine.c:  Rework the hook machinery so that they can
  receive an arbitrary number of arguments.  The return and abort
  hooks will pass the values that they return to their continuations.
  (vm_engine): Adapt to ABORT_CONTINUATION_HOOK change.

* libguile/vm-i-system.c (return, return/values): Adapt to
  POP_CONTINUATION_HOOK change.

* module/system/vm/frame.scm (frame-return-values): Remove.  The
  pop-continuation-hook will pass the values directly.

* module/system/vm/trace.scm (print-return):
  (trace-calls-to-procedure):
  (trace-calls-in-procedure): Update to receive return values
  directly.

* module/system/vm/traps.scm (trap-in-procedure)
  (trap-in-dynamic-extent): Ignore return values.
  (trap-frame-finish, trap-calls-in-dynamic-extent)
  (trap-calls-to-procedure): Pass return values to the handlers.
This commit is contained in:
Andy Wingo 2013-05-23 15:07:37 +02:00
parent 27319ffaa9
commit c850a0ff4d
8 changed files with 111 additions and 112 deletions

View file

@ -799,10 +799,11 @@ To digress, Guile's VM has 6 different hooks (@pxref{Hooks}) that can be
fired at different times, which may be accessed with the following fired at different times, which may be accessed with the following
procedures. procedures.
All hooks are called with one argument, the frame in The first argument of calls to these hooks is the frame in question.
question. @xref{Frames}. Since these hooks may be fired very @xref{Frames}. Some hooks may call their procedures with more
frequently, Guile does a terrible thing: it allocates the frames on the arguments. Since these hooks may be fired very frequently, Guile does a
C stack instead of the garbage-collected heap. terrible thing: it allocates the frames on the C stack instead of the
garbage-collected heap.
The upshot here is that the frames are only valid within the dynamic The upshot here is that the frames are only valid within the dynamic
extent of the call to the hook. If a hook procedure keeps a reference to extent of the call to the hook. If a hook procedure keeps a reference to
@ -832,11 +833,8 @@ corresponding apply-hook.
@deffn {Scheme Procedure} vm-pop-continuation-hook vm @deffn {Scheme Procedure} vm-pop-continuation-hook vm
The hook that will be fired before returning from a frame. The hook that will be fired before returning from a frame.
This hook is a bit trickier than the rest, in that there is a particular This hook fires with a variable number of arguments, corresponding to
interpretation of the values on the stack. Specifically, the top value the values that the frame returns to its continuation.
on the stack is the number of values being returned, and the next
@var{n} values are the actual values being returned, with the last value
highest on the stack.
@end deffn @end deffn
@deffn {Scheme Procedure} vm-apply-hook vm @deffn {Scheme Procedure} vm-apply-hook vm
@ -852,8 +850,11 @@ hook.
@deffn {Scheme Procedure} vm-abort-continuation-hook vm @deffn {Scheme Procedure} vm-abort-continuation-hook vm
The hook that will be called after aborting to a The hook that will be called after aborting to a
prompt. @xref{Prompts}. The stack will be in the same state as for prompt. @xref{Prompts}.
@code{vm-pop-continuation-hook}.
Like the pop-continuation hook, this hook fires with a variable number
of arguments, corresponding to the values that returned to the
continuation.
@end deffn @end deffn
@deffn {Scheme Procedure} vm-restore-continuation-hook vm @deffn {Scheme Procedure} vm-restore-continuation-hook vm

View file

@ -68,6 +68,38 @@
# define ASSERT(condition) # define ASSERT(condition)
#endif #endif
#if VM_USE_HOOKS
#define RUN_HOOK(h, args, n) \
do { \
if (SCM_UNLIKELY (vp->trace_level > 0)) \
{ \
SYNC_REGISTER (); \
vm_dispatch_hook (vm, h, args, n); \
} \
} while (0)
#else
#define RUN_HOOK(h, args, n)
#endif
#define RUN_HOOK0(h) RUN_HOOK(h, NULL, 0)
#define APPLY_HOOK() \
RUN_HOOK0 (SCM_VM_APPLY_HOOK)
#define PUSH_CONTINUATION_HOOK() \
RUN_HOOK0 (SCM_VM_PUSH_CONTINUATION_HOOK)
#define POP_CONTINUATION_HOOK(vals, n) \
RUN_HOOK (SCM_VM_POP_CONTINUATION_HOOK, vals, n)
#define NEXT_HOOK() \
RUN_HOOK0 (SCM_VM_NEXT_HOOK)
#define ABORT_CONTINUATION_HOOK(vals, n) \
RUN_HOOK (SCM_VM_ABORT_CONTINUATION_HOOK, vals, n)
#define RESTORE_CONTINUATION_HOOK() \
RUN_HOOK0 (SCM_VM_RESTORE_CONTINUATION_HOOK)
#define VM_HANDLE_INTERRUPTS \
SCM_ASYNC_TICK_WITH_CODE (current_thread, SYNC_REGISTER ())
/* Cache the VM's instruction, stack, and frame pointer in local variables. */ /* Cache the VM's instruction, stack, and frame pointer in local variables. */
#define CACHE_REGISTER() \ #define CACHE_REGISTER() \
@ -141,51 +173,6 @@
#define CHECK_OBJECT(_num) #define CHECK_OBJECT(_num)
#define CHECK_FREE_VARIABLE(_num) #define CHECK_FREE_VARIABLE(_num)
/*
* Hooks
*/
#if VM_USE_HOOKS
#define RUN_HOOK(h) \
{ \
if (SCM_UNLIKELY (vp->trace_level > 0)) \
{ \
SYNC_REGISTER (); \
vm_dispatch_hook (vm, h); \
} \
}
#define RUN_HOOK1(h, x) \
{ \
if (SCM_UNLIKELY (vp->trace_level > 0)) \
{ \
PUSH (x); \
SYNC_REGISTER (); \
vm_dispatch_hook (vm, h); \
DROP(); \
} \
}
#else
#define RUN_HOOK(h)
#define RUN_HOOK1(h, x)
#endif
#define APPLY_HOOK() \
RUN_HOOK (SCM_VM_APPLY_HOOK)
#define PUSH_CONTINUATION_HOOK() \
RUN_HOOK (SCM_VM_PUSH_CONTINUATION_HOOK)
#define POP_CONTINUATION_HOOK(n) \
RUN_HOOK1 (SCM_VM_POP_CONTINUATION_HOOK, SCM_I_MAKINUM (n))
#define NEXT_HOOK() \
RUN_HOOK (SCM_VM_NEXT_HOOK)
#define ABORT_CONTINUATION_HOOK() \
RUN_HOOK (SCM_VM_ABORT_CONTINUATION_HOOK)
#define RESTORE_CONTINUATION_HOOK() \
RUN_HOOK (SCM_VM_RESTORE_CONTINUATION_HOOK)
#define VM_HANDLE_INTERRUPTS \
SCM_ASYNC_TICK_WITH_CODE (current_thread, SYNC_REGISTER ())
/* /*
* Stack operation * Stack operation
@ -352,7 +339,7 @@ VM_NAME (SCM vm, SCM program, SCM *argv, int nargs)
CACHE_PROGRAM (); CACHE_PROGRAM ();
/* The stack contains the values returned to this continuation, /* The stack contains the values returned to this continuation,
along with a number-of-values marker -- like an MV return. */ along with a number-of-values marker -- like an MV return. */
ABORT_CONTINUATION_HOOK (); ABORT_CONTINUATION_HOOK (sp - SCM_I_INUM (*sp), SCM_I_INUM (*sp));
NEXT; NEXT;
} }

View file

@ -1150,7 +1150,7 @@ VM_DEFINE_INSTRUCTION (68, tail_call_cc, "tail-call/cc", 0, 1, 1)
VM_DEFINE_INSTRUCTION (69, return, "return", 0, 1, 1) VM_DEFINE_INSTRUCTION (69, return, "return", 0, 1, 1)
{ {
vm_return: vm_return:
POP_CONTINUATION_HOOK (1); POP_CONTINUATION_HOOK (sp, 1);
VM_HANDLE_INTERRUPTS; VM_HANDLE_INTERRUPTS;
@ -1189,7 +1189,7 @@ VM_DEFINE_INSTRUCTION (70, return_values, "return/values", 1, -1, -1)
that perhaps it might be used without declaration. Fooey to that, I say. */ that perhaps it might be used without declaration. Fooey to that, I say. */
nvalues = FETCH (); nvalues = FETCH ();
vm_return_values: vm_return_values:
POP_CONTINUATION_HOOK (nvalues); POP_CONTINUATION_HOOK (sp + 1 - nvalues, nvalues);
VM_HANDLE_INTERRUPTS; VM_HANDLE_INTERRUPTS;

View file

@ -202,14 +202,16 @@ scm_i_capture_current_stack (void)
0); 0);
} }
static void vm_dispatch_hook (SCM vm, int hook_num,
SCM *argv, int n) SCM_NOINLINE;
static void static void
vm_dispatch_hook (SCM vm, int hook_num) vm_dispatch_hook (SCM vm, int hook_num, SCM *argv, int n)
{ {
struct scm_vm *vp; struct scm_vm *vp;
SCM hook; SCM hook;
struct scm_frame c_frame; struct scm_frame c_frame;
scm_t_cell *frame; scm_t_cell *frame;
SCM args[1];
int saved_trace_level; int saved_trace_level;
vp = SCM_VM_DATA (vm); vp = SCM_VM_DATA (vm);
@ -242,9 +244,30 @@ vm_dispatch_hook (SCM vm, int hook_num)
frame->word_0 = SCM_PACK (scm_tc7_frame); frame->word_0 = SCM_PACK (scm_tc7_frame);
frame->word_1 = SCM_PACK_POINTER (&c_frame); frame->word_1 = SCM_PACK_POINTER (&c_frame);
args[0] = SCM_PACK_POINTER (frame);
scm_c_run_hookn (hook, args, 1); if (n == 0)
{
SCM args[1];
args[0] = SCM_PACK_POINTER (frame);
scm_c_run_hookn (hook, args, 1);
}
else if (n == 1)
{
SCM args[2];
args[0] = SCM_PACK_POINTER (frame);
args[1] = argv[0];
scm_c_run_hookn (hook, args, 2);
}
else
{
SCM args = SCM_EOL;
while (n--)
args = scm_cons (argv[n], args);
scm_c_run_hook (hook, scm_cons (SCM_PACK_POINTER (frame), args));
}
vp->trace_level = saved_trace_level; vp->trace_level = saved_trace_level;
} }

View file

@ -29,7 +29,6 @@
#:use-module (system vm program) #:use-module (system vm program)
#:use-module (system vm trap-state) #:use-module (system vm trap-state)
#:use-module (system vm vm) #:use-module (system vm vm)
#:use-module ((system vm frame) #:select (frame-return-values))
#:autoload (system base language) (lookup-language language-reader) #:autoload (system base language) (lookup-language language-reader)
#:autoload (system vm trace) (call-with-trace) #:autoload (system vm trace) (call-with-trace)
#:use-module (ice-9 format) #:use-module (ice-9 format)
@ -688,8 +687,8 @@ Note that the given source location must be inside a procedure."
(format #t "Trap ~a: ~a.~%" idx (trap-name idx))))) (format #t "Trap ~a: ~a.~%" idx (trap-name idx)))))
(define (repl-pop-continuation-resumer repl msg) (define (repl-pop-continuation-resumer repl msg)
;; Capture the dynamic environment with this prompt thing. The ;; Capture the dynamic environment with this prompt thing. The result
;; result is a procedure that takes a frame. ;; is a procedure that takes a frame and number of values returned.
(% (call-with-values (% (call-with-values
(lambda () (lambda ()
(abort (abort
@ -697,18 +696,18 @@ Note that the given source location must be inside a procedure."
;; Call frame->stack-vector before reinstating the ;; Call frame->stack-vector before reinstating the
;; continuation, so that we catch the %stacks fluid at ;; continuation, so that we catch the %stacks fluid at
;; the time of capture. ;; the time of capture.
(lambda (frame) (lambda (frame . values)
(k frame (k frame
(frame->stack-vector (frame->stack-vector
(frame-previous frame))))))) (frame-previous frame))
(lambda (from stack) values)))))
(lambda (from stack values)
(format #t "~a~%" msg) (format #t "~a~%" msg)
(let ((vals (frame-return-values from))) (if (null? values)
(if (null? vals) (format #t "No return values.~%")
(format #t "No return values.~%") (begin
(begin (format #t "Return values:~%")
(format #t "Return values:~%") (for-each (lambda (x) (repl-print repl x)) values)))
(for-each (lambda (x) (repl-print repl x)) vals))))
((module-ref (resolve-interface '(system repl repl)) 'start-repl) ((module-ref (resolve-interface '(system repl repl)) 'start-repl)
#:debug (make-debug stack 0 msg #t)))))) #:debug (make-debug stack 0 msg #t))))))

View file

@ -28,8 +28,7 @@
frame-binding-ref frame-binding-set! frame-binding-ref frame-binding-set!
frame-next-source frame-call-representation frame-next-source frame-call-representation
frame-environment frame-environment
frame-object-binding frame-object-name frame-object-binding frame-object-name))
frame-return-values))
(define (frame-bindings frame) (define (frame-bindings frame)
(let ((p (frame-procedure frame))) (let ((p (frame-procedure frame)))
@ -158,12 +157,3 @@
(define (frame-object-name frame obj) (define (frame-object-name frame obj)
(cond ((frame-object-binding frame obj) => binding:name) (cond ((frame-object-binding frame obj) => binding:name)
(else #f))) (else #f)))
;; Nota bene, only if frame is in a return context (i.e. in a
;; pop-continuation hook dispatch).
(define (frame-return-values frame)
(let* ((len (frame-num-locals frame))
(nvalues (frame-local-ref frame (1- len))))
(map (lambda (i)
(frame-local-ref frame (+ (- len nvalues 1) i)))
(iota nvalues))))

View file

@ -1,6 +1,6 @@
;;; Guile VM tracer ;;; Guile VM tracer
;; Copyright (C) 2001, 2009, 2010, 2013 Free Software Foundation, Inc. ;; Copyright (C) 2001, 2009, 2010, 2012, 2013 Free Software Foundation, Inc.
;;; This library is free software; you can redistribute it and/or ;;; This library is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU Lesser General Public ;;; modify it under the terms of the GNU Lesser General Public
@ -53,34 +53,33 @@
width width
(frame-call-representation frame)))) (frame-call-representation frame))))
(define* (print-return frame depth width prefix max-indent) (define* (print-return frame depth width prefix max-indent values)
(let* ((len (frame-num-locals frame)) (let* ((len (frame-num-locals frame))
(nvalues (frame-local-ref frame (1- len)))
(prefix (build-prefix prefix depth "| " "~d< "max-indent))) (prefix (build-prefix prefix depth "| " "~d< "max-indent)))
(case nvalues (case (length values)
((0) ((0)
(format (current-error-port) "~ano values\n" prefix)) (format (current-error-port) "~ano values\n" prefix))
((1) ((1)
(format (current-error-port) "~a~v:@y\n" (format (current-error-port) "~a~v:@y\n"
prefix prefix
width width
(frame-local-ref frame (- len 2)))) (car values)))
(else (else
;; this should work, but there appears to be a bug ;; this should work, but there appears to be a bug
;; "~a~d values:~:{ ~v:@y~}\n" ;; "~a~d values:~:{ ~v:@y~}\n"
(format (current-error-port) "~a~d values:~{ ~a~}\n" (format (current-error-port) "~a~d values:~{ ~a~}\n"
prefix nvalues prefix (length values)
(map (lambda (val) (map (lambda (val)
(format #f "~v:@y" width val)) (format #f "~v:@y" width val))
(frame-return-values frame))))))) values))))))
(define* (trace-calls-to-procedure proc #:key (width 80) (vm (the-vm)) (define* (trace-calls-to-procedure proc #:key (width 80) (vm (the-vm))
(prefix "trace: ") (prefix "trace: ")
(max-indent (- width 40))) (max-indent (- width 40)))
(define (apply-handler frame depth) (define (apply-handler frame depth)
(print-application frame depth width prefix max-indent)) (print-application frame depth width prefix max-indent))
(define (return-handler frame depth) (define (return-handler frame depth . values)
(print-return frame depth width prefix max-indent)) (print-return frame depth width prefix max-indent values))
(trap-calls-to-procedure proc apply-handler return-handler (trap-calls-to-procedure proc apply-handler return-handler
#:vm vm)) #:vm vm))
@ -89,8 +88,8 @@
(max-indent (- width 40))) (max-indent (- width 40)))
(define (apply-handler frame depth) (define (apply-handler frame depth)
(print-application frame depth width prefix max-indent)) (print-application frame depth width prefix max-indent))
(define (return-handler frame depth) (define (return-handler frame depth . values)
(print-return frame depth width prefix max-indent)) (print-return frame depth width prefix max-indent values))
(trap-calls-in-dynamic-extent proc apply-handler return-handler (trap-calls-in-dynamic-extent proc apply-handler return-handler
#:vm vm)) #:vm vm))

View file

@ -1,6 +1,6 @@
;;; Traps: stepping, breakpoints, and such. ;;; Traps: stepping, breakpoints, and such.
;; Copyright (C) 2010 Free Software Foundation, Inc. ;; Copyright (C) 2010, 2012 Free Software Foundation, Inc.
;;; This library is free software; you can redistribute it and/or ;;; This library is free software; you can redistribute it and/or
;;; modify it under the terms of the GNU Lesser General Public ;;; modify it under the terms of the GNU Lesser General Public
@ -184,13 +184,13 @@
(if in-proc? (if in-proc?
(exit-proc frame))) (exit-proc frame)))
(define (pop-cont-hook frame) (define (pop-cont-hook frame . values)
(if in-proc? (if in-proc?
(exit-proc frame)) (exit-proc frame))
(if (our-frame? (frame-previous frame)) (if (our-frame? (frame-previous frame))
(enter-proc (frame-previous frame)))) (enter-proc (frame-previous frame))))
(define (abort-hook frame) (define (abort-hook frame . values)
(if in-proc? (if in-proc?
(exit-proc frame)) (exit-proc frame))
(if (our-frame? frame) (if (our-frame? frame)
@ -409,17 +409,17 @@
(arg-check return-handler procedure?) (arg-check return-handler procedure?)
(arg-check abort-handler procedure?) (arg-check abort-handler procedure?)
(let ((fp (frame-address frame))) (let ((fp (frame-address frame)))
(define (pop-cont-hook frame) (define (pop-cont-hook frame . values)
(if (and fp (eq? (frame-address frame) fp)) (if (and fp (eq? (frame-address frame) fp))
(begin (begin
(set! fp #f) (set! fp #f)
(return-handler frame)))) (apply return-handler frame values))))
(define (abort-hook frame) (define (abort-hook frame . values)
(if (and fp (< (frame-address frame) fp)) (if (and fp (< (frame-address frame) fp))
(begin (begin
(set! fp #f) (set! fp #f)
(abort-handler frame)))) (apply abort-handler frame values))))
(new-enabled-trap (new-enabled-trap
vm frame vm frame
@ -447,12 +447,12 @@
(arg-check return-handler procedure?) (arg-check return-handler procedure?)
(arg-check abort-handler procedure?) (arg-check abort-handler procedure?)
(let ((exit-trap #f)) (let ((exit-trap #f))
(define (return-hook frame) (define (return-hook frame . values)
(exit-trap frame) ; disable the return/abort trap. (exit-trap frame) ; disable the return/abort trap.
(set! exit-trap #f) (set! exit-trap #f)
(return-handler frame)) (return-handler frame))
(define (abort-hook frame) (define (abort-hook frame . values)
(exit-trap frame) ; disable the return/abort trap. (exit-trap frame) ; disable the return/abort trap.
(set! exit-trap #f) (set! exit-trap #f)
(abort-handler frame)) (abort-handler frame))
@ -490,8 +490,8 @@
(define (trace-push frame) (define (trace-push frame)
(set! *call-depth* (1+ *call-depth*))) (set! *call-depth* (1+ *call-depth*)))
(define (trace-pop frame) (define (trace-pop frame . values)
(return-handler frame *call-depth*) (apply return-handler frame *call-depth* values)
(set! *call-depth* (1- *call-depth*))) (set! *call-depth* (1- *call-depth*)))
(define (trace-apply frame) (define (trace-apply frame)
@ -570,12 +570,12 @@
(delq finish-trap pending-finish-traps)) (delq finish-trap pending-finish-traps))
(set! finish-trap #f)) (set! finish-trap #f))
(define (return-hook frame) (define (return-hook frame . values)
(frame-finished frame) (frame-finished frame)
(return-handler frame depth)) (apply return-handler frame depth values))
;; FIXME: abort handler? ;; FIXME: abort handler?
(define (abort-hook frame) (define (abort-hook frame . values)
(frame-finished frame)) (frame-finished frame))
(set! finish-trap (set! finish-trap