3 /* Simple non-optimizing compiler.
5 This is one of the two compilers implementing Factor; the second one is written
6 in Factor and performs advanced optimizations. See core/compiler/compiler.factor.
8 The non-optimizing compiler compiles a quotation at a time by concatenating
9 machine code chunks; prolog, epilog, call word, jump to word, etc. These machine
10 code chunks are generated from Factor code in core/cpu/.../bootstrap.factor.
12 It actually does do a little bit of very simple optimization:
14 1) Tail call optimization.
16 2) If a quotation is determined to not call any other words (except for a few
17 special words which are open-coded, see below), then no prolog/epilog is
20 3) When in tail position and immediately preceded by literal arguments, the
21 'if' and 'dispatch' conditionals are generated inline, instead of as a call to
24 4) When preceded by an array, calls to the 'declare' word are optimized out
25 entirely. This word is only used by the optimizing compiler, and with the
26 non-optimizing compiler it would otherwise just decrease performance to have to
27 push the array and immediately drop it after.
29 5) Sub-primitives are primitive words which are implemented in assembly and not
30 in the VM. They are open-coded and no subroutine call is generated. This
31 includes stack shufflers, some fixnum arithmetic words, and words such as tag,
32 slot and eq?. A primitive call is relatively expensive (two subroutine calls)
33 so this results in a big speedup for relatively little effort. */
35 bool jit_primitive_call_p(F_ARRAY *array, CELL i)
37 return (i + 2) == array_capacity(array)
38 && type_of(array_nth(array,i)) == FIXNUM_TYPE
39 && array_nth(array,i + 1) == userenv[JIT_PRIMITIVE_WORD];
42 bool jit_fast_if_p(F_ARRAY *array, CELL i)
44 return (i + 3) == array_capacity(array)
45 && type_of(array_nth(array,i)) == QUOTATION_TYPE
46 && type_of(array_nth(array,i + 1)) == QUOTATION_TYPE
47 && array_nth(array,i + 2) == userenv[JIT_IF_WORD];
50 bool jit_fast_dispatch_p(F_ARRAY *array, CELL i)
52 return (i + 2) == array_capacity(array)
53 && type_of(array_nth(array,i)) == ARRAY_TYPE
54 && array_nth(array,i + 1) == userenv[JIT_DISPATCH_WORD];
57 bool jit_ignore_declare_p(F_ARRAY *array, CELL i)
59 return (i + 1) < array_capacity(array)
60 && type_of(array_nth(array,i)) == ARRAY_TYPE
61 && array_nth(array,i + 1) == userenv[JIT_DECLARE_WORD];
64 F_ARRAY *code_to_emit(CELL code)
66 return untag_object(array_nth(untag_object(code),0));
69 F_REL rel_to_emit(CELL code, CELL code_format, CELL code_length,
70 CELL rel_argument, bool *rel_p)
72 F_ARRAY *quadruple = untag_object(code);
73 CELL rel_class = array_nth(quadruple,1);
74 CELL rel_type = array_nth(quadruple,2);
75 CELL offset = array_nth(quadruple,3);
88 rel.type = to_fixnum(rel_type)
89 | (to_fixnum(rel_class) << 8)
90 | (rel_argument << 16);
91 rel.offset = (code_length + to_fixnum(offset)) * code_format;
97 #define EMIT(name,rel_argument) { \
99 F_REL rel = rel_to_emit(name,code_format,code_count,rel_argument,&rel_p); \
100 if(rel_p) GROWABLE_BYTE_ARRAY_APPEND(relocation,&rel,sizeof(F_REL)); \
101 GROWABLE_ARRAY_APPEND(code,code_to_emit(name)); \
104 bool jit_stack_frame_p(F_ARRAY *array)
106 F_FIXNUM length = array_capacity(array);
109 for(i = 0; i < length - 1; i++)
111 CELL obj = array_nth(array,i);
112 if(type_of(obj) == WORD_TYPE)
114 F_WORD *word = untag_object(obj);
115 if(word->subprimitive == F && obj != userenv[JIT_DECLARE_WORD])
123 void set_quot_xt(F_QUOTATION *quot, F_COMPILED *code)
125 if(code->type != QUOTATION_TYPE)
126 critical_error("bad param to set_quot_xt",(CELL)code);
129 quot->xt = (XT)(code + 1);
134 void jit_compile(CELL quot, bool relocate)
136 if(untag_quotation(quot)->compiledp != F)
139 CELL code_format = compiled_code_format();
143 CELL array = untag_quotation(quot)->array;
144 REGISTER_ROOT(array);
146 GROWABLE_ARRAY(code);
149 GROWABLE_BYTE_ARRAY(relocation);
150 REGISTER_ROOT(relocation);
152 GROWABLE_ARRAY(literals);
153 REGISTER_ROOT(literals);
155 GROWABLE_ARRAY_ADD(literals,stack_traces_p() ? quot : F);
157 bool stack_frame = jit_stack_frame_p(untag_object(array));
160 EMIT(userenv[JIT_PROLOG],0);
163 CELL length = array_capacity(untag_object(array));
164 bool tail_call = false;
166 for(i = 0; i < length; i++)
168 CELL obj = array_nth(untag_object(array),i);
175 word = untag_object(obj);
178 if(word->subprimitive != F)
180 if(array_nth(untag_object(word->subprimitive),1) != F)
182 GROWABLE_ARRAY_ADD(literals,T);
185 EMIT(word->subprimitive,literals_count - 1);
189 GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
194 EMIT(userenv[JIT_EPILOG],0);
196 EMIT(userenv[JIT_WORD_JUMP],literals_count - 1);
201 EMIT(userenv[JIT_WORD_CALL],literals_count - 1);
205 wrapper = untag_object(obj);
206 GROWABLE_ARRAY_ADD(literals,wrapper->object);
207 EMIT(userenv[JIT_PUSH_LITERAL],literals_count - 1);
210 if(jit_primitive_call_p(untag_object(array),i))
212 EMIT(userenv[JIT_SAVE_STACK],0);
213 EMIT(userenv[JIT_PRIMITIVE],to_fixnum(obj));
221 if(jit_fast_if_p(untag_object(array),i))
224 EMIT(userenv[JIT_EPILOG],0);
226 GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
227 GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i + 1));
228 EMIT(userenv[JIT_IF_JUMP],literals_count - 2);
236 if(jit_fast_dispatch_p(untag_object(array),i))
239 EMIT(userenv[JIT_EPILOG],0);
241 GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
242 EMIT(userenv[JIT_DISPATCH],literals_count - 1);
249 else if(jit_ignore_declare_p(untag_object(array),i))
255 GROWABLE_ARRAY_ADD(literals,obj);
256 EMIT(userenv[immediate_p(obj) ? JIT_PUSH_IMMEDIATE : JIT_PUSH_LITERAL],literals_count - 1);
264 EMIT(userenv[JIT_EPILOG],0);
266 EMIT(userenv[JIT_RETURN],0);
269 GROWABLE_ARRAY_TRIM(code);
270 GROWABLE_ARRAY_TRIM(literals);
271 GROWABLE_BYTE_ARRAY_TRIM(relocation);
273 F_COMPILED *compiled = add_compiled_block(
278 untag_object(literals));
280 set_quot_xt(untag_object(quot),compiled);
283 iterate_code_heap_step(compiled,relocate_code_block);
285 UNREGISTER_ROOT(literals);
286 UNREGISTER_ROOT(relocation);
287 UNREGISTER_ROOT(code);
288 UNREGISTER_ROOT(array);
289 UNREGISTER_ROOT(quot);
292 /* Crappy code duplication. If C had closures (not just function pointers)
293 it would be easy to get rid of, but I can't think of a good way to deal
294 with it right now that doesn't involve lots of boilerplate that would be
295 worse than the duplication itself (eg, putting all state in some global
297 #define COUNT(name,scan) \
299 if(offset == 0) return scan - 1; \
300 offset -= array_capacity(code_to_emit(name)) * code_format; \
303 F_FIXNUM quot_code_offset_to_scan(CELL quot, F_FIXNUM offset)
305 CELL code_format = compiled_code_format();
307 CELL array = untag_quotation(quot)->array;
309 bool stack_frame = jit_stack_frame_p(untag_object(array));
312 COUNT(userenv[JIT_PROLOG],0)
315 CELL length = array_capacity(untag_object(array));
316 bool tail_call = false;
318 for(i = 0; i < length; i++)
320 CELL obj = array_nth(untag_object(array),i);
327 word = untag_object(obj);
328 if(word->subprimitive != F)
329 COUNT(word->subprimitive,i)
330 else if(i == length - 1)
333 COUNT(userenv[JIT_EPILOG],i);
335 COUNT(userenv[JIT_WORD_JUMP],i)
340 COUNT(userenv[JIT_WORD_CALL],i)
343 COUNT(userenv[JIT_PUSH_LITERAL],i)
346 if(jit_primitive_call_p(untag_object(array),i))
348 COUNT(userenv[JIT_SAVE_STACK],i);
349 COUNT(userenv[JIT_PRIMITIVE],i);
357 if(jit_fast_if_p(untag_object(array),i))
360 COUNT(userenv[JIT_EPILOG],i)
364 COUNT(userenv[JIT_IF_JUMP],i)
370 if(jit_fast_dispatch_p(untag_object(array),i))
373 COUNT(userenv[JIT_EPILOG],i)
377 COUNT(userenv[JIT_DISPATCH],i)
382 if(jit_ignore_declare_p(untag_object(array),i))
384 if(offset == 0) return i;
391 COUNT(userenv[immediate_p(obj) ? JIT_PUSH_IMMEDIATE : JIT_PUSH_LITERAL],i)
399 COUNT(userenv[JIT_EPILOG],length)
401 COUNT(userenv[JIT_RETURN],length)
407 F_FASTCALL CELL primitive_jit_compile(CELL quot, F_STACK_FRAME *stack)
409 stack_chain->callstack_top = stack;
411 jit_compile(quot,true);
412 UNREGISTER_ROOT(quot);
416 /* push a new quotation on the stack */
417 void primitive_array_to_quotation(void)
419 F_QUOTATION *quot = allot_object(QUOTATION_TYPE,sizeof(F_QUOTATION));
420 quot->array = dpeek();
421 quot->xt = lazy_jit_compile;
423 drepl(tag_object(quot));
426 void primitive_quotation_xt(void)
428 F_QUOTATION *quot = untag_quotation(dpeek());
429 drepl(allot_cell((CELL)quot->xt));