inline annotation for combinators; faster stack checker taking advantage of this fact; started dataflow IR

cvs
Slava Pestov 2004-11-27 05:33:17 +00:00
parent 9680d5b6bb
commit 15a07f6f40
14 changed files with 132 additions and 70 deletions

View File

@ -25,6 +25,7 @@
+ listener/plugin: + listener/plugin:
- console: wrong history
- listener: if too many things popped off the stack, complain - listener: if too many things popped off the stack, complain
- gracefully handle non-working cfactor - gracefully handle non-working cfactor
- NPE in ErrorHighlight - NPE in ErrorHighlight

View File

@ -102,6 +102,7 @@ USE: stdio
"/library/tools/heap-stats.factor" "/library/tools/heap-stats.factor"
"/library/gensym.factor" "/library/gensym.factor"
"/library/tools/interpreter.factor" "/library/tools/interpreter.factor"
"/library/inference/dataflow.factor"
"/library/inference/inference.factor" "/library/inference/inference.factor"
"/library/inference/words.factor" "/library/inference/words.factor"
"/library/inference/branches.factor" "/library/inference/branches.factor"

View File

@ -42,16 +42,16 @@ USE: stack
: keep ( a quot -- a ) : keep ( a quot -- a )
#! Execute the quotation with a on the stack, and restore a #! Execute the quotation with a on the stack, and restore a
#! after the quotation returns. #! after the quotation returns.
over >r call r> ; over >r call r> ; inline
: 2keep ( a b quot -- a b ) : 2keep ( a b quot -- a b )
#! Execute the quotation with a and b on the stack, and #! Execute the quotation with a and b on the stack, and
#! restore a and b after the quotation returns. #! restore a and b after the quotation returns.
over >r pick >r call r> r> ; over >r pick >r call r> r> ; inline
: apply ( code input -- code output ) : apply ( code input -- code output )
#! Apply code to input. #! Apply code to input.
swap dup >r call r> swap ; swap dup >r call r> swap ; inline
: cond ( x list -- ) : cond ( x list -- )
#! The list is of this form: #! The list is of this form:
@ -86,8 +86,7 @@ USE: stack
#! If the condition is not f, execute the 'true' quotation, #! If the condition is not f, execute the 'true' quotation,
#! with the condition on the stack. Otherwise, pop the #! with the condition on the stack. Otherwise, pop the
#! condition and execute the 'false' quotation. #! condition and execute the 'false' quotation.
pick [ drop call ] [ nip nip call ] ifte ; pick [ drop call ] [ nip nip call ] ifte ; inline
inline
: unless ( cond quot -- ) : unless ( cond quot -- )
#! Execute a quotation only when the condition is f. The #! Execute a quotation only when the condition is f. The

View File

