factor/basis/tools/walker/walker.factor

268 lines
7.3 KiB
Factor
Raw Normal View History

2008-02-21 00:13:22 -05:00
! Copyright (C) 2004, 2008 Slava Pestov.
! See http://factorcode.org/license.txt for BSD license.
USING: threads kernel namespaces continuations combinators
sequences math namespaces.private continuations.private
concurrency.messaging quotations kernel.private words
2008-07-04 18:58:37 -04:00
sequences.private assocs models models.filter arrays accessors
generic generic.standard definitions ;
2008-02-21 00:13:22 -05:00
IN: tools.walker
2007-12-31 22:16:21 -05:00
2008-03-18 02:26:09 -04:00
SYMBOL: show-walker-hook ! ( status continuation thread -- )
2008-02-20 00:26:07 -05:00
2008-03-18 02:26:09 -04:00
! Thread local in thread being walked
2008-02-21 00:13:22 -05:00
SYMBOL: walker-thread
2008-03-18 02:26:09 -04:00
! Thread local in walker thread
2008-02-21 00:13:31 -05:00
SYMBOL: walking-thread
2008-03-18 02:26:09 -04:00
SYMBOL: walker-status
SYMBOL: walker-continuation
SYMBOL: walker-history
DEFER: start-walker-thread
2008-02-20 00:26:07 -05:00
2008-03-18 02:26:09 -04:00
: get-walker-thread ( -- status continuation thread )
2008-02-21 00:13:22 -05:00
walker-thread tget [
2008-08-30 13:35:14 -04:00
[ variables>> walker-status swap at ]
[ variables>> walker-continuation swap at ]
2008-03-18 02:26:09 -04:00
[ ] tri
2008-02-21 00:13:31 -05:00
] [
2008-03-18 02:26:09 -04:00
f <model>
f <model>
2dup start-walker-thread
2008-02-21 00:13:31 -05:00
] if* ;
2007-10-04 18:45:19 -04:00
2008-03-18 02:26:09 -04:00
: show-walker ( -- thread )
get-walker-thread
[ show-walker-hook get call ] keep ;
2008-02-21 00:13:31 -05:00
2008-03-18 02:26:09 -04:00
: after-break ( object -- )
{
2008-02-21 00:13:31 -05:00
{ [ dup continuation? ] [ (continue) ] }
{ [ dup quotation? ] [ call ] }
2008-03-19 15:25:53 -04:00
{ [ dup not ] [ "Single stepping abandoned" rethrow ] }
2008-02-21 00:13:31 -05:00
} cond ;
2008-03-18 02:26:09 -04:00
: break ( -- )
2008-08-30 13:35:14 -04:00
continuation callstack >>call
2008-03-18 02:26:09 -04:00
show-walker send-synchronous
after-break ;
2008-02-21 00:13:31 -05:00
\ break t "break?" set-word-prop
: walk ( quot -- quot' )
\ break prefix [ break rethrow ] recover ;
GENERIC: add-breakpoint ( quot -- quot' )
M: callable add-breakpoint
dup [ break ] head? [ \ break prefix ] unless ;
2007-09-20 18:09:08 -04:00
M: array add-breakpoint
[ add-breakpoint ] map ;
M: object add-breakpoint ;
: (step-into-quot) ( quot -- ) add-breakpoint call ;
2007-09-20 18:09:08 -04:00
2008-06-08 16:32:55 -04:00
: (step-into-if) ( true false ? -- ) ? (step-into-quot) ;
2008-02-21 00:13:31 -05:00
2008-06-08 16:32:55 -04:00
: (step-into-dispatch) ( array n -- ) nth (step-into-quot) ;
2008-02-21 00:13:31 -05:00
: (step-into-execute) ( word -- )
{
{ [ dup "step-into" word-prop ] [ "step-into" word-prop call ] }
{ [ dup standard-generic? ] [ effective-method (step-into-execute) ] }
2008-04-11 09:35:07 -04:00
{ [ dup hook-generic? ] [ effective-method (step-into-execute) ] }
{ [ dup uses \ suspend swap member? ] [ execute break ] }
{ [ dup primitive? ] [ execute break ] }
[ def>> (step-into-quot) ]
} cond ;
2008-02-21 00:13:31 -05:00
\ (step-into-execute) t "step-into?" set-word-prop
2008-06-08 16:32:55 -04:00
: (step-into-continuation) ( -- )
continuation callstack >>call break ;
2007-10-04 18:45:19 -04:00
: (step-into-call-next-method) ( class generic -- )
next-method-quot (step-into-quot) ;
2008-02-21 00:13:22 -05:00
! Messages sent to walker thread
2008-02-20 00:26:07 -05:00
SYMBOL: step
SYMBOL: step-out
SYMBOL: step-into
SYMBOL: step-all
2008-02-21 00:13:22 -05:00
SYMBOL: step-into-all
2008-02-20 00:26:07 -05:00
SYMBOL: step-back
SYMBOL: abandon
SYMBOL: call-in
2007-09-20 18:09:08 -04:00
2008-02-21 00:13:22 -05:00
SYMBOL: +running+
SYMBOL: +suspended+
SYMBOL: +stopped+
2008-02-20 00:26:07 -05:00
: change-frame ( continuation quot -- continuation' )
#! Applies quot to innermost call frame of the
#! continuation.
>r clone r> [
>r clone r>
[
>r
[ innermost-frame-scan 1+ ]
[ innermost-frame-quot ] bi
r> call
]
[ drop set-innermost-frame-quot ]
[ drop ]
2tri
] curry change-call ; inline
2008-02-20 00:26:07 -05:00
: step-msg ( continuation -- continuation' )
[
2dup nth \ break = [
nip
] [
swap 1+ cut [ break ] swap 3append
] if
] change-frame ;
: step-out-msg ( continuation -- continuation' )
[ nip \ break suffix ] change-frame ;
2008-02-20 00:26:07 -05:00
{
{ call [ (step-into-quot) ] }
{ (throw) [ drop (step-into-quot) ] }
{ execute [ (step-into-execute) ] }
{ if [ (step-into-if) ] }
{ dispatch [ (step-into-dispatch) ] }
2007-10-03 20:49:17 -04:00
{ continuation [ (step-into-continuation) ] }
{ (call-next-method) [ (step-into-call-next-method) ] }
} [ "step-into" set-word-prop ] assoc-each
{
>n ndrop >c c>
2007-10-03 20:49:17 -04:00
continue continue-with
stop suspend (spawn)
} [
dup [ execute break ] curry
"step-into" set-word-prop
] each
2007-09-20 18:09:08 -04:00
2007-10-09 01:30:28 -04:00
\ break [ break ] "step-into" set-word-prop
2008-02-20 00:26:07 -05:00
: step-into-msg ( continuation -- continuation' )
[
2007-10-12 16:30:36 -04:00
swap cut [
2008-02-21 00:13:31 -05:00
swap % unclip {
{ [ dup \ break eq? ] [ , ] }
{ [ dup quotation? ] [ add-breakpoint , \ break , ] }
{ [ dup array? ] [ add-breakpoint , \ break , ] }
2008-02-21 00:13:31 -05:00
{ [ dup word? ] [ literalize , \ (step-into-execute) , ] }
2008-04-11 13:57:43 -04:00
[ , \ break , ]
2008-02-21 00:13:31 -05:00
} cond %
] [ ] make
2008-02-21 00:13:22 -05:00
] change-frame ;
2007-10-04 18:45:19 -04:00
2008-02-21 00:13:22 -05:00
: status ( -- symbol )
walker-status tget model-value ;
: set-status ( symbol -- )
walker-status tget set-model ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:31 -05:00
: keep-running ( -- )
+running+ set-status ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: walker-stopped ( -- )
+stopped+ set-status ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: step-into-all-loop ( -- )
+running+ set-status
2008-02-21 00:13:31 -05:00
[ status +running+ eq? ] [
2008-02-21 00:13:22 -05:00
[
{
2008-02-21 02:25:59 -05:00
{ step [ f ] }
{ step-out [ f ] }
{ step-into [ f ] }
{ step-all [ f ] }
{ step-into-all [ f ] }
{ step-back [ f ] }
{ f [ +stopped+ set-status f ] }
[
[ walker-continuation tget set-model ]
[ step-into-msg ] bi
2008-02-21 02:25:59 -05:00
]
} case
2008-02-21 00:13:22 -05:00
] handle-synchronous
] [ ] while ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:31 -05:00
: step-back-msg ( continuation -- continuation' )
walker-history tget
[ pop* ]
[ dup empty? [ drop ] [ nip pop ] if ] bi ;
2008-02-21 00:13:31 -05:00
2008-02-21 00:13:22 -05:00
: walker-suspended ( continuation -- continuation' )
+suspended+ set-status
[ status +suspended+ eq? ] [
2008-02-21 00:13:31 -05:00
dup walker-history tget push
dup walker-continuation tget set-model
2008-02-20 00:26:07 -05:00
[
{
2008-02-21 00:13:22 -05:00
! These are sent by the walker tool. We reply
! and keep cycling.
{ step [ step-msg keep-running ] }
{ step-out [ step-out-msg keep-running ] }
{ step-into [ step-into-msg keep-running ] }
2008-02-20 00:26:07 -05:00
{ step-all [ keep-running ] }
2008-02-21 00:13:22 -05:00
{ step-into-all [ step-into-all-loop ] }
2008-02-20 00:26:07 -05:00
{ abandon [ drop f keep-running ] }
! Pass quotation to debugged thread
{ call-in [ nip keep-running ] }
! Pass previous continuation to debugged thread
2008-02-21 00:13:31 -05:00
{ step-back [ step-back-msg ] }
} case f
2008-02-20 00:26:07 -05:00
] handle-synchronous
2008-02-21 00:13:22 -05:00
] [ ] while ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: walker-loop ( -- )
+running+ set-status
2008-03-18 02:26:09 -04:00
[ status +stopped+ eq? not ] [
2008-02-20 00:26:07 -05:00
[
{
! ignore these commands while the thread is
! running
{ step [ f ] }
{ step-out [ f ] }
{ step-into [ f ] }
{ step-all [ f ] }
2008-02-21 00:13:31 -05:00
{ step-into-all [ step-into-all-loop f ] }
2008-02-20 00:26:07 -05:00
{ step-back [ f ] }
2008-02-21 00:13:31 -05:00
{ abandon [ f ] }
2008-02-21 00:13:22 -05:00
{ f [ walker-stopped f ] }
2008-02-20 00:26:07 -05:00
! thread hit a breakpoint and sent us the
2008-02-21 00:13:22 -05:00
! continuation, so we modify it and send it
! back.
[ walker-suspended ]
2008-02-20 00:26:07 -05:00
} case
] handle-synchronous
2008-03-17 06:08:47 -04:00
] [ ] while ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: associate-thread ( walker -- )
2008-02-21 00:13:31 -05:00
walker-thread tset
[ f walker-thread tget send-synchronous drop ]
2008-08-30 13:35:14 -04:00
self (>>exit-handler) ;
2008-02-20 00:26:07 -05:00
2008-02-21 00:13:22 -05:00
: start-walker-thread ( status continuation -- thread' )
2008-02-21 00:13:31 -05:00
self [
walking-thread tset
2008-02-21 00:13:22 -05:00
walker-continuation tset
walker-status tset
V{ } clone walker-history tset
walker-loop
2008-02-21 00:13:31 -05:00
] 3curry
2008-08-30 13:35:14 -04:00
"Walker on " self name>> append spawn
2008-02-21 00:13:22 -05:00
[ associate-thread ] keep ;
! For convenience
IN: syntax
2008-06-08 16:32:55 -04:00
: B ( -- ) break ;