138 lines
4.3 KiB
Factor
138 lines
4.3 KiB
Factor
! Copyright (C) 2008, 2009 Slava Pestov.
|
|
! See http://factorcode.org/license.txt for BSD license.
|
|
USING: accessors kernel arrays sequences math math.order
|
|
math.partial-dispatch generic generic.standard generic.single generic.math
|
|
classes.algebra classes.union sets quotations assocs combinators
|
|
combinators.short-circuit words namespaces continuations classes
|
|
fry hints locals
|
|
compiler.tree
|
|
compiler.tree.builder
|
|
compiler.tree.recursive
|
|
compiler.tree.combinators
|
|
compiler.tree.normalization
|
|
compiler.tree.propagation.info
|
|
compiler.tree.propagation.nodes ;
|
|
IN: compiler.tree.propagation.inlining
|
|
|
|
! Splicing nodes
|
|
: splicing-call ( #call word -- nodes )
|
|
[ [ in-d>> ] [ out-d>> ] bi ] dip <#call> 1array ;
|
|
|
|
: open-code-#call ( #call word/quot -- nodes/f )
|
|
[ [ in-d>> ] [ out-d>> ] bi ] dip build-sub-tree ;
|
|
|
|
: splicing-body ( #call quot/word -- nodes/f )
|
|
open-code-#call dup [ analyze-recursive normalize ] when ;
|
|
|
|
! Dispatch elimination
|
|
: undo-inlining ( #call -- ? )
|
|
f >>method f >>body f >>class drop f ;
|
|
|
|
: propagate-body ( #call -- ? )
|
|
body>> (propagate) t ;
|
|
|
|
GENERIC: splicing-nodes ( #call word/quot -- nodes/f )
|
|
|
|
M: word splicing-nodes splicing-call ;
|
|
|
|
M: callable splicing-nodes splicing-body ;
|
|
|
|
: eliminate-dispatch ( #call class/f word/quot/f -- ? )
|
|
dup [
|
|
[ >>class ] dip
|
|
over method>> over = [ drop propagate-body ] [
|
|
2dup splicing-nodes dup [
|
|
[ >>method ] [ >>body ] bi* propagate-body
|
|
] [ 2drop undo-inlining ] if
|
|
] if
|
|
] [ 2drop undo-inlining ] if ;
|
|
|
|
: inlining-standard-method ( #call word -- class/f method/f )
|
|
dup "methods" word-prop assoc-empty? [ 2drop f f ] [
|
|
2dup [ in-d>> length ] [ dispatch# ] bi* <= [ 2drop f f ] [
|
|
[ in-d>> <reversed> ] [ [ dispatch# ] keep ] bi*
|
|
[ swap nth value-info class>> dup ] dip
|
|
method-for-class
|
|
] if
|
|
] if ;
|
|
|
|
: inline-standard-method ( #call word -- ? )
|
|
dupd inlining-standard-method eliminate-dispatch ;
|
|
|
|
: normalize-math-class ( class -- class' )
|
|
{
|
|
null
|
|
fixnum bignum integer
|
|
ratio rational
|
|
float real
|
|
complex number
|
|
object
|
|
} [ class<= ] with find nip ;
|
|
|
|
: inlining-math-method ( #call word -- class/f quot/f )
|
|
swap in-d>>
|
|
first2 [ value-info class>> normalize-math-class ] bi@
|
|
3dup math-both-known?
|
|
[ math-method* ] [ 3drop f ] if
|
|
number swap ;
|
|
|
|
: inline-math-method ( #call word -- ? )
|
|
dupd inlining-math-method eliminate-dispatch ;
|
|
|
|
! Method body inlining
|
|
SYMBOL: history
|
|
|
|
: already-inlined? ( obj -- ? ) history get member-eq? ;
|
|
|
|
: add-to-history ( obj -- ) history [ swap suffix ] change ;
|
|
|
|
:: inline-word ( #call word -- ? )
|
|
word already-inlined? [ f ] [
|
|
#call word splicing-body [
|
|
word add-to-history
|
|
#call body<<
|
|
#call propagate-body
|
|
] [ f ] if*
|
|
] if ;
|
|
|
|
: always-inline-word? ( word -- ? )
|
|
{ curry compose } member-eq? ;
|
|
|
|
: never-inline-word? ( word -- ? )
|
|
{ [ deferred? ] [ "default" word-prop ] [ \ call eq? ] } 1|| ;
|
|
|
|
: custom-inlining? ( word -- ? )
|
|
"custom-inlining" word-prop ;
|
|
|
|
: inline-custom ( #call word -- ? )
|
|
[ dup ] [ custom-inlining? ] bi*
|
|
call( #call -- word/quot/f )
|
|
object swap eliminate-dispatch ;
|
|
|
|
: (do-inlining) ( #call word -- ? )
|
|
#! If the generic was defined in an outer compilation unit,
|
|
#! then it doesn't have a definition yet; the definition
|
|
#! is built at the end of the compilation unit. We do not
|
|
#! attempt inlining at this stage since the stack discipline
|
|
#! is not finalized yet, so dispatch# might return an out
|
|
#! of bounds value. This case comes up if a parsing word
|
|
#! calls the compiler at parse time (doing so is
|
|
#! discouraged, but it should still work.)
|
|
{
|
|
{ [ dup never-inline-word? ] [ 2drop f ] }
|
|
{ [ dup always-inline-word? ] [ inline-word ] }
|
|
{ [ dup standard-generic? ] [ inline-standard-method ] }
|
|
{ [ dup math-generic? ] [ inline-math-method ] }
|
|
{ [ dup inline? ] [ inline-word ] }
|
|
[ 2drop f ]
|
|
} cond ;
|
|
|
|
: do-inlining ( #call word -- ? )
|
|
#! Note the logic here: if there's a custom inlining hook,
|
|
#! it is permitted to return f, which means that we try the
|
|
#! normal inlining heuristic.
|
|
[
|
|
dup custom-inlining? [ 2dup inline-custom ] [ f ] if
|
|
[ 2drop t ] [ (do-inlining) ] if
|
|
] with-scope ;
|