@ -42,13 +42,16 @@ USE: hashtables
DEFER: (infer) DEFER: (infer)
: (effect) ( -- [ in | stack ] ) : infer-branch ( quot -- [ in-d | datastack ] dataflow )
d-in get meta-d get cons ;
: infer-branch ( quot -- [ in-d | datastack ] )
#! Infer the quotation's effect, restoring the meta #! Infer the quotation's effect, restoring the meta
#! interpreter state afterwards. #! interpreter state afterwards.
[ copy-interpreter (infer) (effect) ] with-scope ; [
copy-interpreter
dataflow-graph off
(infer)
d-in get meta-d get cons
get-dataflow
] with-scope ;
: difference ( [ in | stack ] -- diff ) : difference ( [ in | stack ] -- diff )
#! Stack height difference of infer-branch return value. #! Stack height difference of infer-branch return value.
@ -87,23 +90,28 @@ DEFER: (infer)
"Unbalanced branches" throw "Unbalanced branches" throw
] ifte ; ] ifte ;
: recursive-branch ( quot -- ) : recursive-branch ( quot -- ? )
#! Set base case if inference didn't fail #! Set base case if inference didn't fail.
[ [
car infer-branch recursive-state get set-base car infer-branch drop recursive-state get set-base t
] [ ] [
[ drop ] when [ drop f ] when
] catch ; ] catch ;
: infer-branches ( brachlist -- ) : infer-branches ( consume instruction brachlist -- )
#! Recursive stack effect inference is done here. If one of #! Recursive stack effect inference is done here. If one of
#! the branches has an undecidable stack effect, we set the #! the branches has an undecidable stack effect, we set the
#! base case to this stack effect and try again. #! base case to this stack effect and try again.
dup [ recursive-branch ] each f over [ recursive-branch or ] each [
[ car infer-branch ] map unify ; [ [ car infer-branch , ] map ] make-list swap
>r dataflow, r> unify
] [
"Foo!" throw
] ifte ;
: infer-ifte ( -- ) : infer-ifte ( -- )
#! Infer effects for both branches, unify. #! Infer effects for both branches, unify.
3 IFTE
pop-d pop-d 2list pop-d pop-d 2list
pop-d drop ( condition ) pop-d drop ( condition )
infer-branches ; infer-branches ;
@ -118,12 +126,14 @@ DEFER: (infer)
: infer-generic ( -- ) : infer-generic ( -- )
#! Infer effects for all branches, unify. #! Infer effects for all branches, unify.
2 GENERIC
pop-d vtable>list pop-d vtable>list
peek-d drop ( dispatch ) peek-d drop ( dispatch )
infer-branches ; infer-branches ;
: infer-2generic ( -- ) : infer-2generic ( -- )
#! Infer effects for all branches, unify. #! Infer effects for all branches, unify.
3 2GENERIC
pop-d vtable>list pop-d vtable>list
peek-d drop ( dispatch ) peek-d drop ( dispatch )
peek-d drop ( dispatch ) peek-d drop ( dispatch )

View File

@ -0,0 +1,59 @@
! :folding=indent:collapseFolds=1:
! $Id$
!
! Copyright (C) 2004 Slava Pestov.
!
! Redistribution and use in source and binary forms, with or without
! modification, are permitted provided that the following conditions are met:
!
! 1. Redistributions of source code must retain the above copyright notice,
! this list of conditions and the following disclaimer.
!
! 2. Redistributions in binary form must reproduce the above copyright notice,
! this list of conditions and the following disclaimer in the documentation
! and/or other materials provided with the distribution.
!
! THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
! INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
! FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
! DEVELOPERS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
! SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
! PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
! OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
! WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
! OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
! ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
IN: inference
USE: lists
USE: namespaces
USE: stack
! We build a dataflow graph for the compiler.
SYMBOL: dataflow-graph
SYMBOL: CALL ( non-tail call )
SYMBOL: JUMP ( tail-call )
SYMBOL: PUSH ( literal )
SYMBOL: IFTE
SYMBOL: GENERIC
SYMBOL: 2GENERIC
: get-dataflow ( -- IR )
dataflow-graph get reverse ;
: dataflow, ( consume instruction parameters -- )
#! Add a node to the dataflow IR. Each node is a list of
#! three elements:
#! - list of elements consumed from stack
#! - a symbol CALL, JUMP or PUSH
#! - parameter(s) to insn
unit cons cons dataflow-graph cons@ ;
: dataflow-literal, ( lit -- )
>r 0 PUSH r> dataflow, ;
: dataflow-word, ( in word -- )
>r count CALL r> dataflow, ;

View File

