2010-01-14 10:10:13 -05:00
|
|
|
! Copyright (C) 2009, 2010 Slava Pestov, Daniel Ehrenberg.
|
2009-03-17 00:02:55 -04:00
|
|
|
! See http://factorcode.org/license.txt for BSD license.
|
2010-01-14 10:10:13 -05:00
|
|
|
USING: accessors arrays combinators combinators.private effects
|
2010-02-02 07:48:43 -05:00
|
|
|
fry kernel kernel.private make namespaces sequences continuations
|
2010-01-29 02:15:19 -05:00
|
|
|
quotations words math stack-checker stack-checker.dependencies
|
|
|
|
combinators.short-circuit stack-checker.transforms
|
|
|
|
compiler.tree.propagation.info
|
2009-11-13 04:52:14 -05:00
|
|
|
compiler.tree.propagation.inlining compiler.units ;
|
2009-07-14 02:12:45 -04:00
|
|
|
IN: compiler.tree.propagation.call-effect
|
2009-03-17 00:02:55 -04:00
|
|
|
|
|
|
|
! call( and execute( have complex expansions.
|
|
|
|
|
2010-01-29 02:15:19 -05:00
|
|
|
! If the input quotation is a literal, or built up from curry and
|
|
|
|
! compose with terminal quotations literal, it is inlined at the
|
|
|
|
! call site.
|
|
|
|
|
|
|
|
! For dynamic call sites, call( uses the following strategy:
|
2009-03-17 00:02:55 -04:00
|
|
|
! - Inline caching. If the quotation is the same as last time, just call it unsafely
|
|
|
|
! - Effect inference. Infer quotation's effect, caching it in the cached-effect slot,
|
|
|
|
! and compare it with declaration. If matches, call it unsafely.
|
|
|
|
! - Fallback. If the above doesn't work, call it and compare the datastack before
|
|
|
|
! and after to make sure it didn't mess anything up.
|
2009-11-13 04:52:14 -05:00
|
|
|
! - Inline caches and cached effects are invalidated whenever a macro is redefined, or
|
|
|
|
! a word's effect changes, by comparing a global counter against the counter value
|
|
|
|
! last observed. The counter is incremented by compiler.units.
|
2009-03-17 00:02:55 -04:00
|
|
|
|
|
|
|
! execute( uses a similar strategy.
|
|
|
|
|
2009-11-12 17:09:07 -05:00
|
|
|
TUPLE: inline-cache value counter ;
|
|
|
|
|
|
|
|
: inline-cache-hit? ( word/quot ic -- ? )
|
2009-11-13 05:32:33 -05:00
|
|
|
{ [ value>> eq? ] [ nip counter>> effect-counter eq? ] } 2&& ; inline
|
2009-11-12 17:09:07 -05:00
|
|
|
|
|
|
|
: update-inline-cache ( word/quot ic -- )
|
2009-11-13 04:52:14 -05:00
|
|
|
[ effect-counter ] dip
|
2010-05-05 16:52:54 -04:00
|
|
|
[ value<< ] [ counter<< ] bi-curry bi* ; inline
|
2009-03-17 00:02:55 -04:00
|
|
|
|
2009-04-30 22:08:29 -04:00
|
|
|
SINGLETON: +unknown+
|
2009-03-17 00:02:55 -04:00
|
|
|
|
2009-03-17 19:53:44 -04:00
|
|
|
GENERIC: cached-effect ( quot -- effect )
|
|
|
|
|
|
|
|
M: object cached-effect drop +unknown+ ;
|
|
|
|
|
2011-11-27 19:21:20 -05:00
|
|
|
GENERIC: curry-effect* ( effect -- effect' )
|
2009-04-30 22:08:29 -04:00
|
|
|
|
2011-11-27 19:21:20 -05:00
|
|
|
M: +unknown+ curry-effect* ;
|
2009-04-30 22:08:29 -04:00
|
|
|
|
2011-11-27 19:21:20 -05:00
|
|
|
M: effect curry-effect* curry-effect ;
|
2009-04-30 22:08:29 -04:00
|
|
|
|
|
|
|
M: curry cached-effect
|
2011-11-27 19:21:20 -05:00
|
|
|
quot>> cached-effect curry-effect* ;
|
2009-04-30 22:08:29 -04:00
|
|
|
|
|
|
|
: compose-effects* ( effect1 effect2 -- effect' )
|
|
|
|
{
|
|
|
|
{ [ 2dup [ effect? ] both? ] [ compose-effects ] }
|
|
|
|
{ [ 2dup [ +unknown+ eq? ] either? ] [ 2drop +unknown+ ] }
|
|
|
|
} cond ;
|
|
|
|
|
|
|
|
M: compose cached-effect
|
|
|
|
[ first>> ] [ second>> ] bi [ cached-effect ] bi@ compose-effects* ;
|
|
|
|
|
2009-09-07 18:45:03 -04:00
|
|
|
: safe-infer ( quot -- effect )
|
2010-02-02 07:48:43 -05:00
|
|
|
! Save and restore error variables here, so that we don't
|
|
|
|
! pollute words such as :error and :c for the user.
|
|
|
|
error get-global error-continuation get-global
|
|
|
|
[ [ [ infer ] [ 2drop +unknown+ ] recover ] without-dependencies ] 2dip
|
|
|
|
[ error set-global ] [ error-continuation set-global ] bi* ;
|
2009-09-07 18:45:03 -04:00
|
|
|
|
2009-11-12 17:09:07 -05:00
|
|
|
: cached-effect-valid? ( quot -- ? )
|
2009-11-13 04:52:14 -05:00
|
|
|
cache-counter>> effect-counter eq? ; inline
|
2009-11-12 17:09:07 -05:00
|
|
|
|
|
|
|
: save-effect ( effect quot -- )
|
2009-11-13 04:52:14 -05:00
|
|
|
[ effect-counter ] dip
|
2010-05-05 16:52:54 -04:00
|
|
|
[ cached-effect<< ] [ cache-counter<< ] bi-curry bi* ;
|
2009-11-12 17:09:07 -05:00
|
|
|
|
2009-03-17 19:53:44 -04:00
|
|
|
M: quotation cached-effect
|
2009-11-12 17:09:07 -05:00
|
|
|
dup cached-effect-valid?
|
|
|
|
[ cached-effect>> ] [ [ safe-infer dup ] keep save-effect ] if ;
|
2009-03-17 00:02:55 -04:00
|
|
|
|
|
|
|
: call-effect-unsafe? ( quot effect -- ? )
|
|
|
|
[ cached-effect ] dip
|
2009-03-17 19:53:44 -04:00
|
|
|
over +unknown+ eq?
|
2010-01-19 03:08:45 -05:00
|
|
|
[ 2drop f ] [ [ { effect } declare ] dip effect<= ] if ; inline
|
2009-03-17 00:02:55 -04:00
|
|
|
|
|
|
|
: call-effect-slow>quot ( effect -- quot )
|
2010-02-01 02:50:44 -05:00
|
|
|
[ \ call-effect def>> curry ] [ add-effect-input ] bi
|
|
|
|
'[ _ _ call-effect-unsafe ] ;
|
2009-03-17 00:02:55 -04:00
|
|
|
|
|
|
|
: call-effect-slow ( quot effect -- ) drop call ;
|
|
|
|
|
|
|
|
\ call-effect-slow [ call-effect-slow>quot ] 1 define-transform
|
|
|
|
|
2009-04-20 19:44:45 -04:00
|
|
|
\ call-effect-slow t "no-compile" set-word-prop
|
|
|
|
|
2009-03-17 00:02:55 -04:00
|
|
|
: call-effect-fast ( quot effect inline-cache -- )
|
|
|
|
2over call-effect-unsafe?
|
2009-11-12 17:09:07 -05:00
|
|
|
[ [ nip update-inline-cache ] [ drop call-effect-unsafe ] 3bi ]
|
2009-03-17 00:02:55 -04:00
|
|
|
[ drop call-effect-slow ]
|
|
|
|
if ; inline
|
|
|
|
|
2009-07-10 02:05:03 -04:00
|
|
|
: call-effect-ic ( quot effect inline-cache -- )
|
2009-11-12 17:09:07 -05:00
|
|
|
3dup nip inline-cache-hit?
|
2009-07-10 02:05:03 -04:00
|
|
|
[ drop call-effect-unsafe ]
|
|
|
|
[ call-effect-fast ]
|
|
|
|
if ; inline
|
|
|
|
|
2009-07-14 02:12:45 -04:00
|
|
|
: call-effect>quot ( effect -- quot )
|
|
|
|
inline-cache new '[ drop _ _ call-effect-ic ] ;
|
2009-04-20 19:44:45 -04:00
|
|
|
|
2009-03-17 00:02:55 -04:00
|
|
|
: execute-effect-slow ( word effect -- )
|
|
|
|
[ '[ _ execute ] ] dip call-effect-slow ; inline
|
|
|
|
|
|
|
|
: execute-effect-unsafe? ( word effect -- ? )
|
2010-02-01 02:50:44 -05:00
|
|
|
over optimized?
|
|
|
|
[ [ stack-effect { effect } declare ] dip effect<= ]
|
|
|
|
[ 2drop f ]
|
|
|
|
if ; inline
|
2009-03-17 00:02:55 -04:00
|
|
|
|
|
|
|
: execute-effect-fast ( word effect inline-cache -- )
|
|
|
|
2over execute-effect-unsafe?
|
2009-11-12 17:09:07 -05:00
|
|
|
[ [ nip update-inline-cache ] [ drop execute-effect-unsafe ] 3bi ]
|
2009-03-17 00:02:55 -04:00
|
|
|
[ drop execute-effect-slow ]
|
|
|
|
if ; inline
|
|
|
|
|
|
|
|
: execute-effect-ic ( word effect inline-cache -- )
|
2009-11-12 17:09:07 -05:00
|
|
|
3dup nip inline-cache-hit?
|
2009-03-17 00:02:55 -04:00
|
|
|
[ drop execute-effect-unsafe ]
|
|
|
|
[ execute-effect-fast ]
|
|
|
|
if ; inline
|
|
|
|
|
|
|
|
: execute-effect>quot ( effect -- quot )
|
2009-07-14 02:12:45 -04:00
|
|
|
inline-cache new '[ drop _ _ execute-effect-ic ] ;
|
|
|
|
|
2009-09-07 18:45:03 -04:00
|
|
|
! Some bookkeeping to make sure that crap like
|
|
|
|
! [ dup curry call( quot -- ) ] dup curry call( quot -- ) ]
|
|
|
|
! doesn't hang the compiler.
|
|
|
|
GENERIC: already-inlined-quot? ( quot -- ? )
|
|
|
|
|
|
|
|
M: curry already-inlined-quot? quot>> already-inlined-quot? ;
|
|
|
|
|
|
|
|
M: compose already-inlined-quot?
|
|
|
|
[ first>> already-inlined-quot? ]
|
|
|
|
[ second>> already-inlined-quot? ] bi or ;
|
|
|
|
|
|
|
|
M: quotation already-inlined-quot? already-inlined? ;
|
|
|
|
|
|
|
|
GENERIC: add-quot-to-history ( quot -- )
|
|
|
|
|
|
|
|
M: curry add-quot-to-history quot>> add-quot-to-history ;
|
|
|
|
|
|
|
|
M: compose add-quot-to-history
|
|
|
|
[ first>> add-quot-to-history ]
|
|
|
|
[ second>> add-quot-to-history ] bi ;
|
|
|
|
|
|
|
|
M: quotation add-quot-to-history add-to-history ;
|
|
|
|
|
2009-07-14 02:12:45 -04:00
|
|
|
: last2 ( seq -- penultimate ultimate )
|
|
|
|
2 tail* first2 ;
|
|
|
|
|
|
|
|
: top-two ( #call -- effect value )
|
|
|
|
in-d>> last2 [ value-info ] bi@
|
|
|
|
literal>> swap ;
|
|
|
|
|
|
|
|
ERROR: uninferable ;
|
|
|
|
|
|
|
|
: remove-effect-input ( effect -- effect' )
|
2011-10-18 16:18:42 -04:00
|
|
|
( -- object ) swap compose-effects ;
|
2009-07-14 02:12:45 -04:00
|
|
|
|
|
|
|
: (infer-value) ( value-info -- effect )
|
2009-09-07 18:45:03 -04:00
|
|
|
dup literal?>> [
|
|
|
|
literal>>
|
|
|
|
[ callable? [ uninferable ] unless ]
|
|
|
|
[ already-inlined-quot? [ uninferable ] when ]
|
|
|
|
[ safe-infer dup +unknown+ = [ uninferable ] when ] tri
|
|
|
|
] [
|
|
|
|
dup class>> {
|
|
|
|
{ \ curry [ slots>> third (infer-value) remove-effect-input ] }
|
|
|
|
{ \ compose [ slots>> last2 [ (infer-value) ] bi@ compose-effects ] }
|
|
|
|
[ uninferable ]
|
|
|
|
} case
|
|
|
|
] if ;
|
2009-07-14 02:12:45 -04:00
|
|
|
|
|
|
|
: infer-value ( value-info -- effect/f )
|
|
|
|
[ (infer-value) ]
|
|
|
|
[ dup uninferable? [ 2drop f ] [ rethrow ] if ]
|
|
|
|
recover ;
|
|
|
|
|
|
|
|
: (value>quot) ( value-info -- quot )
|
2009-09-07 18:45:03 -04:00
|
|
|
dup literal?>> [
|
|
|
|
literal>> [ add-quot-to-history ] [ '[ drop @ ] ] bi
|
|
|
|
] [
|
|
|
|
dup class>> {
|
|
|
|
{ \ curry [
|
|
|
|
slots>> third (value>quot)
|
|
|
|
'[ [ obj>> ] [ quot>> @ ] bi ]
|
|
|
|
] }
|
|
|
|
{ \ compose [
|
|
|
|
slots>> last2 [ (value>quot) ] bi@
|
|
|
|
'[ [ first>> @ ] [ second>> @ ] bi ]
|
|
|
|
] }
|
|
|
|
} case
|
|
|
|
] if ;
|
2009-07-14 02:12:45 -04:00
|
|
|
|
|
|
|
: value>quot ( value-info -- quot: ( code effect -- ) )
|
|
|
|
(value>quot) '[ drop @ ] ;
|
|
|
|
|
|
|
|
: call-inlining ( #call -- quot/f )
|
|
|
|
top-two dup infer-value [
|
|
|
|
pick effect<=
|
|
|
|
[ nip value>quot ]
|
|
|
|
[ drop call-effect>quot ] if
|
|
|
|
] [ drop call-effect>quot ] if* ;
|
|
|
|
|
|
|
|
\ call-effect [ call-inlining ] "custom-inlining" set-word-prop
|
|
|
|
|
|
|
|
: execute-inlining ( #call -- quot/f )
|
|
|
|
top-two >literal< [
|
|
|
|
2dup swap execute-effect-unsafe?
|
|
|
|
[ nip '[ 2drop _ execute ] ]
|
|
|
|
[ drop execute-effect>quot ] if
|
|
|
|
] [ drop execute-effect>quot ] if ;
|
|
|
|
|
|
|
|
\ execute-effect [ execute-inlining ] "custom-inlining" set-word-prop
|