From 9aba341bdb81bdb76f44cb63f8397291c63adb5e Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Mon, 3 Aug 2009 21:26:06 -0500 Subject: [PATCH 01/17] furnace.sessions: fix tests, requests must have a method set now --- basis/furnace/sessions/sessions-tests.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basis/furnace/sessions/sessions-tests.factor b/basis/furnace/sessions/sessions-tests.factor index 99855c76fa..392d43e89b 100644 --- a/basis/furnace/sessions/sessions-tests.factor +++ b/basis/furnace/sessions/sessions-tests.factor @@ -53,7 +53,7 @@ M: foo call-responder* "auth-test.db" temp-file [ - init-request + "GET" >>method init-request session ensure-table "127.0.0.1" 1234 remote-address set From eed4f4dcfc9c712cedab82a031e1a62b1f557a5a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 4 Aug 2009 16:23:14 -0500 Subject: [PATCH 02/17] compiler.tree.recursive: add some more more loop detection tests --- .../tree/recursive/recursive-tests.factor | 41 ++++++++++++++----- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/basis/compiler/tree/recursive/recursive-tests.factor b/basis/compiler/tree/recursive/recursive-tests.factor index 80edae076f..7cdb98bc58 100644 --- a/basis/compiler/tree/recursive/recursive-tests.factor +++ b/basis/compiler/tree/recursive/recursive-tests.factor @@ -67,13 +67,6 @@ compiler.tree.combinators ; \ loop-test-3 label-is-not-loop? ] unit-test -: loop-test-4 ( a -- ) - dup [ - loop-test-4 - ] [ - drop - ] if ; inline recursive - [ f ] [ [ [ [ ] map ] map ] build-tree analyze-recursive [ @@ -145,17 +138,32 @@ DEFER: a' DEFER: a'' -: b'' ( -- ) +: b'' ( a -- b ) a'' ; inline recursive -: a'' ( -- ) - b'' a'' ; inline recursive +: a'' ( a -- b ) + dup [ b'' a'' ] when ; inline recursive [ t ] [ [ a'' ] build-tree analyze-recursive \ a'' label-is-not-loop? ] unit-test +[ t ] [ + [ a'' ] build-tree analyze-recursive + \ b'' label-is-loop? +] unit-test + +[ t ] [ + [ b'' ] build-tree analyze-recursive + \ a'' label-is-not-loop? +] unit-test + +[ f ] [ + [ b'' ] build-tree analyze-recursive + \ b'' label-is-not-loop? +] unit-test + : loop-in-non-loop ( x quot: ( i -- ) -- ) over 0 > [ [ [ 1 - ] dip loop-in-non-loop ] [ call ] 2bi @@ -166,3 +174,16 @@ DEFER: a'' build-tree analyze-recursive \ (each-integer) label-is-loop? ] unit-test + +DEFER: a''' + +: b''' ( -- ) + blah [ b''' ] [ a''' b''' ] if ; inline recursive + +: a''' ( -- ) + blah [ b''' ] [ a''' ] if ; inline recursive + +[ t ] [ + [ b''' ] build-tree analyze-recursive + \ a''' label-is-loop? +] unit-test \ No newline at end of file From c3d60e58993938c5f158dce3847ba376c949a1f0 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 4 Aug 2009 19:18:40 -0500 Subject: [PATCH 03/17] compiler.tree.recursive: more accurate loop detection --- basis/compiler/tree/checker/checker.factor | 1 + basis/compiler/tree/cleanup/cleanup.factor | 2 +- .../tree/dead-code/recursive/recursive.factor | 1 + .../recursive/recursive.factor | 3 +- .../propagation/recursive/recursive.factor | 2 +- .../tree/recursive/recursive-tests.factor | 6 +- .../compiler/tree/recursive/recursive.factor | 178 ++++++++++-------- basis/compiler/tree/tree.factor | 3 - 8 files changed, 110 insertions(+), 86 deletions(-) diff --git a/basis/compiler/tree/checker/checker.factor b/basis/compiler/tree/checker/checker.factor index e25f152aef..0b3b46fe33 100755 --- a/basis/compiler/tree/checker/checker.factor +++ b/basis/compiler/tree/checker/checker.factor @@ -5,6 +5,7 @@ arrays combinators continuations columns math vectors grouping stack-checker.branches compiler.tree compiler.tree.def-use +compiler.tree.recursive compiler.tree.combinators ; IN: compiler.tree.checker diff --git a/basis/compiler/tree/cleanup/cleanup.factor b/basis/compiler/tree/cleanup/cleanup.factor index 1b0343faa9..3232e965db 100644 --- a/basis/compiler/tree/cleanup/cleanup.factor +++ b/basis/compiler/tree/cleanup/cleanup.factor @@ -20,7 +20,7 @@ IN: compiler.tree.cleanup GENERIC: delete-node ( node -- ) M: #call-recursive delete-node - dup label>> [ [ eq? not ] with filter ] change-calls drop ; + dup label>> calls>> [ node>> eq? not ] with filter-here ; M: #return-recursive delete-node label>> f >>return drop ; diff --git a/basis/compiler/tree/dead-code/recursive/recursive.factor b/basis/compiler/tree/dead-code/recursive/recursive.factor index 71830d07e7..b0ab864c80 100644 --- a/basis/compiler/tree/dead-code/recursive/recursive.factor +++ b/basis/compiler/tree/dead-code/recursive/recursive.factor @@ -3,6 +3,7 @@ USING: accessors arrays assocs sequences kernel locals fry combinators stack-checker.backend compiler.tree +compiler.tree.recursive compiler.tree.dead-code.branches compiler.tree.dead-code.liveness compiler.tree.dead-code.simple ; diff --git a/basis/compiler/tree/escape-analysis/recursive/recursive.factor b/basis/compiler/tree/escape-analysis/recursive/recursive.factor index 5aece23d17..ad6572a35c 100644 --- a/basis/compiler/tree/escape-analysis/recursive/recursive.factor +++ b/basis/compiler/tree/escape-analysis/recursive/recursive.factor @@ -3,6 +3,7 @@ USING: kernel sequences math combinators accessors namespaces fry disjoint-sets compiler.tree +compiler.tree.recursive compiler.tree.combinators compiler.tree.escape-analysis.nodes compiler.tree.escape-analysis.branches @@ -67,5 +68,5 @@ M: #return-recursive escape-analysis* ( #return-recursive -- ) [ call-next-method ] [ [ in-d>> ] [ label>> calls>> ] bi - [ out-d>> escaping-values get '[ _ equate ] 2each ] with each + [ node>> out-d>> escaping-values get '[ _ equate ] 2each ] with each ] bi ; diff --git a/basis/compiler/tree/propagation/recursive/recursive.factor b/basis/compiler/tree/propagation/recursive/recursive.factor index b8d1760a0b..64b7ba4609 100644 --- a/basis/compiler/tree/propagation/recursive/recursive.factor +++ b/basis/compiler/tree/propagation/recursive/recursive.factor @@ -21,7 +21,7 @@ IN: compiler.tree.propagation.recursive in-d>> [ value-info ] map ; : recursive-stacks ( #enter-recursive -- stacks initial ) - [ label>> calls>> [ node-input-infos ] map flip ] + [ label>> calls>> [ node>> node-input-infos ] map flip ] [ latest-input-infos ] bi ; : generalize-counter-interval ( interval initial-interval -- interval' ) diff --git a/basis/compiler/tree/recursive/recursive-tests.factor b/basis/compiler/tree/recursive/recursive-tests.factor index 7cdb98bc58..f9ba5f75ea 100644 --- a/basis/compiler/tree/recursive/recursive-tests.factor +++ b/basis/compiler/tree/recursive/recursive-tests.factor @@ -146,7 +146,7 @@ DEFER: a'' [ t ] [ [ a'' ] build-tree analyze-recursive - \ a'' label-is-not-loop? + \ a'' label-is-loop? ] unit-test [ t ] [ @@ -156,10 +156,10 @@ DEFER: a'' [ t ] [ [ b'' ] build-tree analyze-recursive - \ a'' label-is-not-loop? + \ a'' label-is-loop? ] unit-test -[ f ] [ +[ t ] [ [ b'' ] build-tree analyze-recursive \ b'' label-is-not-loop? ] unit-test diff --git a/basis/compiler/tree/recursive/recursive.factor b/basis/compiler/tree/recursive/recursive.factor index 2e40693e69..f6235719ff 100644 --- a/basis/compiler/tree/recursive/recursive.factor +++ b/basis/compiler/tree/recursive/recursive.factor @@ -1,104 +1,128 @@ -! Copyright (C) 2008 Slava Pestov. +! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: kernel assocs arrays namespaces accessors sequences deques -search-deques dlists compiler.tree compiler.tree.combinators ; +USING: kernel assocs arrays namespaces accessors sequences deques fry +search-deques dlists combinators.short-circuit make sets compiler.tree ; IN: compiler.tree.recursive -! Collect label info -GENERIC: collect-label-info ( node -- ) +TUPLE: call-site tail? node label ; -M: #return-recursive collect-label-info - dup label>> (>>return) ; +: recursive-phi-in ( #enter-recursive -- seq ) + [ label>> calls>> [ node>> in-d>> ] map ] [ in-d>> ] bi suffix ; -M: #call-recursive collect-label-info - dup label>> calls>> push ; +> V{ } clone >>calls drop ; +TUPLE: call-tree-node label children calls ; -M: node collect-label-info drop ; - -! A loop is a #recursive which only tail calls itself, and those -! calls are nested inside other loops only. We optimistically -! assume all #recursive nodes are loops, disqualifying them as -! we see evidence to the contrary. : (tail-calls) ( tail? seq -- seq' ) reverse [ swap [ and ] keep ] map nip reverse ; : tail-calls ( tail? node -- seq ) [ - [ #phi? ] - [ #return? ] - [ #return-recursive? ] - tri or or + { + [ #phi? ] + [ #return? ] + [ #return-recursive? ] + } 1|| ] map (tail-calls) ; -SYMBOL: loop-heights -SYMBOL: loop-calls -SYMBOL: loop-stack -SYMBOL: work-list +SYMBOLS: children calls ; -GENERIC: collect-loop-info* ( tail? node -- ) +GENERIC: node-call-tree ( tail? node -- ) -: non-tail-label-info ( nodes -- ) - [ f swap collect-loop-info* ] each ; +: (build-call-tree) ( tail? nodes -- ) + [ tail-calls ] keep + [ node-call-tree ] 2each ; -: (collect-loop-info) ( tail? nodes -- ) - [ tail-calls ] keep [ collect-loop-info* ] 2each ; - -: remember-loop-info ( label -- ) - loop-stack get length swap loop-heights get set-at ; - -M: #recursive collect-loop-info* +: build-call-tree ( nodes -- labels calls ) [ - [ - label>> - [ swap 2array loop-stack [ swap suffix ] change ] - [ remember-loop-info ] - [ t >>loop? drop ] - tri - ] - [ t swap child>> (collect-loop-info) ] bi + V{ } clone children set + V{ } clone calls set + [ t ] dip (build-call-tree) + children get + calls get ] with-scope ; -: current-loop-nesting ( label -- alist ) - loop-stack get swap loop-heights get at tail ; +M: #return-recursive node-call-tree + nip dup label>> (>>return) ; -: disqualify-loop ( label -- ) - work-list get push-front ; +M: #call-recursive node-call-tree + [ dup label>> call-site boa ] keep + [ drop calls get push ] + [ label>> calls>> push ] 2bi ; -M: #call-recursive collect-loop-info* - label>> - swap [ dup disqualify-loop ] unless - dup current-loop-nesting - [ keys [ loop-calls get push-at ] with each ] - [ [ nip not ] assoc-filter keys [ disqualify-loop ] each ] +M: #recursive node-call-tree + nip + [ label>> V{ } clone >>calls drop ] + [ + [ label>> ] [ child>> build-call-tree ] bi + call-tree-node boa children get push + ] bi ; + +M: #branch node-call-tree + children>> [ (build-call-tree) ] with each ; + +M: node node-call-tree 2drop ; + +SYMBOLS: not-loops recursive-nesting ; + +: not-a-loop ( label -- ) not-loops get conjoin ; + +: not-a-loop? ( label -- ? ) not-loops get key? ; + +: non-tail-calls ( call-tree-node -- seq ) + calls>> [ tail?>> not ] filter ; + +: visit-back-edges ( call-tree -- ) + [ + [ non-tail-calls [ label>> not-a-loop ] each ] + [ children>> visit-back-edges ] + bi + ] each ; + +SYMBOL: changed? + +: check-cross-frame-call ( call-site -- ) + label>> dup not-a-loop? [ drop ] [ + recursive-nesting get [ + 2dup eq? [ 2drop f ] [ + not-a-loop? [ not-a-loop changed? on ] [ drop ] if t + ] if + ] with all? drop + ] if ; + +: detect-cross-frame-calls ( call-tree -- ) + ! Suppose we have a nesting of recursives A --> B --> C + ! B tail-calls A, and C non-tail-calls B. Then A cannot be + ! a loop, it needs its own procedure, since the call from + ! C to A crosses a call-frame boundary. + [ + [ label>> recursive-nesting get push ] + [ calls>> [ check-cross-frame-call ] each ] + [ children>> detect-cross-frame-calls ] tri + recursive-nesting get pop* + ] each ; + +: while-changing ( quot: ( -- ) -- ) + changed? off + [ call ] [ changed? get [ while-changing ] [ drop ] if ] bi ; + inline recursive + +: detect-loops ( call-tree -- ) + H{ } clone not-loops set + V{ } clone recursive-nesting set + [ visit-back-edges ] + [ '[ _ detect-cross-frame-calls ] while-changing ] bi ; -M: #if collect-loop-info* - children>> [ (collect-loop-info) ] with each ; +: mark-loops ( call-tree -- ) + [ + [ label>> dup not-a-loop? [ t >>loop? ] unless drop ] + [ children>> mark-loops ] + bi + ] each ; -M: #dispatch collect-loop-info* - children>> [ (collect-loop-info) ] with each ; - -M: node collect-loop-info* 2drop ; - -: collect-loop-info ( node -- ) - { } loop-stack set - H{ } clone loop-calls set - H{ } clone loop-heights set - work-list set - t swap (collect-loop-info) ; - -: disqualify-loops ( -- ) - work-list get [ - dup loop?>> [ - [ f >>loop? drop ] - [ loop-calls get at [ disqualify-loop ] each ] - bi - ] [ drop ] if - ] slurp-deque ; +PRIVATE> : analyze-recursive ( nodes -- nodes ) - dup [ collect-label-info ] each-node - dup collect-loop-info disqualify-loops ; + dup build-call-tree drop + [ detect-loops ] [ mark-loops ] bi ; diff --git a/basis/compiler/tree/tree.factor b/basis/compiler/tree/tree.factor index c73f2211f0..7fa096b623 100644 --- a/basis/compiler/tree/tree.factor +++ b/basis/compiler/tree/tree.factor @@ -165,9 +165,6 @@ M: #shuffle inputs/outputs mapping>> unzip swap ; M: #copy inputs/outputs [ in-d>> ] [ out-d>> ] bi ; M: #return-recursive inputs/outputs [ in-d>> ] [ out-d>> ] bi ; -: recursive-phi-in ( #enter-recursive -- seq ) - [ label>> calls>> [ in-d>> ] map ] [ in-d>> ] bi suffix ; - : ends-with-terminate? ( nodes -- ? ) [ f ] [ last #terminate? ] if-empty ; From 3b2fd98e7c70de5b02e3ab311d33a8c75af7ecb7 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 4 Aug 2009 21:01:21 -0500 Subject: [PATCH 04/17] Refactor source-file-errors a little bit to remove some code duplication, and so that clicking 'Edit' in error list tool works for parse errors in unit tests --- basis/editors/editors.factor | 35 ++------------------------ basis/tools/errors/errors.factor | 10 +++++--- basis/tools/test/test.factor | 2 +- core/lexer/lexer.factor | 11 ++++---- core/source-files/errors/errors.factor | 14 ++++++++++- 5 files changed, 28 insertions(+), 44 deletions(-) diff --git a/basis/editors/editors.factor b/basis/editors/editors.factor index da6a589031..4a6dd9b5be 100644 --- a/basis/editors/editors.factor +++ b/basis/editors/editors.factor @@ -47,43 +47,12 @@ M: cannot-find-source error. : edit-vocab ( name -- ) >vocab-link edit ; -GENERIC: error-file ( error -- file ) - -GENERIC: error-line ( error -- line ) - -M: lexer-error error-file - error>> error-file ; - -M: lexer-error error-line - [ error>> error-line ] [ line>> ] bi or ; - -M: source-file-error error-file - [ error>> error-file ] [ file>> ] bi or ; - -M: source-file-error error-line - error>> error-line ; - -M: condition error-file - error>> error-file ; - -M: condition error-line - error>> error-line ; - -M: object error-file - drop f ; - -M: object error-line - drop f ; - -: (:edit) ( error -- ) +: edit-error ( error -- ) [ error-file ] [ error-line ] bi 2dup and [ edit-location ] [ 2drop ] if ; : :edit ( -- ) - error get (:edit) ; - -: edit-error ( error -- ) - [ file>> ] [ line#>> ] bi 2dup and [ edit-location ] [ 2drop ] if ; + error get edit-error ; : edit-each ( seq -- ) [ diff --git a/basis/tools/errors/errors.factor b/basis/tools/errors/errors.factor index b53d4ef7a2..963ea7592c 100644 --- a/basis/tools/errors/errors.factor +++ b/basis/tools/errors/errors.factor @@ -14,14 +14,16 @@ M: source-file-error error-help error>> error-help ; CONSTANT: +listener-input+ "" -M: source-file-error summary +: error-location ( error -- string ) [ - [ file>> [ % ": " % ] [ +listener-input+ % ] if* ] - [ line#>> [ # ] when* ] bi + [ file>> [ % ] [ +listener-input+ % ] if* ] + [ line#>> [ ": " % # ] when* ] bi ] "" make ; +M: source-file-error summary error>> summary ; + M: source-file-error error. - [ summary print nl ] + [ error-location print nl ] [ asset>> [ "Asset: " write short. nl ] when* ] [ error>> error. ] tri ; diff --git a/basis/tools/test/test.factor b/basis/tools/test/test.factor index 7b07311ded..b6d56b18c0 100644 --- a/basis/tools/test/test.factor +++ b/basis/tools/test/test.factor @@ -130,7 +130,7 @@ TEST: must-fail M: test-failure error. ( error -- ) { - [ summary print nl ] + [ error-location print nl ] [ asset>> [ experiment. nl ] when* ] [ error>> error. ] [ traceback-button. ] diff --git a/core/lexer/lexer.factor b/core/lexer/lexer.factor index 99e6f05c6c..036c7d9721 100644 --- a/core/lexer/lexer.factor +++ b/core/lexer/lexer.factor @@ -1,7 +1,8 @@ ! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: kernel sequences accessors namespaces math words strings -io vectors arrays math.parser combinators continuations ; +io vectors arrays math.parser combinators continuations +source-files.errors ; IN: lexer TUPLE: lexer text line line-text line-length column ; @@ -24,11 +25,8 @@ TUPLE: lexer text line line-text line-length column ; ERROR: unexpected want got ; -PREDICATE: unexpected-tab < unexpected - got>> CHAR: \t = ; - : forbid-tab ( c -- c ) - [ CHAR: \t eq? [ "[space]" "[tab]" unexpected ] when ] keep ; + [ CHAR: \t eq? [ "[space]" "[tab]" unexpected ] when ] keep ; inline : skip ( i seq ? -- n ) over length @@ -96,6 +94,9 @@ PREDICATE: unexpected-eof < unexpected TUPLE: lexer-error line column line-text error ; +M: lexer-error error-file error>> error-file ; +M: lexer-error error-line [ error>> error-line ] [ line>> ] bi or ; + : ( msg -- error ) \ lexer-error new lexer get diff --git a/core/source-files/errors/errors.factor b/core/source-files/errors/errors.factor index 86a8354071..93078c162b 100644 --- a/core/source-files/errors/errors.factor +++ b/core/source-files/errors/errors.factor @@ -1,11 +1,23 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. USING: accessors assocs kernel math.order sorting sequences definitions -namespaces arrays splitting io math.parser math init ; +namespaces arrays splitting io math.parser math init continuations ; IN: source-files.errors +GENERIC: error-file ( error -- file ) +GENERIC: error-line ( error -- line ) + +M: object error-file drop f ; +M: object error-line drop f ; + +M: condition error-file error>> error-file ; +M: condition error-line error>> error-line ; + TUPLE: source-file-error error asset file line# ; +M: source-file-error error-file [ error>> error-file ] [ file>> ] bi or ; +M: source-file-error error-line [ error>> error-line ] [ line#>> ] bi or ; + : sort-errors ( errors -- alist ) [ [ line#>> ] sort-with ] { } assoc-map-as sort-keys ; From eb0ecb68cdce8cbaccb29713216e0e60f30d6bcb Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Tue, 4 Aug 2009 21:14:43 -0500 Subject: [PATCH 05/17] ui.tools.debugger: (:edit) got renamed to edit-error --- basis/ui/tools/debugger/debugger.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basis/ui/tools/debugger/debugger.factor b/basis/ui/tools/debugger/debugger.factor index 024442a264..a4fda6600e 100755 --- a/basis/ui/tools/debugger/debugger.factor +++ b/basis/ui/tools/debugger/debugger.factor @@ -79,7 +79,7 @@ debugger "gestures" f { : com-help ( debugger -- ) error>> error-help-window ; -: com-edit ( debugger -- ) error>> (:edit) ; +: com-edit ( debugger -- ) error>> edit-error ; \ com-edit H{ { +listener+ t } } define-command From 50fd4f17c398d231de92ed3dd633f4911eb579ba Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 5 Aug 2009 01:15:06 -0500 Subject: [PATCH 06/17] Oops --- basis/stuff.factor | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 basis/stuff.factor diff --git a/basis/stuff.factor b/basis/stuff.factor deleted file mode 100644 index 2e5fa2dfae..0000000000 --- a/basis/stuff.factor +++ /dev/null @@ -1,20 +0,0 @@ - -: spill-integer-base ( -- n ) - stack-frame get spill-counts>> double-float-regs swap at - double-float-regs reg-size * ; - -: spill-integer@ ( n -- offset ) - cells spill-integer-base + param@ ; - -: spill-float@ ( n -- offset ) - double-float-regs reg-size * param@ ; - -: (stack-frame-size) ( stack-frame -- n ) - [ - { - [ spill-counts>> [ swap reg-size * ] { } assoc>map sum ] - [ gc-roots>> cells ] - [ params>> ] - [ return>> ] - } cleave - ] sum-outputs ; \ No newline at end of file From fb03a93763214a5fe820a81475aaf0e60f26792a Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 5 Aug 2009 02:14:49 -0500 Subject: [PATCH 07/17] compiler.tree.recursive: have to check tail call flag of call tree edges too --- .../tree/recursive/recursive-tests.factor | 22 ++++++++++++++----- .../compiler/tree/recursive/recursive.factor | 10 ++++----- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/basis/compiler/tree/recursive/recursive-tests.factor b/basis/compiler/tree/recursive/recursive-tests.factor index f9ba5f75ea..8157084805 100644 --- a/basis/compiler/tree/recursive/recursive-tests.factor +++ b/basis/compiler/tree/recursive/recursive-tests.factor @@ -1,9 +1,10 @@ IN: compiler.tree.recursive.tests -USING: compiler.tree.recursive tools.test -kernel combinators.short-circuit math sequences accessors +USING: tools.test kernel combinators.short-circuit math sequences accessors compiler.tree compiler.tree.builder -compiler.tree.combinators ; +compiler.tree.combinators +compiler.tree.recursive +compiler.tree.recursive.private ; [ { f f f f } ] [ f { f t f f } (tail-calls) ] unit-test [ { f f f t } ] [ t { f t f f } (tail-calls) ] unit-test @@ -146,7 +147,7 @@ DEFER: a'' [ t ] [ [ a'' ] build-tree analyze-recursive - \ a'' label-is-loop? + \ a'' label-is-not-loop? ] unit-test [ t ] [ @@ -186,4 +187,15 @@ DEFER: a''' [ t ] [ [ b''' ] build-tree analyze-recursive \ a''' label-is-loop? -] unit-test \ No newline at end of file +] unit-test + +DEFER: b4 + +: a4 ( a -- b ) dup [ b4 ] when ; inline recursive + +: b4 ( a -- b ) dup [ a4 reverse ] when ; inline recursive + +[ t ] [ [ b4 ] build-tree analyze-recursive \ a4 label-is-loop? ] unit-test +[ t ] [ [ b4 ] build-tree analyze-recursive \ b4 label-is-not-loop? ] unit-test +[ t ] [ [ a4 ] build-tree analyze-recursive \ a4 label-is-not-loop? ] unit-test +[ t ] [ [ a4 ] build-tree analyze-recursive \ b4 label-is-loop? ] unit-test \ No newline at end of file diff --git a/basis/compiler/tree/recursive/recursive.factor b/basis/compiler/tree/recursive/recursive.factor index f6235719ff..3746046bea 100644 --- a/basis/compiler/tree/recursive/recursive.factor +++ b/basis/compiler/tree/recursive/recursive.factor @@ -11,7 +11,7 @@ TUPLE: call-site tail? node label ; > calls>> push ] 2bi ; M: #recursive node-call-tree - nip [ label>> V{ } clone >>calls drop ] [ [ label>> ] [ child>> build-call-tree ] bi @@ -84,8 +83,9 @@ SYMBOL: changed? : check-cross-frame-call ( call-site -- ) label>> dup not-a-loop? [ drop ] [ recursive-nesting get [ - 2dup eq? [ 2drop f ] [ - not-a-loop? [ not-a-loop changed? on ] [ drop ] if t + 2dup label>> eq? [ 2drop f ] [ + [ label>> not-a-loop? ] [ tail?>> not ] bi or + [ not-a-loop changed? on ] [ drop ] if t ] if ] with all? drop ] if ; @@ -96,7 +96,7 @@ SYMBOL: changed? ! a loop, it needs its own procedure, since the call from ! C to A crosses a call-frame boundary. [ - [ label>> recursive-nesting get push ] + [ recursive-nesting get push ] [ calls>> [ check-cross-frame-call ] each ] [ children>> detect-cross-frame-calls ] tri recursive-nesting get pop* From 97ec3ea1b44094fd93ba1783182c71a279a438a9 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 5 Aug 2009 03:33:06 -0500 Subject: [PATCH 08/17] compiler.graphviz: add high-level IR call graph rendering --- .../compiler/tree/recursive/recursive.factor | 47 +++--- extra/compiler/cfg/graphviz/graphviz.factor | 44 ------ extra/compiler/graphviz/graphviz.factor | 139 ++++++++++++++++++ 3 files changed, 165 insertions(+), 65 deletions(-) delete mode 100644 extra/compiler/cfg/graphviz/graphviz.factor create mode 100644 extra/compiler/graphviz/graphviz.factor diff --git a/basis/compiler/tree/recursive/recursive.factor b/basis/compiler/tree/recursive/recursive.factor index 3746046bea..bc6243e138 100644 --- a/basis/compiler/tree/recursive/recursive.factor +++ b/basis/compiler/tree/recursive/recursive.factor @@ -11,7 +11,7 @@ TUPLE: call-site tail? node label ; > (>>return) ; -M: #call-recursive node-call-tree +M: #call-recursive node-call-graph [ dup label>> call-site boa ] keep [ drop calls get push ] [ label>> calls>> push ] 2bi ; -M: #recursive node-call-tree +M: #recursive node-call-graph [ label>> V{ } clone >>calls drop ] [ - [ label>> ] [ child>> build-call-tree ] bi - call-tree-node boa children get push + [ label>> ] [ child>> build-call-graph ] bi + call-graph-node boa children get push ] bi ; -M: #branch node-call-tree - children>> [ (build-call-tree) ] with each ; +M: #branch node-call-graph + children>> [ (build-call-graph) ] with each ; -M: node node-call-tree 2drop ; +M: node node-call-graph 2drop ; SYMBOLS: not-loops recursive-nesting ; @@ -68,10 +68,10 @@ SYMBOLS: not-loops recursive-nesting ; : not-a-loop? ( label -- ? ) not-loops get key? ; -: non-tail-calls ( call-tree-node -- seq ) +: non-tail-calls ( call-graph-node -- seq ) calls>> [ tail?>> not ] filter ; -: visit-back-edges ( call-tree -- ) +: visit-back-edges ( call-graph -- ) [ [ non-tail-calls [ label>> not-a-loop ] each ] [ children>> visit-back-edges ] @@ -90,7 +90,7 @@ SYMBOL: changed? ] with all? drop ] if ; -: detect-cross-frame-calls ( call-tree -- ) +: detect-cross-frame-calls ( call-graph -- ) ! Suppose we have a nesting of recursives A --> B --> C ! B tail-calls A, and C non-tail-calls B. Then A cannot be ! a loop, it needs its own procedure, since the call from @@ -107,14 +107,14 @@ SYMBOL: changed? [ call ] [ changed? get [ while-changing ] [ drop ] if ] bi ; inline recursive -: detect-loops ( call-tree -- ) +: detect-loops ( call-graph -- ) H{ } clone not-loops set V{ } clone recursive-nesting set [ visit-back-edges ] [ '[ _ detect-cross-frame-calls ] while-changing ] bi ; -: mark-loops ( call-tree -- ) +: mark-loops ( call-graph -- ) [ [ label>> dup not-a-loop? [ t >>loop? ] unless drop ] [ children>> mark-loops ] @@ -123,6 +123,11 @@ SYMBOL: changed? PRIVATE> +SYMBOL: call-graph + : analyze-recursive ( nodes -- nodes ) - dup build-call-tree drop - [ detect-loops ] [ mark-loops ] bi ; + dup build-call-graph drop + [ call-graph set ] + [ detect-loops ] + [ mark-loops ] + tri ; diff --git a/extra/compiler/cfg/graphviz/graphviz.factor b/extra/compiler/cfg/graphviz/graphviz.factor deleted file mode 100644 index 0aade1301f..0000000000 --- a/extra/compiler/cfg/graphviz/graphviz.factor +++ /dev/null @@ -1,44 +0,0 @@ -! Copyright (C) 2009 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license -USING: accessors compiler.cfg.rpo compiler.cfg.dominance -compiler.cfg.dominance.private compiler.cfg.predecessors images.viewer -io io.encodings.ascii io.files io.files.unique io.launcher kernel -math.parser sequences assocs arrays make namespaces ; -IN: compiler.cfg.graphviz - -: render-graph ( edges -- ) - "cfg" "dot" make-unique-file - [ - ascii [ - "digraph CFG {" print - [ [ number>> number>string ] bi@ " -> " glue write ";" print ] assoc-each - "}" print - ] with-file-writer - ] - [ { "dot" "-Tpng" "-O" } swap suffix try-process ] - [ ".png" append { "open" } swap suffix try-process ] - tri ; - -: cfg-edges ( cfg -- edges ) - [ - [ - dup successors>> [ - 2array , - ] with each - ] each-basic-block - ] { } make ; - -: render-cfg ( cfg -- ) cfg-edges render-graph ; - -: dom-edges ( cfg -- edges ) - [ - compute-predecessors - compute-dominance - dom-childrens get [ - [ - 2array , - ] with each - ] assoc-each - ] { } make ; - -: render-dom ( cfg -- ) dom-edges render-graph ; \ No newline at end of file diff --git a/extra/compiler/graphviz/graphviz.factor b/extra/compiler/graphviz/graphviz.factor new file mode 100644 index 0000000000..353a134375 --- /dev/null +++ b/extra/compiler/graphviz/graphviz.factor @@ -0,0 +1,139 @@ +! Copyright (C) 2009 Slava Pestov. +! See http://factorcode.org/license.txt for BSD license +USING: accessors compiler.tree.builder compiler.cfg compiler.cfg.rpo +compiler.cfg.dominance compiler.cfg.dominance.private +compiler.cfg.predecessors compiler.cfg.debugger compiler.cfg.optimizer +compiler.cfg.utilities compiler.tree.recursive images.viewer +images.png io io.encodings.ascii io.files io.files.unique io.launcher +kernel math.parser sequences assocs arrays make math namespaces +quotations combinators locals words ; +IN: compiler.graphviz + +: quotes ( str -- str' ) "\"" "\"" surround ; + +: graph, ( quot title -- ) + [ + quotes "digraph " " {" surround , + call + "}" , + ] { } make , ; inline + +: render-graph ( quot -- ) + { } make + "cfg" ".dot" make-unique-file + dup "Wrote " prepend print + [ [ concat ] dip ascii set-file-lines ] + [ { "dot" "-Tpng" "-O" } swap suffix try-process ] + [ ".png" append image. ] + tri ; inline + +: attrs>string ( seq -- str ) + [ "" ] [ "," join "[" "]" surround ] if-empty ; + +: edge,* ( from to attrs -- ) + [ + [ quotes % " -> " % ] [ quotes % " " % ] [ attrs>string % ] tri* + ";" % + ] "" make , ; + +: edge, ( from to -- ) + { } edge,* ; + +: bb-edge, ( from to -- ) + [ number>> number>string ] bi@ edge, ; + +: node-style, ( str attrs -- ) + [ [ quotes % " " % ] [ attrs>string % ";" % ] bi* ] "" make , ; + +: cfg-title ( cfg/mr -- string ) + [ + "=== word: " % + [ word>> name>> % ", label: " % ] + [ label>> name>> % ] + bi + ] "" make ; + +: cfg-vertex, ( bb -- ) + [ number>> number>string ] + [ kill-block? { "color=grey" "style=filled" } { } ? ] + bi node-style, ; + +: cfgs ( cfgs -- ) + [ + [ + [ [ cfg-vertex, ] each-basic-block ] + [ + [ + dup successors>> [ + bb-edge, + ] with each + ] each-basic-block + ] bi + ] over cfg-title graph, + ] each ; + +: optimized-cfg ( quot -- cfgs ) + { + { [ dup cfg? ] [ 1array ] } + { [ dup quotation? ] [ test-cfg [ optimize-cfg ] map ] } + { [ dup word? ] [ test-cfg [ optimize-cfg ] map ] } + [ ] + } cond ; + +: render-cfg ( cfg -- ) + optimized-cfg [ cfgs ] render-graph ; + +: dom-trees ( cfgs -- ) + [ + [ + compute-predecessors + compute-dominance + dom-childrens get [ + [ + bb-edge, + ] with each + ] assoc-each + ] over cfg-title graph, + ] each ; + +: render-dom ( cfg -- ) + optimized-cfg [ dom-trees ] render-graph ; + +SYMBOL: word-counts +SYMBOL: vertex-names + +: vertex-name ( call-graph-node -- string ) + label>> vertex-names get [ + word>> name>> + dup word-counts get [ 0 or 1 + dup ] change-at number>string " #" glue + ] cache ; + +: vertex-attrs ( obj -- string ) + tail?>> { "style=bold,label=\"tail\"" } { } ? ; + +: call-graph-edge, ( from to attrs -- ) + [ [ vertex-name ] [ vertex-attrs ] bi ] dip append edge,* ; + +: (call-graph-back-edges) ( string calls -- ) + [ { "color=red" } call-graph-edge, ] with each ; + +: (call-graph-edges) ( string children -- ) + [ + { + [ { } call-graph-edge, ] + [ [ vertex-name ] [ label>> loop?>> { "shape=box" } { } ? ] bi node-style, ] + [ [ vertex-name ] [ calls>> ] bi (call-graph-back-edges) ] + [ [ vertex-name ] [ children>> ] bi (call-graph-edges) ] + } cleave + ] with each ; + +: call-graph-edges ( call-graph-node -- ) + H{ } clone word-counts set + H{ } clone vertex-names set + [ "ROOT" ] dip (call-graph-edges) ; + +: render-call-graph ( tree -- ) + dup quotation? [ build-tree ] when + analyze-recursive drop + [ [ call-graph get call-graph-edges ] "Call graph" graph, ] + render-graph ; \ No newline at end of file From b1a85133dc12bae3cc5b2ca1c035e590dcb79fcf Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 5 Aug 2009 03:35:31 -0500 Subject: [PATCH 09/17] http.server.rewrite: fix typo in docs --- basis/http/server/rewrite/rewrite-docs.factor | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basis/http/server/rewrite/rewrite-docs.factor b/basis/http/server/rewrite/rewrite-docs.factor index 478adbab69..9ded10bded 100644 --- a/basis/http/server/rewrite/rewrite-docs.factor +++ b/basis/http/server/rewrite/rewrite-docs.factor @@ -39,7 +39,7 @@ HELP: " >>default" " >>child" " \"blog_id\" >>param" - " \"blogs.vegan.net >>suffix" + " \"blogs.vegan.net\" >>suffix" } } ; From eb3bd1edea493f96fa966840ab6a164457bd3665 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 5 Aug 2009 18:30:42 -0500 Subject: [PATCH 10/17] cpu.x86.assembler: make some words private --- basis/cpu/x86/assembler/assembler.factor | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/basis/cpu/x86/assembler/assembler.factor b/basis/cpu/x86/assembler/assembler.factor index 2b99513fc1..b2de0cc6e4 100644 --- a/basis/cpu/x86/assembler/assembler.factor +++ b/basis/cpu/x86/assembler/assembler.factor @@ -606,6 +606,8 @@ ALIAS: PINSRQ PINSRD : PSHUFLW ( dest src imm -- ) HEX: 70 HEX: f2 3-operand-rm-sse ; : PSHUFHW ( dest src imm -- ) HEX: 70 HEX: f3 3-operand-rm-sse ; + + : PSRLW ( dest src -- ) dup integer? [ (PSRLW-imm) ] [ (PSRLW-reg) ] if ; : PSRAW ( dest src -- ) dup integer? [ (PSRAW-imm) ] [ (PSRAW-reg) ] if ; : PSLLW ( dest src -- ) dup integer? [ (PSLLW-imm) ] [ (PSLLW-reg) ] if ; From 370f4c081d0fb8f51b42e6a421ab0fbd9acab0ff Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 5 Aug 2009 18:57:46 -0500 Subject: [PATCH 11/17] compiler.cfg: convert code into two-operand form before SSA destruction; SSA destruction now operates on a relaxed SSA form where multiple defs of the same vreg are allowed, but only within a single basic block. This makes linear scan's coalescing redundant, allowing it to be removed completely --- .../linear-scan/allocation/allocation.factor | 13 ++-- .../allocation/coalescing/coalescing.factor | 35 ----------- .../allocation/splitting/splitting.factor | 2 +- .../cfg/linear-scan/debugger/debugger.factor | 3 +- .../cfg/linear-scan/linear-scan-tests.factor | 20 ------- .../live-intervals/live-intervals.factor | 12 +--- basis/compiler/cfg/mr/mr.factor | 7 +-- basis/compiler/cfg/optimizer/optimizer.factor | 2 + .../cfg/ssa/destruction/destruction.factor | 28 +++++---- .../cfg/ssa/interference/interference.factor | 8 ++- .../live-ranges/live-ranges.factor | 9 ++- .../cfg/two-operand/two-operand-tests.factor | 22 ------- .../cfg/two-operand/two-operand.factor | 60 +++++-------------- 13 files changed, 57 insertions(+), 164 deletions(-) delete mode 100644 basis/compiler/cfg/linear-scan/allocation/coalescing/coalescing.factor diff --git a/basis/compiler/cfg/linear-scan/allocation/allocation.factor b/basis/compiler/cfg/linear-scan/allocation/allocation.factor index d55266e6e4..4b504d97f5 100644 --- a/basis/compiler/cfg/linear-scan/allocation/allocation.factor +++ b/basis/compiler/cfg/linear-scan/allocation/allocation.factor @@ -3,7 +3,6 @@ USING: accessors assocs heaps kernel namespaces sequences fry math math.order combinators arrays sorting compiler.utilities compiler.cfg.linear-scan.live-intervals -compiler.cfg.linear-scan.allocation.coalescing compiler.cfg.linear-scan.allocation.spilling compiler.cfg.linear-scan.allocation.splitting compiler.cfg.linear-scan.allocation.state ; @@ -29,13 +28,11 @@ IN: compiler.cfg.linear-scan.allocation second 0 = ; inline : assign-register ( new -- ) - dup coalesce? [ coalesce ] [ - dup register-status { - { [ dup no-free-registers? ] [ drop assign-blocked-register ] } - { [ 2dup register-available? ] [ register-available ] } - [ drop assign-blocked-register ] - } cond - ] if ; + dup register-status { + { [ dup no-free-registers? ] [ drop assign-blocked-register ] } + { [ 2dup register-available? ] [ register-available ] } + [ drop assign-blocked-register ] + } cond ; : handle-interval ( live-interval -- ) [ diff --git a/basis/compiler/cfg/linear-scan/allocation/coalescing/coalescing.factor b/basis/compiler/cfg/linear-scan/allocation/coalescing/coalescing.factor deleted file mode 100644 index ef8a9c56f8..0000000000 --- a/basis/compiler/cfg/linear-scan/allocation/coalescing/coalescing.factor +++ /dev/null @@ -1,35 +0,0 @@ -! Copyright (C) 2009 Slava Pestov. -! See http://factorcode.org/license.txt for BSD license. -USING: accessors kernel sequences namespaces assocs fry -combinators.short-circuit -compiler.cfg.linear-scan.live-intervals -compiler.cfg.linear-scan.allocation.state ; -IN: compiler.cfg.linear-scan.allocation.coalescing - -: active-interval ( vreg -- live-interval ) - dup [ dup active-intervals-for [ vreg>> = ] with find nip ] when ; - -: avoids-inactive-intervals? ( live-interval -- ? ) - dup vreg>> inactive-intervals-for - [ intervals-intersect? not ] with all? ; - -: coalesce? ( live-interval -- ? ) - { - [ copy-from>> active-interval ] - [ [ start>> ] [ copy-from>> active-interval end>> ] bi = ] - [ avoids-inactive-intervals? ] - } 1&& ; - -: reuse-spill-slot ( old new -- ) - [ vreg>> spill-slots get at ] dip '[ _ vreg>> spill-slots get set-at ] when* ; - -: reuse-register ( old new -- ) - reg>> >>reg drop ; - -: (coalesce) ( old new -- ) - [ add-active ] [ [ delete-active ] [ add-handled ] bi ] bi* ; - -: coalesce ( live-interval -- ) - dup copy-from>> active-interval - [ reuse-spill-slot ] [ reuse-register ] [ (coalesce) ] 2tri ; - \ No newline at end of file diff --git a/basis/compiler/cfg/linear-scan/allocation/splitting/splitting.factor b/basis/compiler/cfg/linear-scan/allocation/splitting/splitting.factor index 874523d70a..1a2b0f2f2b 100644 --- a/basis/compiler/cfg/linear-scan/allocation/splitting/splitting.factor +++ b/basis/compiler/cfg/linear-scan/allocation/splitting/splitting.factor @@ -45,7 +45,7 @@ ERROR: splitting-atomic-interval ; f >>spill-to ; inline : split-after ( after -- after' ) - f >>copy-from f >>reg f >>reload-from ; inline + f >>reg f >>reload-from ; inline :: split-interval ( live-interval n -- before after ) live-interval n check-split diff --git a/basis/compiler/cfg/linear-scan/debugger/debugger.factor b/basis/compiler/cfg/linear-scan/debugger/debugger.factor index c9c1b77a0d..68ff8d4f88 100644 --- a/basis/compiler/cfg/linear-scan/debugger/debugger.factor +++ b/basis/compiler/cfg/linear-scan/debugger/debugger.factor @@ -18,9 +18,8 @@ IN: compiler.cfg.linear-scan.debugger : interval-picture ( interval -- str ) [ uses>> picture ] - [ copy-from>> unparse ] [ vreg>> unparse ] - tri 3array ; + bi 2array ; : live-intervals. ( seq -- ) [ interval-picture ] map simple-table. ; diff --git a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor index 2164cef429..7cca94c061 100644 --- a/basis/compiler/cfg/linear-scan/linear-scan-tests.factor +++ b/basis/compiler/cfg/linear-scan/linear-scan-tests.factor @@ -470,7 +470,6 @@ USING: math.private ; clone dup [ start>> ] [ end>> ] bi 1vector >>ranges ] map ; -! Coalescing interacted badly with splitting [ ] [ { T{ live-interval @@ -478,7 +477,6 @@ USING: math.private ; { start 14 } { end 17 } { uses V{ 14 15 16 17 } } - { copy-from V int-regs 67 } } T{ live-interval { vreg V int-regs 67 } @@ -503,7 +501,6 @@ USING: math.private ; { start 10 } { end 18 } { uses V{ 10 11 12 18 } } - { copy-from V int-regs 56 } } T{ live-interval { vreg V int-regs 60 } @@ -559,7 +556,6 @@ USING: math.private ; { start 44 } { end 56 } { uses V{ 44 45 45 46 56 } } - { copy-from V int-regs 3686445 } } T{ live-interval { vreg V int-regs 3686198 } @@ -572,7 +568,6 @@ USING: math.private ; { start 46 } { end 49 } { uses V{ 46 47 47 49 } } - { copy-from V int-regs 3686449 } } T{ live-interval { vreg V int-regs 3686196 } @@ -603,7 +598,6 @@ USING: math.private ; { start 49 } { end 52 } { uses V{ 49 50 50 52 } } - { copy-from V int-regs 3686454 } } T{ live-interval { vreg V int-regs 3686461 } @@ -622,42 +616,36 @@ USING: math.private ; { start 54 } { end 76 } { uses V{ 54 55 55 76 } } - { copy-from V int-regs 3686464 } } T{ live-interval { vreg V int-regs 3686470 } { start 58 } { end 60 } { uses V{ 58 59 59 60 } } - { copy-from V int-regs 3686469 } } T{ live-interval { vreg V int-regs 3686469 } { start 56 } { end 58 } { uses V{ 56 57 57 58 } } - { copy-from V int-regs 3686449 } } T{ live-interval { vreg V int-regs 3686473 } { start 60 } { end 62 } { uses V{ 60 61 61 62 } } - { copy-from V int-regs 3686470 } } T{ live-interval { vreg V int-regs 3686479 } { start 62 } { end 64 } { uses V{ 62 63 63 64 } } - { copy-from V int-regs 3686473 } } T{ live-interval { vreg V int-regs 3686735 } { start 78 } { end 96 } { uses V{ 78 79 79 96 } } - { copy-from V int-regs 3686372 } } T{ live-interval { vreg V int-regs 3686482 } @@ -688,7 +676,6 @@ USING: math.private ; { start 66 } { end 75 } { uses V{ 66 67 67 75 } } - { copy-from V int-regs 3686483 } } T{ live-interval { vreg V int-regs 3687509 } @@ -719,7 +706,6 @@ USING: math.private ; { start 69 } { end 74 } { uses V{ 69 70 70 74 } } - { copy-from V int-regs 3686491 } } T{ live-interval { vreg V int-regs 3687778 } @@ -762,7 +748,6 @@ USING: math.private ; { start 72 } { end 74 } { uses V{ 72 73 73 74 } } - { copy-from V int-regs 3686499 } } T{ live-interval { vreg V int-regs 3687780 } @@ -877,7 +862,6 @@ USING: math.private ; { start 27 } { end 30 } { uses V{ 27 28 28 30 } } - { copy-from V int-regs 3686300 } } T{ live-interval { vreg V int-regs 3686306 } @@ -950,7 +934,6 @@ USING: math.private ; { start 243 } { end 245 } { uses V{ 243 244 244 245 } } - { copy-from V int-regs 3687845 } } T{ live-interval { vreg V int-regs 3687850 } @@ -1119,7 +1102,6 @@ USING: math.private ; { start 141 } { end 143 } { uses V{ 141 142 142 143 } } - { copy-from V int-regs 3687377 } } T{ live-interval { vreg V int-regs 3687381 } @@ -1174,7 +1156,6 @@ USING: math.private ; { start 293 } { end 295 } { uses V{ 293 294 294 295 } } - { copy-from V int-regs 3687087 } } T{ live-interval { vreg V int-regs 3687403 } @@ -1345,7 +1326,6 @@ USING: math.private ; { start 78 } { end 96 } { uses V{ 78 79 96 } } - { copy-from V int-regs 6372 } } T{ live-interval { vreg V int-regs 6483 } diff --git a/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor b/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor index 48bef197e6..8cc28e41e2 100644 --- a/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor +++ b/basis/compiler/cfg/linear-scan/live-intervals/live-intervals.factor @@ -13,8 +13,7 @@ C: live-range TUPLE: live-interval vreg reg spill-to reload-from -start end ranges uses -copy-from ; +start end ranges uses ; GENERIC: covers? ( insn# obj -- ? ) @@ -102,15 +101,6 @@ M: vreg-insn compute-live-intervals* [ [ temp-vregs ] 2dip '[ [ _ ] dip _ handle-temp ] each ] 3tri ; -: record-copy ( insn -- ) - [ dst>> live-intervals get at ] [ src>> ] bi >>copy-from drop ; - -M: ##copy compute-live-intervals* - [ call-next-method ] [ record-copy ] bi ; - -M: ##copy-float compute-live-intervals* - [ call-next-method ] [ record-copy ] bi ; - : handle-live-out ( bb -- ) live-out keys basic-block get [ block-from ] [ block-to ] bi diff --git a/basis/compiler/cfg/mr/mr.factor b/basis/compiler/cfg/mr/mr.factor index cb198d5149..77d9f1ce18 100644 --- a/basis/compiler/cfg/mr/mr.factor +++ b/basis/compiler/cfg/mr/mr.factor @@ -1,12 +1,11 @@ ! Copyright (C) 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: compiler.cfg.linearization compiler.cfg.two-operand -compiler.cfg.gc-checks compiler.cfg.linear-scan -compiler.cfg.build-stack-frame compiler.cfg.rpo ; +USING: compiler.cfg.linearization compiler.cfg.gc-checks +compiler.cfg.linear-scan compiler.cfg.build-stack-frame +compiler.cfg.rpo ; IN: compiler.cfg.mr : build-mr ( cfg -- mr ) - convert-two-operand insert-gc-checks linear-scan flatten-cfg diff --git a/basis/compiler/cfg/optimizer/optimizer.factor b/basis/compiler/cfg/optimizer/optimizer.factor index 8e2df04cca..2026cdb4c3 100644 --- a/basis/compiler/cfg/optimizer/optimizer.factor +++ b/basis/compiler/cfg/optimizer/optimizer.factor @@ -11,6 +11,7 @@ compiler.cfg.value-numbering compiler.cfg.copy-prop compiler.cfg.dce compiler.cfg.write-barrier +compiler.cfg.two-operand compiler.cfg.ssa.destruction compiler.cfg.empty-blocks compiler.cfg.predecessors @@ -42,6 +43,7 @@ SYMBOL: check-optimizer? copy-propagation eliminate-dead-code eliminate-write-barriers + convert-two-operand destruct-ssa delete-empty-blocks ?check diff --git a/basis/compiler/cfg/ssa/destruction/destruction.factor b/basis/compiler/cfg/ssa/destruction/destruction.factor index 3e6172229a..02e48962cb 100644 --- a/basis/compiler/cfg/ssa/destruction/destruction.factor +++ b/basis/compiler/cfg/ssa/destruction/destruction.factor @@ -58,9 +58,13 @@ SYMBOL: copies GENERIC: prepare-insn ( insn -- ) -M: ##copy prepare-insn +: prepare-copy ( insn -- ) [ dst>> ] [ src>> ] bi 2array copies get push ; +M: ##copy prepare-insn prepare-copy ; + +M: ##copy-float prepare-insn prepare-copy ; + M: ##phi prepare-insn [ dst>> ] [ inputs>> values ] bi [ eliminate-copy ] with each ; @@ -81,8 +85,10 @@ M: insn prepare-insn drop ; [ 2drop ] [ eliminate-copy ] if ] assoc-each ; +UNION: copy-insn ##copy ##copy-float ; + : useless-copy? ( ##copy -- ? ) - dup ##copy? [ [ dst>> ] [ src>> ] bi eq? ] [ drop f ] if ; + dup copy-insn? [ [ dst>> ] [ src>> ] bi eq? ] [ drop f ] if ; : perform-renaming ( cfg -- ) leader-map get keys [ dup leader ] H{ } map>assoc renamings set @@ -95,13 +101,11 @@ M: insn prepare-insn drop ; ] each-basic-block ; : destruct-ssa ( cfg -- cfg' ) - dup cfg-has-phis? [ - dup construct-cssa - dup compute-defs - dup compute-dominance - compute-ssa-live-sets - dup compute-live-ranges - dup prepare-coalescing - process-copies - dup perform-renaming - ] when ; \ No newline at end of file + dup construct-cssa + dup compute-defs + dup compute-dominance + compute-ssa-live-sets + dup compute-live-ranges + dup prepare-coalescing + process-copies + dup perform-renaming ; \ No newline at end of file diff --git a/basis/compiler/cfg/ssa/interference/interference.factor b/basis/compiler/cfg/ssa/interference/interference.factor index dd002ec977..a76b55cd83 100644 --- a/basis/compiler/cfg/ssa/interference/interference.factor +++ b/basis/compiler/cfg/ssa/interference/interference.factor @@ -6,6 +6,11 @@ compiler.cfg.def-use compiler.cfg.dominance compiler.cfg.ssa.interference.live-ranges ; IN: compiler.cfg.ssa.interference +! Interference testing using SSA properties. Actually the only SSA property +! used here is that definitions dominate uses; because of this, the input +! is allowed to have multiple definitions of each vreg as long as they're +! all in the same basic block. This is needed because two-operand conversion +! runs before coalescing, which uses SSA interference testing. [ 2drop 2drop f ] } cond ; -! Debug this stuff later > ] [ src1>> ] bi = ; inline - -: case-1 ( insn -- ) , ; inline - -: case-2? ( insn -- ? ) [ dst>> ] [ src2>> ] bi = ; inline - -: case-2 ( insn -- ) - dup dst>> reg-class>> next-vreg - [ swap src2>> emit-copy ] - [ drop [ src2>> ] [ src1>> ] bi emit-copy ] - [ >>src2 dup dst>> >>src1 , ] - 2tri ; inline - -: case-3 ( insn -- ) +M: two-operand-insn convert-two-operand* [ [ dst>> ] [ src1>> ] bi emit-copy ] [ dup dst>> >>src1 , ] - bi ; inline - -M: two-operand-insn convert-two-operand* - { - { [ dup case-1? ] [ case-1 ] } - { [ dup case-2? ] [ case-2 ] } - [ case-3 ] - } cond ; inline + bi ; M: ##not convert-two-operand* - dup [ dst>> ] [ src>> ] bi = [ - [ [ dst>> ] [ src>> ] bi ##copy ] - [ dup dst>> >>src ] - bi - ] unless , ; + [ [ dst>> ] [ src>> ] bi emit-copy ] + [ dup dst>> >>src , ] + bi ; M: insn convert-two-operand* , ; From dba67b18156f24a3df31feaeaec5c33b7a1291ba Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 5 Aug 2009 22:45:56 -0500 Subject: [PATCH 12/17] ui.gadgets.tables: little cleanup --- basis/ui/gadgets/tables/tables.factor | 95 +++++++++++++++++---------- 1 file changed, 59 insertions(+), 36 deletions(-) diff --git a/basis/ui/gadgets/tables/tables.factor b/basis/ui/gadgets/tables/tables.factor index bb70173455..eba646d08a 100644 --- a/basis/ui/gadgets/tables/tables.factor +++ b/basis/ui/gadgets/tables/tables.factor @@ -1,13 +1,12 @@ ! Copyright (C) 2008, 2009 Slava Pestov. ! See http://factorcode.org/license.txt for BSD license. -USING: accessors arrays colors colors.constants fry kernel math -math.functions math.ranges math.rectangles math.order math.vectors -models.illusion namespaces opengl sequences ui.gadgets +USING: accessors assocs hashtables arrays colors colors.constants fry +kernel math math.functions math.ranges math.rectangles math.order +math.vectors namespaces opengl sequences ui.gadgets ui.gadgets.scrollers ui.gadgets.status-bar ui.gadgets.worlds ui.gestures ui.render ui.pens.solid ui.text ui.commands ui.images -ui.gadgets.menus ui.gadgets.line-support models -combinators combinators.short-circuit -fonts locals strings sequences.extras sets ; +ui.gadgets.menus ui.gadgets.line-support models combinators +combinators.short-circuit fonts locals strings sets sorting ; IN: ui.gadgets.tables ! Row rendererer protocol @@ -52,15 +51,23 @@ multiple-selection? ; array ] change-selected-indices ; -: multiple>single ( values -- value/f ? ) [ f f ] [ first t ] if-empty ; -: multiple>single* ( values -- value/f ) multiple>single drop ; -: selected-index ( table -- n ) selected-indices>> multiple>single* ; -: set-selected-index ( table n -- table ) 1array >>selected-indices ; +: add-selected-index ( table n -- table ) + over selected-indices>> conjoin ; + +: multiple>single ( values -- value/f ? ) + dup assoc-empty? [ drop f f ] [ keys first t ] if ; + +: selected-index ( table -- n ) + selected-indices>> multiple>single drop ; + +: set-selected-index ( table n -- table ) + dup associate >>selected-indices ; + PRIVATE> -: selected ( table -- index/indices ) dup multiple-selection?>> - [ selected-indices>> ] [ selected-index ] if ; + +: selected ( table -- index/indices ) + [ selected-indices>> ] [ multiple-selection?>> ] bi + [ multiple>single drop ] unless ; : new-table ( rows renderer class -- table ) new-line-gadget @@ -70,7 +77,8 @@ PRIVATE> focus-border-color >>focus-border-color transparent >>column-line-color f >>selection-index - f >>selection ; + f >>selection + H{ } clone >>selected-indices ; : ( rows renderer -- table ) table new-table ; @@ -150,9 +158,9 @@ M: table layout* : draw-selected-rows ( table -- ) { - { [ dup selected-indices>> empty? ] [ drop ] } + { [ dup selected-indices>> assoc-empty? ] [ drop ] } [ - [ selected-indices>> ] [ selection-color>> gl-color ] [ ] tri + [ selected-indices>> keys ] [ selection-color>> gl-color ] [ ] tri [ swap row-bounds gl-fill-rect ] curry each ] } cond ; @@ -209,7 +217,8 @@ M: table layout* :: row-font ( row ind table -- font ) table font>> clone row table renderer>> row-color [ >>foreground ] when* - ind table selected-indices>> index [ table selection-color>> >>background ] when ; + ind table selected-indices>> key? + [ table selection-color>> >>background ] when ; : draw-columns ( columns widths alignment font gap -- ) '[ [ _ ] 3dip _ draw-column ] 3each ; @@ -254,23 +263,32 @@ M: table pref-dim* PRIVATE> : (selected-rows) ( table -- {row} ) - [ selected-indices>> ] keep - [ nth-row [ 1array ] [ drop { } ] if ] curry map concat ; + [ selected-indices>> keys natural-sort ] keep + '[ _ nth-row [ 1array ] [ drop { } ] if ] map concat ; : selected-rows ( table -- {value} ) - [ (selected-rows) ] [ renderer>> ] bi [ row-value ] curry map ; + [ (selected-rows) ] [ renderer>> ] bi '[ _ row-value ] map ; + : (selected-row) ( table -- value/f ? ) (selected-rows) multiple>single ; + : selected-row ( table -- value/f ? ) selected-rows multiple>single ; single* ] unless swap set-model ; + [ multiple>single drop ] unless swap set-model ; : update-selected ( table -- ) - [ [ selection>> ] [ selected-rows ] [ multiple-selection?>> ] tri set-table-model ] [ - [ selection-index>> ] [ selected-indices>> ] [ multiple-selection?>> ] tri + [ selection>> ] + [ selected-rows ] + [ multiple-selection?>> ] tri + set-table-model + ] + [ + [ selection-index>> ] + [ selected-indices>> ] + [ multiple-selection?>> ] tri set-table-model ] bi ; @@ -286,17 +304,17 @@ PRIVATE> : find-row-index ( value table -- n/f ) [ model>> value>> ] [ renderer>> '[ _ row-value ] map index ] bi ; -: initial-selected-indices ( table -- {n}/f ) +: (update-selected-indices) ( table -- set ) + [ selection>> value>> dup array? [ 1array ] unless ] keep + [ find-row-index ] curry map sift unique f like ; + +: initial-selected-indices ( table -- set ) { [ model>> value>> empty? not ] [ selection-required?>> ] - [ drop { 0 } ] + [ drop { 0 } unique ] } 1&& ; -: (update-selected-indices) ( table -- {n}/f ) - [ selection>> value>> dup array? [ 1array ] unless ] keep - [ find-row-index ] curry map [ ] filter [ f ] when-empty ; - : update-selected-indices ( table -- {n}/f ) { [ (update-selected-indices) ] @@ -304,7 +322,7 @@ PRIVATE> } 1|| ; M: table model-changed - nip dup update-selected-indices [ { } ] unless* { + nip dup update-selected-indices { [ >>selected-indices f >>mouse-index drop ] [ [ f ] [ first ] if-empty show-row-summary ] [ drop update-selected ] @@ -319,7 +337,7 @@ M: table model-changed : add-selected-row ( table n -- ) [ scroll-to-row ] - [ push-selected-index relayout-1 ] 2bi ; + [ add-selected-index relayout-1 ] 2bi ; : (select-row) ( table n -- ) [ scroll-to-row ] @@ -337,12 +355,17 @@ M: table model-changed dup takes-focus?>> [ dup request-focus ] when swap '[ swap [ >>mouse-index ] _ bi ] [ drop ] if-mouse-row ; inline -: table-button-down ( table -- ) [ (select-row) ] swap (table-button-down) ; -: continued-button-down ( table -- ) dup multiple-selection?>> +: table-button-down ( table -- ) + [ (select-row) ] swap (table-button-down) ; + +: continued-button-down ( table -- ) + dup multiple-selection?>> [ [ add-selected-row ] swap (table-button-down) ] [ table-button-down ] if ; -: thru-button-down ( table -- ) dup multiple-selection?>> [ + +: thru-button-down ( table -- ) + dup multiple-selection?>> [ [ 2dup over selected-index (a,b) swap - [ swap push-selected-index drop ] curry each add-selected-row ] + [ swap add-selected-index drop ] curry each add-selected-row ] swap (table-button-down) ] [ table-button-down ] if ; From 926797d4859b0967b5e63e001709820ef132a529 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 5 Aug 2009 22:56:08 -0500 Subject: [PATCH 13/17] ui.gadgets.tables: more fixes --- basis/ui/gadgets/tables/tables.factor | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/basis/ui/gadgets/tables/tables.factor b/basis/ui/gadgets/tables/tables.factor index eba646d08a..3856553b96 100644 --- a/basis/ui/gadgets/tables/tables.factor +++ b/basis/ui/gadgets/tables/tables.factor @@ -55,7 +55,7 @@ multiple-selection? ; over selected-indices>> conjoin ; : multiple>single ( values -- value/f ? ) - dup assoc-empty? [ drop f f ] [ keys first t ] if ; + dup assoc-empty? [ drop f f ] [ values first t ] if ; : selected-index ( table -- n ) selected-indices>> multiple>single drop ; @@ -262,12 +262,13 @@ M: table pref-dim* PRIVATE> -: (selected-rows) ( table -- {row} ) - [ selected-indices>> keys natural-sort ] keep - '[ _ nth-row [ 1array ] [ drop { } ] if ] map concat ; +: (selected-rows) ( table -- assoc ) + [ selected-indices>> ] keep + '[ _ nth-row drop ] assoc-map ; -: selected-rows ( table -- {value} ) - [ (selected-rows) ] [ renderer>> ] bi '[ _ row-value ] map ; +: selected-rows ( table -- assoc ) + [ selected-indices>> ] [ ] [ renderer>> ] tri + '[ _ nth-row drop _ row-value ] assoc-map ; : (selected-row) ( table -- value/f ? ) (selected-rows) multiple>single ; @@ -306,7 +307,7 @@ PRIVATE> : (update-selected-indices) ( table -- set ) [ selection>> value>> dup array? [ 1array ] unless ] keep - [ find-row-index ] curry map sift unique f like ; + [ find-row-index ] curry map sift unique f assoc-like ; : initial-selected-indices ( table -- set ) { @@ -315,7 +316,7 @@ PRIVATE> [ drop { 0 } unique ] } 1&& ; -: update-selected-indices ( table -- {n}/f ) +: update-selected-indices ( table -- set ) { [ (update-selected-indices) ] [ initial-selected-indices ] @@ -324,7 +325,7 @@ PRIVATE> M: table model-changed nip dup update-selected-indices { [ >>selected-indices f >>mouse-index drop ] - [ [ f ] [ first ] if-empty show-row-summary ] + [ multiple>single drop show-row-summary ] [ drop update-selected ] [ drop relayout ] } 2cleave ; From 311774cb687757c4d7574c661d1acf51343963d8 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 5 Aug 2009 22:56:19 -0500 Subject: [PATCH 14/17] modules.rpc-server: don't start server by default --- extra/modules/rpc-server/rpc-server.factor | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/extra/modules/rpc-server/rpc-server.factor b/extra/modules/rpc-server/rpc-server.factor index 073804fa8c..d82f13f715 100644 --- a/extra/modules/rpc-server/rpc-server.factor +++ b/extra/modules/rpc-server/rpc-server.factor @@ -20,12 +20,12 @@ SYMBOL: serving-vocabs serving-vocabs [ V{ } clone ] initialize PRIVATE> SYNTAX: service current-vocab name>> serving-vocabs get-global adjoin ; -[ [ binary +: start-rpc-server ( -- ) + binary "rpcs" >>name 9012 >>insecure [ deserialize { { "getter" [ getter ] } { "doer" [ doer ] } { "loader" [ deserialize vocab serialize flush ] } } case ] >>handler - start-server ] in-thread -] "modules.rpc-server" add-init-hook \ No newline at end of file + start-server ; From b4f97dc63293cdbddaf1e097a280955e77f6e1c7 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 5 Aug 2009 23:04:34 -0500 Subject: [PATCH 15/17] vocabs.hierarchy: load word now tries to load the vocab named by the prefix itself --- basis/vocabs/hierarchy/hierarchy.factor | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/basis/vocabs/hierarchy/hierarchy.factor b/basis/vocabs/hierarchy/hierarchy.factor index aa3e619660..9352e81afc 100644 --- a/basis/vocabs/hierarchy/hierarchy.factor +++ b/basis/vocabs/hierarchy/hierarchy.factor @@ -107,8 +107,9 @@ MEMO: all-vocabs-recursive ( -- assoc ) PRIVATE> : (load) ( prefix -- failures ) - child-vocabs-recursive no-roots no-prefixes - filter-unportable + [ child-vocabs-recursive no-roots no-prefixes ] + [ dup find-vocab-root [ >vocab-link ] [ drop f ] if ] bi + prefix filter-unportable require-all ; : load ( prefix -- ) From 7734bd9bcdce70d113e94c6cf9c80e5dae1379c2 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Wed, 5 Aug 2009 23:08:14 -0500 Subject: [PATCH 16/17] vocabs.hierarchy: fix load-all --- basis/vocabs/hierarchy/hierarchy.factor | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/basis/vocabs/hierarchy/hierarchy.factor b/basis/vocabs/hierarchy/hierarchy.factor index 9352e81afc..b840b5ab9d 100644 --- a/basis/vocabs/hierarchy/hierarchy.factor +++ b/basis/vocabs/hierarchy/hierarchy.factor @@ -108,8 +108,8 @@ PRIVATE> : (load) ( prefix -- failures ) [ child-vocabs-recursive no-roots no-prefixes ] - [ dup find-vocab-root [ >vocab-link ] [ drop f ] if ] bi - prefix filter-unportable + [ dup find-vocab-root [ >vocab-link prefix ] [ drop ] if ] bi + filter-unportable require-all ; : load ( prefix -- ) From ef97fdf0c5573eb387075a1dc3412d17942bf065 Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Thu, 6 Aug 2009 01:28:30 -0500 Subject: [PATCH 17/17] ui.gadgets.tables: some band-aid fixes --- basis/ui/gadgets/tables/tables-tests.factor | 19 +++++++++++++++++-- basis/ui/gadgets/tables/tables.factor | 7 ++++--- basis/ui/tools/profiler/profiler.factor | 6 +++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/basis/ui/gadgets/tables/tables-tests.factor b/basis/ui/gadgets/tables/tables-tests.factor index 3191753324..b92f72a2dd 100644 --- a/basis/ui/gadgets/tables/tables-tests.factor +++ b/basis/ui/gadgets/tables/tables-tests.factor @@ -1,6 +1,6 @@ IN: ui.gadgets.tables.tests USING: ui.gadgets.tables ui.gadgets.scrollers ui.gadgets.debug accessors -models namespaces tools.test kernel combinators ; +models namespaces tools.test kernel combinators prettyprint arrays ; SINGLETON: test-renderer @@ -44,4 +44,19 @@ M: test-renderer column-titles drop { "First" "Last" } ; [ selected-row drop ] } cleave ] with-grafted-gadget -] unit-test \ No newline at end of file +] unit-test + +SINGLETON: silly-renderer + +M: silly-renderer row-columns drop unparse 1array ; + +M: silly-renderer column-titles drop { "Foo" } ; + +: test-table-2 ( -- table ) + { 1 2 f } silly-renderer
; + +[ f f ] [ + test-table dup [ + selected-row + ] with-grafted-gadget +] unit-test diff --git a/basis/ui/gadgets/tables/tables.factor b/basis/ui/gadgets/tables/tables.factor index 3856553b96..225cf90d8c 100644 --- a/basis/ui/gadgets/tables/tables.factor +++ b/basis/ui/gadgets/tables/tables.factor @@ -303,11 +303,12 @@ PRIVATE> f >>mouse-index [ hide-status ] [ relayout-1 ] bi ; : find-row-index ( value table -- n/f ) - [ model>> value>> ] [ renderer>> '[ _ row-value ] map index ] bi ; + [ model>> value>> ] [ renderer>> ] bi + '[ _ row-value eq? ] with find drop ; : (update-selected-indices) ( table -- set ) - [ selection>> value>> dup array? [ 1array ] unless ] keep - [ find-row-index ] curry map sift unique f assoc-like ; + [ selection>> value>> dup [ array? not ] [ ] bi and [ 1array ] when ] keep + '[ _ find-row-index ] map sift unique f assoc-like ; : initial-selected-indices ( table -- set ) { diff --git a/basis/ui/tools/profiler/profiler.factor b/basis/ui/tools/profiler/profiler.factor index 8be357b409..c3fbdb88cd 100644 --- a/basis/ui/tools/profiler/profiler.factor +++ b/basis/ui/tools/profiler/profiler.factor @@ -147,7 +147,7 @@ M: method-renderer column-titles drop { "" "Method" "Count" } ; horizontal { 3 3 } >>gap profiler vocabs>> vocab-renderer - profiler vocab>> >>selected-value + profiler vocab>> >>selection 10 >>min-rows 10 >>max-rows "Vocabularies" @@ -164,11 +164,11 @@ M: method-renderer column-titles drop { "" "Method" "Count" } ; horizontal { 3 3 } >>gap profiler word-renderer - profiler generic>> >>selected-value + profiler generic>> >>selection "Generic words" 1/2 track-add profiler word-renderer - profiler class>> >>selected-value + profiler class>> >>selection "Classes" 1/2 track-add 1/2 track-add