1 ! Copyright (C) 2004, 2010 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors kernel namespaces arrays sequences io words fry
4 continuations vocabs assocs dlists definitions math graphs generic
5 generic.single combinators deques search-deques macros
6 source-files.errors combinators.short-circuit classes.algebra
8 stack-checker stack-checker.dependencies stack-checker.inlining
11 compiler.errors compiler.units compiler.utilities compiler.crossref
14 compiler.tree.optimizer
18 compiler.cfg.optimizer
27 : compile? ( word -- ? )
28 #! Don't attempt to compile certain words.
30 [ "forgotten" word-prop ]
35 : queue-compile ( word -- )
36 dup compile? [ compile-queue get push-front ] [ drop ] if ;
38 : recompile-callers? ( word -- ? )
39 changed-effects get key? ;
41 : recompile-callers ( word -- )
42 #! If a word's stack effect changed, recompile all words
43 #! that have compiled calls to it.
44 dup recompile-callers?
45 [ effect-dependencies-of keys [ queue-compile ] each ] [ drop ] if ;
47 : compiler-message ( string -- )
48 "trace-compilation" get [ global [ print flush ] bind ] [ drop ] if ;
51 dup name>> compiler-message
53 clear-compiler-error ;
55 GENERIC: no-compile? ( word -- ? )
57 M: method no-compile? "method-generic" word-prop no-compile? ;
59 M: predicate-engine-word no-compile? "owner-generic" word-prop no-compile? ;
62 { [ macro? ] [ "special" word-prop ] [ "no-compile" word-prop ] } 1|| ;
64 GENERIC: combinator? ( word -- ? )
66 M: method combinator? "method-generic" word-prop combinator? ;
68 M: predicate-engine-word combinator? "owner-generic" word-prop combinator? ;
70 M: word combinator? inline? ;
72 : ignore-error? ( word error -- ? )
73 #! Ignore some errors on inline combinators, macros, and special
74 #! words such as 'call'.
77 [ [ combinator? ] [ unknown-macro-input? ] bi* and ]
81 #! Recompile callers if the word's stack effect changed, then
82 #! save the word's dependencies so that if they change, the
83 #! word can get recompiled too.
88 [ dependencies get generic-dependencies get compiled-xref ]
89 [ conditional-dependencies get set-dependency-checks ]
94 : deoptimize-with ( word def -- * )
95 #! If the word failed to infer, compile it with the
96 #! non-optimizing compiler.
97 swap [ finish ] [ compiled get set-at ] bi return ;
99 : not-compiled-def ( word error -- def )
100 '[ _ _ not-compiled ] [ ] like ;
102 : deoptimize* ( word -- * )
103 dup def>> deoptimize-with ;
105 : ignore-error ( word error -- * )
106 drop [ clear-compiler-error ] [ deoptimize* ] bi ;
108 : remember-error ( word error -- * )
109 [ swap <compiler-error> compiler-error ]
110 [ [ drop ] [ not-compiled-def ] 2bi deoptimize-with ]
113 : deoptimize ( word error -- * )
114 #! If the error is ignorable, compile the word with the
115 #! non-optimizing compiler, using its definition. Otherwise,
116 #! if the compiler error is not ignorable, use a dummy
117 #! definition from 'not-compiled-def' which throws an error.
119 { [ dup inference-error? not ] [ rethrow ] }
120 { [ 2dup ignore-error? ] [ ignore-error ] }
124 : optimize? ( word -- ? )
130 : contains-breakpoints? ( -- ? )
131 dependencies get keys [ "break?" word-prop ] any? ;
133 : frontend ( word -- tree )
134 #! If the word contains breakpoints, don't optimize it, since
135 #! the walker does not support this.
137 [ [ build-tree ] [ deoptimize ] recover optimize-tree ] keep
138 contains-breakpoints? [ nip deoptimize* ] [ drop ] if
139 ] [ deoptimize* ] if ;
141 : compile-dependency ( word -- )
142 #! If a word calls an unoptimized word, try to compile the callee.
143 dup optimized? [ drop ] [ queue-compile ] if ;
145 ! Only switch this off for debugging.
146 SYMBOL: compile-dependencies?
148 t compile-dependencies? set-global
150 : compile-dependencies ( asm -- )
151 compile-dependencies? get
152 [ calls>> [ compile-dependency ] each ] [ drop ] if ;
154 : save-asm ( asm -- )
155 [ [ code>> ] [ label>> ] bi compiled get set-at ]
156 [ compile-dependencies ]
159 : backend ( tree word -- )
161 [ optimize-cfg build-mr ] with-cfg
166 : compile-word ( word -- )
167 #! We return early if the word has breakpoints or if it
178 : compile-loop ( deque -- )
179 [ compile-word yield-hook get call( -- ) ] slurp-deque ;
181 SINGLETON: optimizing-compiler
183 M: optimizing-compiler update-call-sites ( class generic -- words )
184 #! Words containing call sites with inferred type 'class'
185 #! which inlined a method on 'generic'
186 generic-call-sites-of swap '[
187 nip _ 2dup [ classoid? ] both?
188 [ classes-intersect? ] [ 2drop f ] if
189 ] assoc-filter keys ;
191 M: optimizing-compiler recompile ( words -- alist )
193 <hashed-dlist> compile-queue set
194 H{ } clone compiled set
197 [ subwords [ compile-dependency ] each ] bi
199 compile-queue get compile-loop
202 "--- compile done" compiler-message ;
204 M: optimizing-compiler to-recompile ( -- words )
205 changed-definitions get compiled-usages
206 maybe-changed get outdated-conditional-usages
207 append assoc-combine keys ;
209 M: optimizing-compiler process-forgotten-words
210 [ delete-compiled-xref ] each ;
212 : with-optimizer ( quot -- )
213 [ optimizing-compiler compiler-impl ] dip with-variable ; inline
215 : enable-optimizer ( -- )
216 optimizing-compiler compiler-impl set-global ;
218 : disable-optimizer ( -- )
219 f compiler-impl set-global ;