6 /* Simple non-optimizing compiler.
8 This is one of the two compilers implementing Factor; the second one is written
9 in Factor and performs advanced optimizations. See basis/compiler/compiler.factor.
11 The non-optimizing compiler compiles a quotation at a time by concatenating
12 machine code chunks; prolog, epilog, call word, jump to word, etc. These machine
13 code chunks are generated from Factor code in basis/cpu/.../bootstrap.factor.
15 Calls to words and constant quotations (referenced by conditionals and dips)
16 are direct jumps to machine code blocks. Literals are also referenced directly
17 without going through the literal table.
19 It actually does do a little bit of very simple optimization:
21 1) Tail call optimization.
23 2) If a quotation is determined to not call any other words (except for a few
24 special words which are open-coded, see below), then no prolog/epilog is
27 3) When in tail position and immediately preceded by literal arguments, the
28 'if' is generated inline, instead of as a call to the 'if' word.
30 4) When preceded by a quotation, calls to 'dip', '2dip' and '3dip' are
31 open-coded as retain stack manipulation surrounding a subroutine call.
33 5) Sub-primitives are primitive words which are implemented in assembly and not
34 in the VM. They are open-coded and no subroutine call is generated. This
35 includes stack shufflers, some fixnum arithmetic words, and words such as tag,
36 slot and eq?. A primitive call is relatively expensive (two subroutine calls)
37 so this results in a big speedup for relatively little effort. */
39 void quotation_jit::init_quotation(cell quot)
41 elements = untag<quotation>(quot)->array;
44 bool quotation_jit::primitive_call_p(cell i, cell length)
46 return (i + 2) <= length && array_nth(elements.untagged(),i + 1) == parent->special_objects[JIT_PRIMITIVE_WORD];
49 bool quotation_jit::fast_if_p(cell i, cell length)
51 return (i + 3) == length
52 && tagged<object>(array_nth(elements.untagged(),i + 1)).type_p(QUOTATION_TYPE)
53 && array_nth(elements.untagged(),i + 2) == parent->special_objects[JIT_IF_WORD];
56 bool quotation_jit::fast_dip_p(cell i, cell length)
58 return (i + 2) <= length && array_nth(elements.untagged(),i + 1) == parent->special_objects[JIT_DIP_WORD];
61 bool quotation_jit::fast_2dip_p(cell i, cell length)
63 return (i + 2) <= length && array_nth(elements.untagged(),i + 1) == parent->special_objects[JIT_2DIP_WORD];
66 bool quotation_jit::fast_3dip_p(cell i, cell length)
68 return (i + 2) <= length && array_nth(elements.untagged(),i + 1) == parent->special_objects[JIT_3DIP_WORD];
71 bool quotation_jit::mega_lookup_p(cell i, cell length)
73 return (i + 4) <= length
74 && tagged<object>(array_nth(elements.untagged(),i + 1)).type_p(FIXNUM_TYPE)
75 && tagged<object>(array_nth(elements.untagged(),i + 2)).type_p(ARRAY_TYPE)
76 && array_nth(elements.untagged(),i + 3) == parent->special_objects[MEGA_LOOKUP_WORD];
79 bool quotation_jit::declare_p(cell i, cell length)
81 return (i + 2) <= length
82 && array_nth(elements.untagged(),i + 1) == parent->special_objects[JIT_DECLARE_WORD];
85 bool quotation_jit::special_subprimitive_p(cell obj)
87 // Subprimitives should be flagged with whether they require a stack frame.
89 return obj == parent->special_objects[SIGNAL_HANDLER_WORD]
90 || obj == parent->special_objects[LEAF_SIGNAL_HANDLER_WORD]
91 || obj == parent->special_objects[FFI_SIGNAL_HANDLER_WORD]
92 || obj == parent->special_objects[FFI_LEAF_SIGNAL_HANDLER_WORD];
95 bool quotation_jit::word_stack_frame_p(cell obj)
97 return (to_boolean(untag<word>(obj)->subprimitive) && !special_subprimitive_p(obj))
98 || obj == parent->special_objects[JIT_PRIMITIVE_WORD];
101 bool quotation_jit::word_safepoint_p(cell obj)
103 if (to_boolean(untag<word>(obj)->subprimitive) && special_subprimitive_p(obj))
109 bool quotation_jit::safepoint_p()
111 fixnum length = array_capacity(elements.untagged());
113 for(fixnum i = 0; i < length; i++)
115 cell obj = array_nth(elements.untagged(),i);
116 switch(tagged<object>(obj).type())
119 if(i != length - 1 || word_stack_frame_p(obj))
123 if(fast_dip_p(i,length) || fast_2dip_p(i,length) || fast_3dip_p(i,length))
134 bool quotation_jit::stack_frame_p()
136 fixnum length = array_capacity(elements.untagged());
138 for(fixnum i = 0; i < length; i++)
140 cell obj = array_nth(elements.untagged(),i);
141 if (tagged<object>(obj).type() == WORD_TYPE && !word_safepoint_p(obj))
148 bool quotation_jit::trivial_quotation_p(array *elements)
150 return array_capacity(elements) == 1 && tagged<object>(array_nth(elements,0)).type_p(WORD_TYPE);
153 void quotation_jit::emit_prolog(bool safepoint, bool stack_frame)
155 if(safepoint) emit(parent->special_objects[JIT_SAFEPOINT]);
156 if(stack_frame) emit(parent->special_objects[JIT_PROLOG]);
159 void quotation_jit::emit_epilog(bool safepoint, bool stack_frame)
161 if(safepoint) emit(parent->special_objects[JIT_SAFEPOINT]);
162 if(stack_frame) emit(parent->special_objects[JIT_EPILOG]);
165 void quotation_jit::emit_quot(cell quot_)
167 data_root<quotation> quot(quot_,parent);
169 array *elements = untag<array>(quot->array);
171 /* If the quotation consists of a single word, compile a direct call
173 if(trivial_quotation_p(elements))
174 literal(array_nth(elements,0));
177 if(compiling) parent->jit_compile_quot(quot.value(),relocate);
178 literal(quot.value());
182 /* Allocates memory */
183 void quotation_jit::iterate_quotation()
185 bool safepoint = safepoint_p();
186 bool stack_frame = stack_frame_p();
190 emit_prolog(safepoint, stack_frame);
193 cell length = array_capacity(elements.untagged());
194 bool tail_call = false;
196 for(i = 0; i < length; i++)
200 data_root<object> obj(array_nth(elements.untagged(),i),parent);
206 if(to_boolean(obj.as<word>()->subprimitive))
208 tail_call = emit_subprimitive(obj.value(), /* word */
209 i == length - 1, /* tail_call_p */
210 stack_frame); /* stack_frame_p */
212 /* Everything else */
213 else if(i == length - 1)
215 emit_epilog(safepoint, stack_frame);
217 word_jump(obj.value());
220 word_call(obj.value());
223 push(obj.as<wrapper>()->object);
225 case BYTE_ARRAY_TYPE:
226 /* Primitive calls */
227 if(primitive_call_p(i,length))
229 /* On x86-64 and PowerPC, the VM pointer is stored in
230 a register; on other platforms, the RT_VM relocation
231 is used and it needs an offset parameter */
233 parameter(tag_fixnum(0));
235 parameter(obj.value());
236 parameter(false_object);
237 #ifdef FACTOR_PPC_TOC
238 parameter(obj.value());
239 parameter(false_object);
241 emit(parent->special_objects[JIT_PRIMITIVE]);
249 /* 'if' preceeded by two literal quotations (this is why if and ? are
250 mutually recursive in the library, but both still work) */
251 if(fast_if_p(i,length))
253 emit_epilog(safepoint, stack_frame);
256 emit_quot(array_nth(elements.untagged(),i));
257 emit_quot(array_nth(elements.untagged(),i + 1));
258 emit(parent->special_objects[JIT_IF]);
263 else if(fast_dip_p(i,length))
265 emit_quot(obj.value());
266 emit(parent->special_objects[JIT_DIP]);
270 else if(fast_2dip_p(i,length))
272 emit_quot(obj.value());
273 emit(parent->special_objects[JIT_2DIP]);
277 else if(fast_3dip_p(i,length))
279 emit_quot(obj.value());
280 emit(parent->special_objects[JIT_3DIP]);
287 /* Method dispatch */
288 if(mega_lookup_p(i,length))
290 emit_epilog(safepoint, stack_frame);
292 emit_mega_cache_lookup(
293 array_nth(elements.untagged(),i),
294 untag_fixnum(array_nth(elements.untagged(),i + 1)),
295 array_nth(elements.untagged(),i + 2));
298 /* Non-optimizing compiler ignores declarations */
299 else if(declare_p(i,length))
312 set_position(length);
314 emit_epilog(safepoint, stack_frame);
315 emit(parent->special_objects[JIT_RETURN]);
319 /* Allocates memory */
320 code_block *factor_vm::jit_compile_quot(cell owner_, cell quot_, bool relocating)
322 data_root<object> owner(owner_,this);
323 data_root<quotation> quot(quot_,this);
325 quotation_jit compiler(owner.value(),true,relocating,this);
326 compiler.init_quotation(quot.value());
327 compiler.iterate_quotation();
329 code_block *compiled = compiler.to_code_block();
331 if(relocating) initialize_code_block(compiled);
336 void factor_vm::jit_compile_quot(cell quot_, bool relocating)
338 data_root<quotation> quot(quot_,this);
339 if(!quot_compiled_p(quot.untagged()))
341 code_block *compiled = jit_compile_quot(quot.value(),quot.value(),relocating);
342 quot.untagged()->entry_point = compiled->entry_point();
346 void factor_vm::primitive_jit_compile()
348 jit_compile_quot(ctx->pop(),true);
351 void *factor_vm::lazy_jit_compile_entry_point()
353 return untag<word>(special_objects[LAZY_JIT_COMPILE_WORD])->entry_point;
356 /* push a new quotation on the stack */
357 void factor_vm::primitive_array_to_quotation()
359 quotation *quot = allot<quotation>(sizeof(quotation));
361 quot->array = ctx->peek();
362 quot->cached_effect = false_object;
363 quot->cache_counter = false_object;
364 quot->entry_point = lazy_jit_compile_entry_point();
366 ctx->replace(tag<quotation>(quot));
369 void factor_vm::primitive_quotation_code()
371 quotation *quot = untag_check<quotation>(ctx->pop());
373 ctx->push(from_unsigned_cell((cell)quot->entry_point));
374 ctx->push(from_unsigned_cell((cell)quot->code() + quot->code()->size()));
377 /* Allocates memory */
378 fixnum factor_vm::quot_code_offset_to_scan(cell quot_, cell offset)
380 data_root<quotation> quot(quot_,this);
381 data_root<array> array(quot->array,this);
383 quotation_jit compiler(quot.value(),false,false,this);
384 compiler.init_quotation(quot.value());
385 compiler.compute_position(offset);
386 compiler.iterate_quotation();
388 return compiler.get_position();
391 cell factor_vm::lazy_jit_compile(cell quot_)
393 data_root<quotation> quot(quot_,this);
395 assert(!quot_compiled_p(quot.untagged()));
397 code_block *compiled = jit_compile_quot(quot.value(),quot.value(),true);
398 quot.untagged()->entry_point = compiled->entry_point();
403 VM_C_API cell lazy_jit_compile(cell quot, factor_vm *parent)
405 return parent->lazy_jit_compile(quot);
408 bool factor_vm::quot_compiled_p(quotation *quot)
410 return quot->entry_point != NULL && quot->entry_point != lazy_jit_compile_entry_point();
413 void factor_vm::primitive_quot_compiled_p()
415 tagged<quotation> quot(ctx->pop());
416 quot.untag_check(this);
417 ctx->push(tag_boolean(quot_compiled_p(quot.untagged())));
420 cell factor_vm::find_all_quotations()
422 return instances(QUOTATION_TYPE);
425 void factor_vm::initialize_all_quotations()
427 data_root<array> quotations(find_all_quotations(),this);
429 cell length = array_capacity(quotations.untagged());
430 for(cell i = 0; i < length; i++)
432 data_root<quotation> quot(array_nth(quotations.untagged(),i),this);
433 if(!quot->entry_point)
434 quot.untagged()->entry_point = lazy_jit_compile_entry_point();