@ -55,13 +55,6 @@ SYMBOL: recursive-state
SYMBOL: base-case SYMBOL: base-case
SYMBOL: entry-effect SYMBOL: entry-effect
! We build a dataflow graph for the compiler.
SYMBOL: dataflow-graph
: dataflow, ( obj -- )
#! Add a node to the dataflow IR.
dataflow-graph cons@ ;
: gensym-vector ( n -- vector ) : gensym-vector ( n -- vector )
dup <vector> swap [ gensym over vector-push ] times ; dup <vector> swap [ gensym over vector-push ] times ;
@ -115,21 +108,14 @@ SYMBOL: dataflow-graph
DEFER: apply-word DEFER: apply-word
: apply-literal ( obj -- )
#! Literals are annotated with the current recursive
#! state.
dup dataflow-literal, recursive-state get cons push-d ;
: apply-object ( obj -- ) : apply-object ( obj -- )
#! Apply the object's stack effect to the inferencer state. #! Apply the object's stack effect to the inferencer state.
#! There are three options: recursive-infer words always dup word? [ apply-word ] [ apply-literal ] ifte ;
#! cause a recursive call of the inferencer, regardless.
#! Be careful, you might hang the inferencer. Other words
#! solve a fixed-point equation if a recursive call is made,
#! otherwise the inferencer is invoked recursively if its
#! not a recursive call.
dup word? [
apply-word
] [
#! Literals are annotated with the current recursive
#! state.
dup dataflow, recursive-state get cons push-d
] ifte ;
: (infer) ( quot -- ) : (infer) ( quot -- )
#! Recursive calls to this word are made for nested #! Recursive calls to this word are made for nested
@ -158,10 +144,11 @@ DEFER: apply-word
: infer ( quot -- [ in | out ] ) : infer ( quot -- [ in | out ] )
#! Stack effect of a quotation. #! Stack effect of a quotation.
[ [ f init-inference (infer) effect ] with-scope ;
f init-inference (infer) effect
( dataflow-graph get USE: prettyprint . ) : dataflow ( quot -- dataflow )
] with-scope ; #! Data flow of a quotation.
[ f init-inference (infer) get-dataflow ] with-scope ;
: try-infer ( quot -- effect/f ) : try-infer ( quot -- effect/f )
#! Push f if inference fails. #! Push f if inference fails.

View File

@ -45,6 +45,7 @@ USE: hashtables
#! either execute the word in the meta interpreter (if it is #! either execute the word in the meta interpreter (if it is
#! side-effect-free and all parameters are literal), or #! side-effect-free and all parameters are literal), or
#! simply apply its stack effect to the meta-interpreter. #! simply apply its stack effect to the meta-interpreter.
dup car pick dataflow-word,
swap "infer" word-property dup [ swap "infer" word-property dup [
swap car ensure-d call swap car ensure-d call
] [ ] [
@ -69,17 +70,11 @@ USE: hashtables
: apply-compound ( word -- ) : apply-compound ( word -- )
#! Infer a compound word's stack effect. #! Infer a compound word's stack effect.
dup "inline-infer" word-property [ dup "inline" word-property [
inline-compound inline-compound
] [ ] [
[ dup infer-compound dup car rot dataflow-word,
dup dataflow, infer-compound consume/produce consume/produce
] [
[
dup t "inline-infer" set-word-property
inline-compound
] when
] catch
] ifte ; ] ifte ;
: current-word ( -- word ) : current-word ( -- word )
@ -112,18 +107,25 @@ USE: hashtables
check-recursion recursive-word check-recursion recursive-word
] [ ] [
drop dup "infer-effect" word-property dup [ drop dup "infer-effect" word-property dup [
over dataflow,
apply-effect apply-effect
] [ ] [
drop dup compound? [ apply-compound ] [ no-effect ] ifte drop
[
[ compound? ] [ apply-compound ]
[ symbol? ] [ apply-literal ]
[ drop t ] [ no-effect ]
] cond
] ifte ] ifte
] ifte ; ] ifte ;
: infer-call ( [ rstate | quot ] -- ) : infer-call ( [ rstate | quot ] -- )
1 \ drop dataflow-word,
[ [
dataflow-graph off
pop-d uncons recursive-state set (infer) pop-d uncons recursive-state set (infer)
d-in get meta-d get d-in get meta-d get get-dataflow
] with-scope meta-d set d-in set ; ] with-scope
[ dataflow-graph cons@ ] each meta-d set d-in set ;
\ call [ infer-call ] "infer" set-word-property \ call [ infer-call ] "infer" set-word-property

