From 6159c8240735c53ed093a2948a5936c46beed59c Mon Sep 17 00:00:00 2001 From: Slava Pestov Date: Fri, 31 Dec 2004 07:17:45 +0000 Subject: [PATCH] type check optimization is here --- TODO.FACTOR.txt | 5 --- library/bootstrap/boot-stage2.factor | 1 + library/compiler/alien.factor | 2 +- library/compiler/assembly-x86.factor | 4 ++ library/compiler/generator-x86.factor | 4 +- library/compiler/generator.factor | 4 ++ library/generic/generic.factor | 26 ++++++++--- library/generic/predicate.factor | 3 ++ library/inference/branches.factor | 65 ++++++++++++++------------- library/inference/inference.factor | 14 +++++- library/inference/types.factor | 29 ++++++++++-- library/inference/words.factor | 7 ++- library/kernel.factor | 2 + library/math/complex.factor | 4 +- library/math/ratio.factor | 4 +- library/primitives.factor | 2 +- library/strings.factor | 2 +- library/test/dataflow.factor | 6 +-- library/test/inference.factor | 48 ++++++-------------- library/words.factor | 8 +++- 20 files changed, 145 insertions(+), 95 deletions(-) diff --git a/TODO.FACTOR.txt b/TODO.FACTOR.txt index aa43a2f9d4..9bec611f5f 100644 --- a/TODO.FACTOR.txt +++ b/TODO.FACTOR.txt @@ -5,13 +5,8 @@ [error] AWT-EventQueue-0: at factor.jedit.WordPreview.actionPerformed(WordPreview.java:79) [error] AWT-EventQueue-0: at javax.swing.Timer.fireActionPerformed(Timer.java:271) -+ inference/dataflow: - -- type inference - + compiler: -- slot compilation - optimize away dispatch - getenv/setenv: if literal arg, compile as a load/store - assembler opcodes dispatch on operand types diff --git a/library/bootstrap/boot-stage2.factor b/library/bootstrap/boot-stage2.factor index a60881b94b..b8b569c475 100644 --- a/library/bootstrap/boot-stage2.factor +++ b/library/bootstrap/boot-stage2.factor @@ -117,6 +117,7 @@ USE: namespaces "/library/inference/branches.factor" "/library/inference/words.factor" "/library/inference/stack.factor" + "/library/inference/types.factor" "/library/compiler/assembler.factor" "/library/compiler/xt.factor" diff --git a/library/compiler/alien.factor b/library/compiler/alien.factor index 89b9808bf0..4e43285945 100644 --- a/library/compiler/alien.factor +++ b/library/compiler/alien.factor @@ -54,7 +54,7 @@ BUILTIN: dll 15 BUILTIN: alien 16 M: alien hashcode ( obj -- n ) - alien-address ; + alien-address >fixnum ; M: alien = ( obj obj -- ? ) over alien? [ diff --git a/library/compiler/assembly-x86.factor b/library/compiler/assembly-x86.factor index 5c4253d1b4..c74a973a6f 100644 --- a/library/compiler/assembly-x86.factor +++ b/library/compiler/assembly-x86.factor @@ -121,6 +121,10 @@ USE: math #! MOV INDIRECT TO . HEX: 8b compile-byte 0 MOD-R/M ; +: D[R]>R ( disp reg reg -- ) + #! MOV INDIRECT DISPLACED TO . + HEX: 8b compile-byte 1 MOD-R/M compile-byte ; + : R>[R] ( reg reg -- ) #! MOV TO INDIRECT . HEX: 89 compile-byte swap 0 MOD-R/M ; diff --git a/library/compiler/generator-x86.factor b/library/compiler/generator-x86.factor index 06cb3f1f4a..22712c3708 100644 --- a/library/compiler/generator-x86.factor +++ b/library/compiler/generator-x86.factor @@ -82,7 +82,9 @@ USE: math #slot [ PEEK-DS - + 2unlist type-tag >r cell * r> - EAX EAX D[R]>R + DS ECX [I]>R absolute-ds + EAX ECX R>[R] ] "generator" set-word-property #call [ diff --git a/library/compiler/generator.factor b/library/compiler/generator.factor index 75164c7031..72a7bd5b2a 100644 --- a/library/compiler/generator.factor +++ b/library/compiler/generator.factor @@ -105,3 +105,7 @@ SYMBOL: previous-offset ] catch ; #label [ save-xt ] "generator" set-word-property + +: type-tag ( type -- tag ) + #! Given a type number, return the tag number. + dup 6 > [ drop 3 ] when ; diff --git a/library/generic/generic.factor b/library/generic/generic.factor index ed57fda472..0dc345b5f2 100644 --- a/library/generic/generic.factor +++ b/library/generic/generic.factor @@ -168,13 +168,10 @@ SYMBOL: classes SYMBOL: object : type-union ( list list -- list ) - append prune [ > ] sort ; - -: type-intersection ( list list -- list ) - intersection [ > ] sort ; + append prune ; : lookup-union ( typelist -- class ) - classes get hash [ object ] unless* ; + [ > ] sort classes get hash [ object ] unless* ; : class-or ( class class -- class ) #! Return a class that both classes are subclasses of. @@ -182,12 +179,19 @@ SYMBOL: object swap builtin-supertypes type-union lookup-union ; +: class-or-list ( list -- class ) + #! Return a class that every class in the list is a + #! subclass of. + [ + [ builtin-supertypes [ unique, ] each ] each + ] make-list lookup-union ; + : class-and ( class class -- class ) #! Return a class that is a subclass of both, or raise an #! error if this is impossible. over builtin-supertypes over builtin-supertypes - type-intersection dup [ + intersection dup [ nip nip lookup-union ] [ drop [ @@ -196,8 +200,18 @@ SYMBOL: object ] make-string throw ] ifte ; +: define-promise ( class -- ) + #! A promise is a word that has no effect during + #! interpretation, but instructs the compiler that the value + #! at the top of the stack is statically-known to be of the + #! given type. Promises should only be used by kernel code. + dup word-name "%" swap cat2 "in" get create + dup [ ] define-compound + swap "promise" set-word-property ; + : define-class ( class metaclass -- ) dupd "metaclass" set-word-property + dup define-promise dup builtin-supertypes [ > ] sort classes get set-hash ; diff --git a/library/generic/predicate.factor b/library/generic/predicate.factor index 4137bc7c1d..e6426b6cac 100644 --- a/library/generic/predicate.factor +++ b/library/generic/predicate.factor @@ -90,3 +90,6 @@ predicate [ PREDICATE: compound generic ( word -- ? ) "combination" word-property ; + +PREDICATE: compound promise ( obj -- ? ) + "promise" word-property ; diff --git a/library/inference/branches.factor b/library/inference/branches.factor index 87efa1eebf..c584344102 100644 --- a/library/inference/branches.factor +++ b/library/inference/branches.factor @@ -39,42 +39,41 @@ USE: words USE: hashtables USE: prettyprint -: vector-length< ( vec1 vec2 -- ? ) - swap vector-length swap vector-length < ; +: longest-vector ( list -- length ) + [ vector-length ] map [ > ] top ; -: unify-length ( vec1 vec2 -- vec1 ) - 2dup vector-length< [ swap ] unless [ - vector-length over vector-length - - empty-vector [ swap vector-append ] keep - ] keep ; +: computed-value-vector ( n -- vector ) + [ drop object ] vector-project ; -: unify-classes ( value value -- class ) - #! If one of the values is f, it was added as a result of - #! length unification so we just replace it with a computed - #! object value. - 2dup and [ - value-class swap value-class class-or +: add-inputs ( count stack -- count stack ) + #! Add this many inputs to the given stack. + [ vector-length - dup ] keep + >r computed-value-vector dup r> vector-append ; + +: unify-lengths ( list -- list ) + #! Pad all vectors to the same length. If one vector is + #! shorter, pad it with unknown results at the bottom. + dup longest-vector swap [ dupd add-inputs nip ] map nip ; + +: unify-results ( list -- value ) + #! If all values in list are equal, return the value. + #! Otherwise, unify types. + dup all=? [ + car ] [ - 2drop object + [ value-class ] map class-or-list ] ifte ; -: unify-results ( value value -- value ) - #! Replace values with unknown result if they differ, - #! otherwise retain them. - 2dup = [ - drop - ] [ - unify-classes - ] ifte ; +: vector-transpose ( list -- vector ) + #! Turn a list of same-length vectors into a vector of lists. + dup car vector-length [ + over [ dupd vector-nth ] map nip + ] vector-project nip ; : unify-stacks ( list -- stack ) #! Replace differing literals in stacks with unknown #! results. - uncons [ - unify-length vector-zip [ - uncons unify-results - ] vector-map - ] each ; + unify-lengths vector-transpose [ unify-results ] vector-map ; : balanced? ( list -- ? ) #! Check if a list of [ instack | outstack ] pairs is @@ -139,9 +138,16 @@ SYMBOL: cloned meta-d off meta-r off d-in off ] when ; +: propagate-type ( [ value | class ] -- ) + #! Type propagation is chained. + [ + unswons 2dup set-value-class + [ type-propagations get ] bind assoc propagate-type + ] when* ; + : infer-branch ( value -- namespace ) [ - uncons [ unswons set-value-class ] when* + uncons propagate-type dup value-recursion recursive-state set copy-inference literal-value dup infer-quot @@ -234,9 +240,8 @@ SYMBOL: cloned #! Infer effects for all branches, unify. [ object vector ] ensure-d dataflow-drop, pop-d vtable>list - [ f cons ] map >r 1 meta-d get vector-tail* #dispatch r> - pop-d drop ( n ) + pop-d ( n ) num-types [ dupd cons ] project nip zip infer-branches ; USE: kernel-internals diff --git a/library/inference/inference.factor b/library/inference/inference.factor index 162005fbe8..4d66760ebe 100644 --- a/library/inference/inference.factor +++ b/library/inference/inference.factor @@ -56,18 +56,24 @@ SYMBOL: d-in ! Recursive state. An alist, mapping words to labels. SYMBOL: recursive-state -! A value has the following slots: GENERIC: literal-value ( value -- obj ) GENERIC: value= ( literal value -- ? ) GENERIC: value-class ( value -- class ) GENERIC: value-class-and ( class value -- ) GENERIC: set-value-class ( class value -- ) +! A value has the following slots in addition to those relating +! to generics above: + +! An association list mapping values to [ value | class ] pairs +SYMBOL: type-propagations + TRAITS: computed C: computed ( class -- value ) [ \ value-class set gensym \ literal-value set + type-propagations off ] extend ; M: computed literal-value ( value -- obj ) "Cannot use a computed value literally." throw ; @@ -82,7 +88,11 @@ M: computed set-value-class ( class value -- ) TRAITS: literal C: literal ( obj rstate -- value ) - [ recursive-state set \ literal-value set ] extend ; + [ + recursive-state set + \ literal-value set + type-propagations off + ] extend ; M: literal literal-value ( value -- obj ) [ \ literal-value get ] bind ; M: literal value= ( literal value -- ? ) diff --git a/library/inference/types.factor b/library/inference/types.factor index fefe23651f..ea8557f604 100644 --- a/library/inference/types.factor +++ b/library/inference/types.factor @@ -38,15 +38,14 @@ USE: strings USE: vectors USE: words USE: stdio +USE: prettyprint ! Enhanced inference of primitives relating to data types. ! Optimizes type checks and slot access. : infer-check ( assert class -- ) peek-d dup value-class pick = [ - [ - "Optimized out " , rot word-name , " check." , - ] make-string print 2drop + 3drop ] [ value-class-and dup "infer-effect" word-property consume/produce @@ -65,6 +64,7 @@ USE: stdio ] "infer" set-word-property \ slot [ + [ object fixnum ] ensure-d dataflow-drop, pop-d literal-value peek-d value-class builtin-supertypes dup length 1 = [ cons #slot dataflow, [ @@ -77,3 +77,26 @@ USE: stdio "slot called without static type knowledge" throw ] ifte ] "infer" set-word-property + +: type-value-map ( value -- ) + [ + num-types [ + dup builtin-type dup [ + pick swons cons , + ] [ + 2drop + ] ifte + ] times* + ] make-list nip ; + +\ type [ + [ object ] ensure-d + \ type #call dataflow, [ + peek-d type-value-map >r + 1 0 node-inputs + [ object ] consume-d + [ fixnum ] produce-d + r> peek-d [ type-propagations set ] bind + 1 0 node-outputs + ] bind +] "infer" set-word-property diff --git a/library/inference/words.factor b/library/inference/words.factor index 6a82eb5756..5f002a098f 100644 --- a/library/inference/words.factor +++ b/library/inference/words.factor @@ -112,6 +112,9 @@ M: compound (apply-word) ( word -- ) infer-compound ] ifte ; +M: promise (apply-word) ( word -- ) + "promise" word-property unit ensure-d ; + M: symbol (apply-word) ( word -- ) apply-literal ; @@ -125,7 +128,7 @@ M: symbol (apply-word) ( word -- ) #! diverging recursion. Note that this check is not done for #! mutually-recursive words. Generally they should be #! avoided. - recursive-state get car = [ + current-word = [ d-in get vector-length meta-d get vector-length > [ current-word word-name " diverges." cat2 throw @@ -183,6 +186,8 @@ M: symbol (apply-word) ( word -- ) \ call [ infer-call ] "infer" set-word-property +\ * [ [ number number ] [ number ] ] "infer-effect" set-word-property + \ undefined-method t "terminator" set-word-property \ not-a-number t "terminator" set-word-property \ throw t "terminator" set-word-property diff --git a/library/kernel.factor b/library/kernel.factor index 8785ff03aa..516a671cfd 100644 --- a/library/kernel.factor +++ b/library/kernel.factor @@ -31,6 +31,8 @@ USE: kernel USE: vectors : dispatch ( n vtable -- ) + #! This word is unsafe in compiled code since n is not + #! bounds-checked. Do not call it directly. vector-nth call ; IN: kernel diff --git a/library/math/complex.factor b/library/math/complex.factor index 21fe06539e..5caf6b9254 100644 --- a/library/math/complex.factor +++ b/library/math/complex.factor @@ -37,11 +37,11 @@ USE: math-internals GENERIC: real ( #{ re im } -- re ) M: real real ; -M: complex real 0 slot ; +M: complex real 0 slot %real ; GENERIC: imaginary ( #{ re im } -- im ) M: real imaginary drop 0 ; -M: complex imaginary 1 slot ; +M: complex imaginary 1 slot %real ; : rect> ( xr xi -- x ) over real? over real? and [ diff --git a/library/math/ratio.factor b/library/math/ratio.factor index 2ab1ebd224..3ba3151547 100644 --- a/library/math/ratio.factor +++ b/library/math/ratio.factor @@ -34,11 +34,11 @@ USE: math-internals GENERIC: numerator ( a/b -- a ) M: integer numerator ; -M: ratio numerator 0 slot ; +M: ratio numerator 0 slot %integer ; GENERIC: denominator ( a/b -- b ) M: integer denominator drop 1 ; -M: ratio denominator 1 slot ; +M: ratio denominator 1 slot %integer ; IN: math-internals diff --git a/library/primitives.factor b/library/primitives.factor index 3a66b98189..ad52311f9b 100644 --- a/library/primitives.factor +++ b/library/primitives.factor @@ -72,7 +72,7 @@ USE: words [ sbuf-reverse " sbuf -- " [ [ sbuf ] [ ] ] ] [ sbuf-clone " sbuf -- sbuf " [ [ sbuf ] [ sbuf ] ] ] [ sbuf= " sbuf sbuf -- ? " [ [ sbuf sbuf ] [ boolean ] ] ] - [ sbuf-hashcode " sbuf -- n " [ [ sbuf ] [ integer ] ] ] + [ sbuf-hashcode " sbuf -- n " [ [ sbuf ] [ fixnum ] ] ] [ arithmetic-type " n n -- type " [ [ number number ] [ number number fixnum ] ] ] [ >fixnum " n -- fixnum " [ [ number ] [ fixnum ] ] ] [ >bignum " n -- bignum " [ [ number ] [ bignum ] ] ] diff --git a/library/strings.factor b/library/strings.factor index 27cf3b9469..42e82b7ee4 100644 --- a/library/strings.factor +++ b/library/strings.factor @@ -34,7 +34,7 @@ USE: math ! Define methods bound to primitives BUILTIN: string 12 -M: string hashcode 2 slot ; +M: string hashcode 2 slot %fixnum ; M: string = str= ; : str-length ( str -- len ) >string 1 integer-slot ; inline diff --git a/library/test/dataflow.factor b/library/test/dataflow.factor index 1de418a356..07afb2df1e 100644 --- a/library/test/dataflow.factor +++ b/library/test/dataflow.factor @@ -36,9 +36,9 @@ USE: generic : inline-test car car ; inline -[ t ] [ - \ slot [ inline-test ] dataflow dataflow-contains-param? >boolean -] unit-test +! [ t ] [ +! \ slot [ inline-test ] dataflow dataflow-contains-param? >boolean +! ] unit-test [ t ] [ #ifte [ [ drop ] [ + ] ifte ] dataflow dataflow-contains-op? >boolean diff --git a/library/test/inference.factor b/library/test/inference.factor index fa519f7075..bd4534aca8 100644 --- a/library/test/inference.factor +++ b/library/test/inference.factor @@ -20,41 +20,18 @@ unit-test [ [ vector ] [ cons vector cons integer object cons ] ] [ [ vector ] [ cons vector cons ] ] decompose -] +] unit-test [ [ [ object ] [ object ] ] ] [ [ [ object number ] [ object ] ] [ [ object number ] [ object ] ] decompose -] +] unit-test : old-effect ( [ in-types out-types ] -- [ in | out ] ) uncons car length >r length r> cons ; -[ - [ 1 | 2 ] - [ 2 | 1 ] - [ 0 | 3 ] - [ 4 | 2 ] - [ 3 | 3 ] - [ 0 | 0 ] - [ 1 | 5 ] - [ 3 | 4 ] -] "effects" set - -[ { f 1 2 } { 1 2 3 } ] [ - { 1 2 } { 1 2 3 } unify-length -] unit-test - -[ [ sq ] ] [ - [ sq ] f [ sq ] f unify-results literal-value -] unit-test - -[ fixnum ] [ - 5 f 6 f unify-results value-class -] unit-test - [ [ 0 | 2 ] ] [ [ 2 "Hello" ] infer old-effect ] unit-test [ [ 1 | 2 ] ] [ [ dup ] infer old-effect ] unit-test @@ -109,10 +86,10 @@ unit-test [ [ 1 | 1 ] ] [ [ simple-recursion-2 ] infer old-effect ] unit-test -: bad-recursion-1 - dup [ drop bad-recursion-1 5 ] [ ] ifte ; - -[ [ bad-recursion-1 ] infer old-effect ] unit-test-fails +! : bad-recursion-1 +! dup [ drop bad-recursion-1 5 ] [ ] ifte ; +! +! [ [ bad-recursion-1 ] infer old-effect ] unit-test-fails : bad-recursion-2 dup [ uncons bad-recursion-2 ] [ ] ifte ; @@ -236,11 +213,12 @@ SYMBOL: sym-test ! Type inference -! [ [ [ object ] [ ] ] ] [ [ drop ] infer ] unit-test -! [ [ [ object ] [ object object ] ] ] [ [ dup ] infer ] unit-test -! [ [ [ object object ] [ cons ] ] ] [ [ cons ] infer ] unit-test -! [ [ [ cons ] [ cons ] ] ] [ [ uncons cons ] infer ] unit-test -! [ [ [ object ] [ object ] ] ] [ [ dup [ car ] when ] infer ] unit-test -! [ [ [ vector ] [ vector ] ] ] [ [ vector-clone ] infer ] unit-test +[ [ [ object ] [ ] ] ] [ [ drop ] infer ] unit-test +[ [ [ object ] [ object object ] ] ] [ [ dup ] infer ] unit-test +[ [ [ object object ] [ cons ] ] ] [ [ cons ] infer ] unit-test +[ [ [ cons ] [ cons ] ] ] [ [ uncons cons ] infer ] unit-test +[ [ [ general-list ] [ object ] ] ] [ [ dup [ car ] when ] infer ] unit-test +[ [ [ vector ] [ vector ] ] ] [ [ vector-clone ] infer ] unit-test ! [ [ [ number ] [ number ] ] ] [ [ dup + ] infer ] unit-test ! [ [ [ number number number ] [ number ] ] ] [ [ digit+ ] infer ] unit-test +[ [ [ number ] [ real real ] ] ] [ [ >rect ] infer ] unit-test diff --git a/library/words.factor b/library/words.factor index 35c2d61dcb..3500233bc3 100644 --- a/library/words.factor +++ b/library/words.factor @@ -37,7 +37,7 @@ USE: strings BUILTIN: word 1 -M: word hashcode 1 slot ; +M: word hashcode 1 slot %fixnum ; : word-xt ( w -- xt ) >word 2 integer-slot ; inline : set-word-xt ( xt w -- ) >word 2 set-integer-slot ; inline @@ -84,7 +84,11 @@ PREDICATE: word undefined ( obj -- ? ) word-primitive 0 = ; : intern-symbol ( word -- ) dup undefined? [ define-symbol ] [ drop ] ifte ; -: word-name ( word -- str ) "name" word-property ; +#! The type declaration is for the benefit of stack effect +#! inference. +: word-name ( word -- str ) + "name" word-property >string ; + : word-vocabulary ( word -- str ) "vocabulary" word-property ; : stack-effect ( word -- str ) "stack-effect" word-property ; : documentation ( word -- str ) "documentation" word-property ;