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_fast_dip_p(F_ARRAY *array, CELL i)
59 return (i + 2) <= array_capacity(array)
60 && type_of(array_nth(array,i)) == QUOTATION_TYPE
61 && array_nth(array,i + 1) == userenv[JIT_DIP_WORD];
64 bool jit_fast_2dip_p(F_ARRAY *array, CELL i)
66 return (i + 2) <= array_capacity(array)
67 && type_of(array_nth(array,i)) == QUOTATION_TYPE
68 && array_nth(array,i + 1) == userenv[JIT_2DIP_WORD];
71 bool jit_fast_3dip_p(F_ARRAY *array, CELL i)
73 return (i + 2) <= array_capacity(array)
74 && type_of(array_nth(array,i)) == QUOTATION_TYPE
75 && array_nth(array,i + 1) == userenv[JIT_3DIP_WORD];
78 bool jit_ignore_declare_p(F_ARRAY *array, CELL i)
80 return (i + 1) < array_capacity(array)
81 && type_of(array_nth(array,i)) == ARRAY_TYPE
82 && array_nth(array,i + 1) == userenv[JIT_DECLARE_WORD];
85 F_ARRAY *code_to_emit(CELL code)
87 return untag_object(array_nth(untag_object(code),0));
90 F_REL rel_to_emit(CELL code, CELL code_format, CELL code_length,
91 CELL rel_argument, bool *rel_p)
93 F_ARRAY *quadruple = untag_object(code);
94 CELL rel_class = array_nth(quadruple,1);
95 CELL rel_type = array_nth(quadruple,2);
96 CELL offset = array_nth(quadruple,3);
109 rel.type = to_fixnum(rel_type)
110 | (to_fixnum(rel_class) << 8)
111 | (rel_argument << 16);
112 rel.offset = (code_length + to_fixnum(offset)) * code_format;
118 #define EMIT(name,rel_argument) { \
120 F_REL rel = rel_to_emit(name,code_format,code_count,rel_argument,&rel_p); \
121 if(rel_p) GROWABLE_BYTE_ARRAY_APPEND(relocation,&rel,sizeof(F_REL)); \
122 GROWABLE_ARRAY_APPEND(code,code_to_emit(name)); \
125 bool jit_stack_frame_p(F_ARRAY *array)
127 F_FIXNUM length = array_capacity(array);
130 for(i = 0; i < length - 1; i++)
132 CELL obj = array_nth(array,i);
133 if(type_of(obj) == WORD_TYPE)
135 F_WORD *word = untag_object(obj);
136 if(word->subprimitive == F && obj != userenv[JIT_DECLARE_WORD])
139 else if(type_of(obj) == QUOTATION_TYPE)
141 if(jit_fast_dip_p(array,i)
142 || jit_fast_2dip_p(array,i)
143 || jit_fast_3dip_p(array,i))
151 void set_quot_xt(F_QUOTATION *quot, F_COMPILED *code)
153 if(code->type != QUOTATION_TYPE)
154 critical_error("bad param to set_quot_xt",(CELL)code);
157 quot->xt = (XT)(code + 1);
162 void jit_compile(CELL quot, bool relocate)
164 if(untag_quotation(quot)->compiledp != F)
167 CELL code_format = compiled_code_format();
171 CELL array = untag_quotation(quot)->array;
172 REGISTER_ROOT(array);
174 GROWABLE_ARRAY(code);
177 GROWABLE_BYTE_ARRAY(relocation);
178 REGISTER_ROOT(relocation);
180 GROWABLE_ARRAY(literals);
181 REGISTER_ROOT(literals);
183 GROWABLE_ARRAY_ADD(literals,stack_traces_p() ? quot : F);
185 bool stack_frame = jit_stack_frame_p(untag_object(array));
188 EMIT(userenv[JIT_PROLOG],0);
191 CELL length = array_capacity(untag_object(array));
192 bool tail_call = false;
194 for(i = 0; i < length; i++)
196 CELL obj = array_nth(untag_object(array),i);
203 word = untag_object(obj);
206 if(word->subprimitive != F)
208 if(array_nth(untag_object(word->subprimitive),1) != F)
210 GROWABLE_ARRAY_ADD(literals,T);
213 EMIT(word->subprimitive,literals_count - 1);
217 GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
222 EMIT(userenv[JIT_EPILOG],0);
224 EMIT(userenv[JIT_WORD_JUMP],literals_count - 1);
229 EMIT(userenv[JIT_WORD_CALL],literals_count - 1);
233 wrapper = untag_object(obj);
234 GROWABLE_ARRAY_ADD(literals,wrapper->object);
235 EMIT(userenv[JIT_PUSH_LITERAL],literals_count - 1);
238 if(jit_primitive_call_p(untag_object(array),i))
240 EMIT(userenv[JIT_SAVE_STACK],0);
241 EMIT(userenv[JIT_PRIMITIVE],to_fixnum(obj));
249 if(jit_fast_if_p(untag_object(array),i))
252 EMIT(userenv[JIT_EPILOG],0);
254 GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
255 GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i + 1));
256 EMIT(userenv[JIT_IF_JUMP],literals_count - 2);
263 else if(jit_fast_dip_p(untag_object(array),i))
265 GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
266 EMIT(userenv[JIT_DIP],literals_count - 1);
271 else if(jit_fast_2dip_p(untag_object(array),i))
273 GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
274 EMIT(userenv[JIT_2DIP],literals_count - 1);
279 else if(jit_fast_3dip_p(untag_object(array),i))
281 GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
282 EMIT(userenv[JIT_3DIP],literals_count - 1);
288 if(jit_fast_dispatch_p(untag_object(array),i))
291 EMIT(userenv[JIT_EPILOG],0);
293 GROWABLE_ARRAY_ADD(literals,array_nth(untag_object(array),i));
294 EMIT(userenv[JIT_DISPATCH],literals_count - 1);
301 else if(jit_ignore_declare_p(untag_object(array),i))
307 GROWABLE_ARRAY_ADD(literals,obj);
308 EMIT(userenv[immediate_p(obj) ? JIT_PUSH_IMMEDIATE : JIT_PUSH_LITERAL],literals_count - 1);
316 EMIT(userenv[JIT_EPILOG],0);
318 EMIT(userenv[JIT_RETURN],0);
321 GROWABLE_ARRAY_TRIM(code);
322 GROWABLE_ARRAY_TRIM(literals);
323 GROWABLE_BYTE_ARRAY_TRIM(relocation);
325 F_COMPILED *compiled = add_compiled_block(
330 untag_object(literals));
332 set_quot_xt(untag_object(quot),compiled);
335 iterate_code_heap_step(compiled,relocate_code_block);
337 UNREGISTER_ROOT(literals);
338 UNREGISTER_ROOT(relocation);
339 UNREGISTER_ROOT(code);
340 UNREGISTER_ROOT(array);
341 UNREGISTER_ROOT(quot);
344 /* Crappy code duplication. If C had closures (not just function pointers)
345 it would be easy to get rid of, but I can't think of a good way to deal
346 with it right now that doesn't involve lots of boilerplate that would be
347 worse than the duplication itself (eg, putting all state in some global
349 #define COUNT(name,scan) \
351 if(offset == 0) return scan - 1; \
352 offset -= array_capacity(code_to_emit(name)) * code_format; \
355 F_FIXNUM quot_code_offset_to_scan(CELL quot, F_FIXNUM offset)
357 CELL code_format = compiled_code_format();
359 CELL array = untag_quotation(quot)->array;
361 bool stack_frame = jit_stack_frame_p(untag_object(array));
364 COUNT(userenv[JIT_PROLOG],0)
367 CELL length = array_capacity(untag_object(array));
368 bool tail_call = false;
370 for(i = 0; i < length; i++)
372 CELL obj = array_nth(untag_object(array),i);
379 word = untag_object(obj);
380 if(word->subprimitive != F)
381 COUNT(word->subprimitive,i)
382 else if(i == length - 1)
385 COUNT(userenv[JIT_EPILOG],i);
387 COUNT(userenv[JIT_WORD_JUMP],i)
392 COUNT(userenv[JIT_WORD_CALL],i)
395 COUNT(userenv[JIT_PUSH_LITERAL],i)
398 if(jit_primitive_call_p(untag_object(array),i))
400 COUNT(userenv[JIT_SAVE_STACK],i);
401 COUNT(userenv[JIT_PRIMITIVE],i);
409 if(jit_fast_if_p(untag_object(array),i))
412 COUNT(userenv[JIT_EPILOG],i)
416 COUNT(userenv[JIT_IF_JUMP],i)
421 else if(jit_fast_dip_p(untag_object(array),i))
424 COUNT(userenv[JIT_DIP],i)
427 else if(jit_fast_2dip_p(untag_object(array),i))
430 COUNT(userenv[JIT_2DIP],i)
433 else if(jit_fast_3dip_p(untag_object(array),i))
436 COUNT(userenv[JIT_3DIP],i)
440 if(jit_fast_dispatch_p(untag_object(array),i))
443 COUNT(userenv[JIT_EPILOG],i)
447 COUNT(userenv[JIT_DISPATCH],i)
452 if(jit_ignore_declare_p(untag_object(array),i))
454 if(offset == 0) return i;
461 COUNT(userenv[immediate_p(obj) ? JIT_PUSH_IMMEDIATE : JIT_PUSH_LITERAL],i)
469 COUNT(userenv[JIT_EPILOG],length)
471 COUNT(userenv[JIT_RETURN],length)
477 F_FASTCALL CELL primitive_jit_compile(CELL quot, F_STACK_FRAME *stack)
479 stack_chain->callstack_top = stack;
481 jit_compile(quot,true);
482 UNREGISTER_ROOT(quot);
486 /* push a new quotation on the stack */
487 void primitive_array_to_quotation(void)
489 F_QUOTATION *quot = allot_object(QUOTATION_TYPE,sizeof(F_QUOTATION));
490 quot->array = dpeek();
491 quot->xt = lazy_jit_compile;
493 drepl(tag_object(quot));
496 void primitive_quotation_xt(void)
498 F_QUOTATION *quot = untag_quotation(dpeek());
499 drepl(allot_cell((CELL)quot->xt));