View File

@ -59,11 +59,12 @@ USE: stack
#! objects to the list that is returned when the quotation #! objects to the list that is returned when the quotation
#! is done. #! is done.
[ "list-buffer" off call "list-buffer" get ] with-scope ; [ "list-buffer" off call "list-buffer" get ] with-scope ;
inline
: make-list ( quot -- list ) : make-list ( quot -- list )
#! Return a list whose entries are in the same order that , #! Return a list whose entries are in the same order that ,
#! was called. #! was called.
make-rlist reverse ; make-rlist reverse ; inline
: , ( obj -- ) : , ( obj -- )
#! Append an object to the currently constructing list. #! Append an object to the currently constructing list.

View File

@ -76,7 +76,7 @@ USE: vectors
dup cons? [ tail ] when not ; dup cons? [ tail ] when not ;
: partition-add ( obj ? ret1 ret2 -- ret1 ret2 ) : partition-add ( obj ? ret1 ret2 -- ret1 ret2 )
rot [ swapd cons ] [ >r cons r> ] ifte ; inline rot [ swapd cons ] [ >r cons r> ] ifte ;
: partition-step ( ref list combinator -- ref cdr combinator car ? ) : partition-step ( ref list combinator -- ref cdr combinator car ? )
pick pick car pick call >r >r unswons r> swap r> ; inline pick pick car pick call >r >r unswons r> swap r> ; inline
@ -141,8 +141,7 @@ DEFER: tree-contains?
: each ( list quot -- ) : each ( list quot -- )
#! Push each element of a proper list in turn, and apply a #! Push each element of a proper list in turn, and apply a
#! quotation with effect ( X -- ) to each element. #! quotation with effect ( X -- ) to each element.
over [ (each) each ] [ 2drop ] ifte ; over [ (each) each ] [ 2drop ] ifte ; inline
inline
: reverse ( list -- list ) : reverse ( list -- list )
[ ] swap [ swons ] each ; [ ] swap [ swons ] each ;
@ -151,8 +150,7 @@ DEFER: tree-contains?
#! Push each element of a proper list in turn, and collect #! Push each element of a proper list in turn, and collect
#! return values of applying a quotation with effect #! return values of applying a quotation with effect
#! ( X -- Y ) to each element into a new list. #! ( X -- Y ) to each element into a new list.
over [ (each) rot >r map r> swons ] [ drop ] ifte ; over [ (each) rot >r map r> swons ] [ drop ] ifte ; inline
inline
: subset ( list quot -- list ) : subset ( list quot -- list )
#! Applies a quotation with effect ( X -- ? ) to each #! Applies a quotation with effect ( X -- ? ) to each

View File

