| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  | ! Copyright (C) 2008, 2009 Slava Pestov. | 
					
						
							| 
									
										
										
										
											2008-07-30 04:38:10 -04:00
										 |  |  | ! See http://factorcode.org/license.txt for BSD license. | 
					
						
							| 
									
										
										
										
											2014-12-13 19:10:21 -05:00
										 |  |  | USING: accessors combinators.short-circuit compiler.tree fry | 
					
						
							|  |  |  | kernel namespaces sequences sets ;
 | 
					
						
							| 
									
										
										
										
											2008-09-12 06:17:27 -04:00
										 |  |  | IN: compiler.tree.recursive | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  | TUPLE: call-site tail? node label ;
 | 
					
						
							| 
									
										
										
										
											2008-09-12 06:17:27 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  | : recursive-phi-in ( #enter-recursive -- seq )
 | 
					
						
							|  |  |  |     [ label>> calls>> [ node>> in-d>> ] map ] [ in-d>> ] bi suffix ;
 | 
					
						
							| 
									
										
										
										
											2008-09-12 06:17:27 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  | <PRIVATE
 | 
					
						
							| 
									
										
										
										
											2008-09-12 06:17:27 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | TUPLE: call-graph-node tail? label children calls ;
 | 
					
						
							| 
									
										
										
										
											2008-09-12 06:17:27 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  | : (tail-calls) ( tail? seq -- seq' )
 | 
					
						
							|  |  |  |     reverse [ swap [ and ] keep ] map nip reverse ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : tail-calls ( tail? node -- seq )
 | 
					
						
							|  |  |  |     [ | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |         { | 
					
						
							|  |  |  |             [ #phi? ] | 
					
						
							|  |  |  |             [ #return? ] | 
					
						
							|  |  |  |             [ #return-recursive? ] | 
					
						
							|  |  |  |         } 1|| | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  |     ] map (tail-calls) ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  | SYMBOLS: children calls ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | GENERIC: node-call-graph ( tail? node -- )
 | 
					
						
							| 
									
										
										
										
											2008-08-10 20:22:13 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | : (build-call-graph) ( tail? nodes -- )
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |     [ tail-calls ] keep
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  |     [ node-call-graph ] 2each ;
 | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | : build-call-graph ( nodes -- labels calls )
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |     [ | 
					
						
							|  |  |  |         V{ } clone children set
 | 
					
						
							|  |  |  |         V{ } clone calls set
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  |         [ t ] dip (build-call-graph) | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |         children get
 | 
					
						
							|  |  |  |         calls get
 | 
					
						
							|  |  |  |     ] with-scope ;
 | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | M: #return-recursive node-call-graph | 
					
						
							| 
									
										
										
										
											2010-05-05 16:52:54 -04:00
										 |  |  |     nip dup label>> return<< ;
 | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | M: #call-recursive node-call-graph | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |     [ dup label>> call-site boa ] keep
 | 
					
						
							|  |  |  |     [ drop calls get push ] | 
					
						
							|  |  |  |     [ label>> calls>> push ] 2bi ;
 | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | M: #recursive node-call-graph | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |     [ label>> V{ } clone >>calls drop ] | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  |     [ | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  |         [ label>> ] [ child>> build-call-graph ] bi
 | 
					
						
							|  |  |  |         call-graph-node boa children get push
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |     ] bi ;
 | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | M: #branch node-call-graph | 
					
						
							|  |  |  |     children>> [ (build-call-graph) ] with each ;
 | 
					
						
							| 
									
										
										
										
											2008-08-10 20:22:13 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-07-28 00:49:26 -04:00
										 |  |  | M: #alien-callback node-call-graph | 
					
						
							|  |  |  |     child>> (build-call-graph) ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | M: node node-call-graph 2drop ;
 | 
					
						
							| 
									
										
										
										
											2008-08-10 20:22:13 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  | SYMBOLS: not-loops recursive-nesting ;
 | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-08 15:34:23 -05:00
										 |  |  | : not-a-loop ( label -- ) not-loops get adjoin ;
 | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-08 15:34:23 -05:00
										 |  |  | : not-a-loop? ( label -- ? ) not-loops get in? ;
 | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | : non-tail-calls ( call-graph-node -- seq )
 | 
					
						
							| 
									
										
										
										
											2015-05-12 21:50:34 -04:00
										 |  |  |     calls>> [ tail?>> ] reject ;
 | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | : visit-back-edges ( call-graph -- )
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |     [ | 
					
						
							|  |  |  |         [ 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 <reversed> [ | 
					
						
							| 
									
										
										
										
											2009-08-05 03:14:49 -04:00
										 |  |  |             2dup label>> eq? [ 2drop f ] [ | 
					
						
							|  |  |  |                 [ label>> not-a-loop? ] [ tail?>> not ] bi or
 | 
					
						
							|  |  |  |                 [ not-a-loop changed? on ] [ drop ] if t
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |             ] if
 | 
					
						
							|  |  |  |         ] with all? drop
 | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | : detect-cross-frame-calls ( call-graph -- )
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |     ! 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. | 
					
						
							|  |  |  |     [ | 
					
						
							| 
									
										
										
										
											2009-08-05 03:14:49 -04:00
										 |  |  |         [ recursive-nesting get push ] | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |         [ calls>> [ check-cross-frame-call ] each ] | 
					
						
							|  |  |  |         [ children>> detect-cross-frame-calls ] tri
 | 
					
						
							|  |  |  |         recursive-nesting get pop*
 | 
					
						
							|  |  |  |     ] each ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-03-09 02:38:10 -05:00
										 |  |  | : while-changing ( ... quot: ( ... -- ... ) -- ... )
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |     changed? off
 | 
					
						
							| 
									
										
										
										
											2015-08-10 13:55:27 -04:00
										 |  |  |     [ call ] | 
					
						
							|  |  |  |     [ changed? get [ while-changing ] [ drop ] if ] bi ; inline recursive
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | : detect-loops ( call-graph -- )
 | 
					
						
							| 
									
										
										
										
											2013-03-08 15:34:23 -05:00
										 |  |  |     HS{ } clone not-loops set
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |     V{ } clone recursive-nesting set
 | 
					
						
							|  |  |  |     [ visit-back-edges ] | 
					
						
							|  |  |  |     [ '[ _ detect-cross-frame-calls ] while-changing ] | 
					
						
							|  |  |  |     bi ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | : mark-loops ( call-graph -- )
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  |     [ | 
					
						
							|  |  |  |         [ label>> dup not-a-loop? [ t >>loop? ] unless drop ] | 
					
						
							|  |  |  |         [ children>> mark-loops ] | 
					
						
							|  |  |  |         bi
 | 
					
						
							|  |  |  |     ] each ;
 | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-04 20:18:40 -04:00
										 |  |  | PRIVATE>
 | 
					
						
							| 
									
										
										
										
											2008-08-10 02:58:39 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  | SYMBOL: call-graph | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-09-12 06:17:27 -04:00
										 |  |  | : analyze-recursive ( nodes -- nodes )
 | 
					
						
							| 
									
										
										
										
											2009-08-05 04:33:06 -04:00
										 |  |  |     dup build-call-graph drop
 | 
					
						
							|  |  |  |     [ call-graph set ] | 
					
						
							|  |  |  |     [ detect-loops ] | 
					
						
							|  |  |  |     [ mark-loops ] | 
					
						
							|  |  |  |     tri ;
 |