@ -38,12 +38,12 @@ USE: stack
#! Call a quotation. The quotation can call , to prepend #! Call a quotation. The quotation can call , to prepend
#! objects to the list that is returned when the quotation #! objects to the list that is returned when the quotation
#! is done. #! is done.
make-list cat ; make-list cat ; inline
: make-rstring ( quot -- string ) : make-rstring ( quot -- string )
#! Return a string whose entries are in the same order that , #! Return a string whose entries are in the same order that ,
#! was called. #! was called.
make-rlist cat ; make-rlist cat ; inline
: fill ( count char -- string ) : fill ( count char -- string )
#! Push a string that consists of the same character #! Push a string that consists of the same character
@ -56,7 +56,7 @@ USE: stack
#! The quotation must have stack effect ( X -- X ). #! The quotation must have stack effect ( X -- X ).
over str-length <sbuf> rot [ over str-length <sbuf> rot [
swap >r apply r> tuck sbuf-append swap >r apply r> tuck sbuf-append
] str-each nip sbuf>str ; ] str-each nip sbuf>str ; inline
: split-next ( index string split -- next ) : split-next ( index string split -- next )
3dup index-of* dup -1 = [ 3dup index-of* dup -1 = [

View File

@ -143,7 +143,7 @@ USE: stack
#! pushed onto the stack. #! pushed onto the stack.
over str-length [ over str-length [
-rot 2dup >r >r >r str-nth r> call r> r> -rot 2dup >r >r >r str-nth r> call r> r>
] times* 2drop ; ] times* 2drop ; inline
: str-sort ( list -- sorted ) : str-sort ( list -- sorted )
#! Sorts the list into ascending lexicographical string #! Sorts the list into ascending lexicographical string

View File

@ -147,6 +147,10 @@ DEFER: foe
[ [ 1 | 0 ] ] [ [ nested-when* ] infer ] unit-test [ [ 1 | 0 ] ] [ [ nested-when* ] infer ] unit-test
SYMBOL: sym-test
[ [ 0 | 1 ] ] [ [ sym-test ] infer ] unit-test
[ [ 2 | 1 ] ] [ [ fie ] infer ] unit-test [ [ 2 | 1 ] ] [ [ fie ] infer ] unit-test
[ [ 2 | 1 ] ] [ [ foe ] infer ] unit-test [ [ 2 | 1 ] ] [ [ foe ] infer ] unit-test

View File

@ -38,7 +38,7 @@ USE: stack
#! pushed onto the stack. #! pushed onto the stack.
over vector-length [ over vector-length [
-rot 2dup >r >r >r vector-nth r> call r> r> -rot 2dup >r >r >r vector-nth r> call r> r>
] times* 2drop ; ] times* 2drop ; inline
: vector-map ( vector code -- vector ) : vector-map ( vector code -- vector )
#! Applies code to each element of the vector, return a new #! Applies code to each element of the vector, return a new
@ -46,14 +46,14 @@ USE: stack
#! ( obj -- obj ). #! ( obj -- obj ).
over vector-length <vector> rot [ over vector-length <vector> rot [
swap >r apply r> tuck vector-push swap >r apply r> tuck vector-push
] vector-each nip ; ] vector-each nip ; inline
: vector-and ( vector -- ? ) : vector-and ( vector -- ? )
#! Logical and of all elements in the vector. #! Logical and of all elements in the vector.
t swap [ and ] vector-each ; t swap [ and ] vector-each ;
: vector-all? ( vector pred -- ? ) : vector-all? ( vector pred -- ? )
vector-map vector-and ; vector-map vector-and ; inline
: vector-append ( v1 v2 -- ) : vector-append ( v1 v2 -- )
#! Destructively append v2 to v1. #! Destructively append v2 to v1.
@ -65,7 +65,7 @@ USE: stack
#! in a new vector. #! in a new vector.
over <vector> rot [ over <vector> rot [
-rot 2dup >r >r slip vector-push r> r> -rot 2dup >r >r slip vector-push r> r>
] times* nip ; ] times* nip ; inline
: vector-zip ( v1 v2 -- v ) : vector-zip ( v1 v2 -- v )
#! Make a new vector with each pair of elements from the #! Make a new vector with each pair of elements from the
@ -81,4 +81,4 @@ USE: stack
#! differ. #! differ.
-rot vector-zip [ -rot vector-zip [
swap dup >r >r uncons r> call r> swap swap dup >r >r uncons r> call r> swap
] vector-map nip ; ] vector-map nip ; inline

View File

@ -72,7 +72,7 @@ DEFER: vector-map
: ?vector= ( n vec vec -- ? ) : ?vector= ( n vec vec -- ? )
#! Reached end? #! Reached end?
drop vector-length = ; drop vector-length number= ;
: (vector=) ( n vec vec -- ? ) : (vector=) ( n vec vec -- ? )
3dup ?vector= [ 3dup ?vector= [