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 core/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 core/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 bool quotation_jit::primitive_call_p(cell i)
41 return (i + 2) == array_capacity(elements.untagged())
42 && tagged<object>(array_nth(elements.untagged(),i)).type_p(FIXNUM_TYPE)
43 && array_nth(elements.untagged(),i + 1) == myvm->userenv[JIT_PRIMITIVE_WORD];
46 bool quotation_jit::fast_if_p(cell i)
48 return (i + 3) == array_capacity(elements.untagged())
49 && tagged<object>(array_nth(elements.untagged(),i)).type_p(QUOTATION_TYPE)
50 && tagged<object>(array_nth(elements.untagged(),i + 1)).type_p(QUOTATION_TYPE)
51 && array_nth(elements.untagged(),i + 2) == myvm->userenv[JIT_IF_WORD];
54 bool quotation_jit::fast_dip_p(cell i)
56 return (i + 2) <= array_capacity(elements.untagged())
57 && tagged<object>(array_nth(elements.untagged(),i)).type_p(QUOTATION_TYPE)
58 && array_nth(elements.untagged(),i + 1) == myvm->userenv[JIT_DIP_WORD];
61 bool quotation_jit::fast_2dip_p(cell i)
63 return (i + 2) <= array_capacity(elements.untagged())
64 && tagged<object>(array_nth(elements.untagged(),i)).type_p(QUOTATION_TYPE)
65 && array_nth(elements.untagged(),i + 1) == myvm->userenv[JIT_2DIP_WORD];
68 bool quotation_jit::fast_3dip_p(cell i)
70 return (i + 2) <= array_capacity(elements.untagged())
71 && tagged<object>(array_nth(elements.untagged(),i)).type_p(QUOTATION_TYPE)
72 && array_nth(elements.untagged(),i + 1) == myvm->userenv[JIT_3DIP_WORD];
75 bool quotation_jit::mega_lookup_p(cell i)
77 return (i + 3) < array_capacity(elements.untagged())
78 && tagged<object>(array_nth(elements.untagged(),i)).type_p(ARRAY_TYPE)
79 && tagged<object>(array_nth(elements.untagged(),i + 1)).type_p(FIXNUM_TYPE)
80 && tagged<object>(array_nth(elements.untagged(),i + 2)).type_p(ARRAY_TYPE)
81 && array_nth(elements.untagged(),i + 3) == myvm->userenv[MEGA_LOOKUP_WORD];
84 bool quotation_jit::stack_frame_p()
86 fixnum length = array_capacity(elements.untagged());
89 for(i = 0; i < length - 1; i++)
91 cell obj = array_nth(elements.untagged(),i);
92 switch(tagged<object>(obj).type())
95 if(myvm->untag<word>(obj)->subprimitive == F)
99 if(fast_dip_p(i) || fast_2dip_p(i) || fast_3dip_p(i))
110 /* Allocates memory */
111 void quotation_jit::iterate_quotation()
113 bool stack_frame = stack_frame_p();
118 emit(myvm->userenv[JIT_PROLOG]);
121 cell length = array_capacity(elements.untagged());
122 bool tail_call = false;
124 for(i = 0; i < length; i++)
128 gc_root<object> obj(array_nth(elements.untagged(),i),myvm);
134 if(obj.as<word>()->subprimitive != F)
135 emit_subprimitive(obj.value());
136 /* The (execute) primitive is special-cased */
137 else if(obj.value() == myvm->userenv[JIT_EXECUTE_WORD])
141 if(stack_frame) emit(myvm->userenv[JIT_EPILOG]);
143 emit(myvm->userenv[JIT_EXECUTE_JUMP]);
146 emit(myvm->userenv[JIT_EXECUTE_CALL]);
148 /* Everything else */
153 if(stack_frame) emit(myvm->userenv[JIT_EPILOG]);
155 /* Inline cache misses are special-cased.
156 The calling convention for tail
157 calls stores the address of the next
158 instruction in a register. However,
159 PIC miss stubs themselves tail-call
160 the inline cache miss primitive, and
161 we don't want to clobber the saved
163 if(obj.value() == myvm->userenv[PIC_MISS_WORD]
164 || obj.value() == myvm->userenv[PIC_MISS_TAIL_WORD])
166 word_special(obj.value());
170 word_jump(obj.value());
174 word_call(obj.value());
178 push(obj.as<wrapper>()->object);
181 /* Primitive calls */
182 if(primitive_call_p(i))
184 emit_with(myvm->userenv[JIT_PRIMITIVE],obj.value());
192 /* 'if' preceeded by two literal quotations (this is why if and ? are
193 mutually recursive in the library, but both still work) */
196 if(stack_frame) emit(myvm->userenv[JIT_EPILOG]);
201 myvm->jit_compile(array_nth(elements.untagged(),i),relocate);
202 myvm->jit_compile(array_nth(elements.untagged(),i + 1),relocate);
205 literal(array_nth(elements.untagged(),i));
206 literal(array_nth(elements.untagged(),i + 1));
207 emit(myvm->userenv[JIT_IF]);
214 else if(fast_dip_p(i))
217 myvm->jit_compile(obj.value(),relocate);
218 emit_with(myvm->userenv[JIT_DIP],obj.value());
223 else if(fast_2dip_p(i))
226 myvm->jit_compile(obj.value(),relocate);
227 emit_with(myvm->userenv[JIT_2DIP],obj.value());
232 else if(fast_3dip_p(i))
235 myvm->jit_compile(obj.value(),relocate);
236 emit_with(myvm->userenv[JIT_3DIP],obj.value());
241 /* Method dispatch */
244 emit_mega_cache_lookup(
245 array_nth(elements.untagged(),i),
246 untag_fixnum(array_nth(elements.untagged(),i + 1)),
247 array_nth(elements.untagged(),i + 2));
260 set_position(length);
263 emit(myvm->userenv[JIT_EPILOG]);
264 emit(myvm->userenv[JIT_RETURN]);
268 void factor_vm::set_quot_xt(quotation *quot, code_block *code)
270 if(code->type != QUOTATION_TYPE)
271 critical_error("Bad param to set_quot_xt",(cell)code);
274 quot->xt = code->xt();
277 /* Allocates memory */
278 void factor_vm::jit_compile(cell quot_, bool relocating)
280 gc_root<quotation> quot(quot_,this);
281 if(quot->code) return;
283 quotation_jit compiler(quot.value(),true,relocating,this);
284 compiler.iterate_quotation();
286 code_block *compiled = compiler.to_code_block();
287 set_quot_xt(quot.untagged(),compiled);
289 if(relocating) relocate_code_block(compiled);
292 inline void factor_vm::primitive_jit_compile()
294 jit_compile(dpop(),true);
297 PRIMITIVE(jit_compile)
299 PRIMITIVE_GETVM()->primitive_jit_compile();
302 /* push a new quotation on the stack */
303 inline void factor_vm::primitive_array_to_quotation()
305 quotation *quot = allot<quotation>(sizeof(quotation));
306 quot->array = dpeek();
307 quot->cached_effect = F;
308 quot->cache_counter = F;
309 quot->xt = (void *)lazy_jit_compile;
311 drepl(tag<quotation>(quot));
314 PRIMITIVE(array_to_quotation)
316 PRIMITIVE_GETVM()->primitive_array_to_quotation();
319 inline void factor_vm::primitive_quotation_xt()
321 quotation *quot = untag_check<quotation>(dpeek());
322 drepl(allot_cell((cell)quot->xt));
325 PRIMITIVE(quotation_xt)
327 PRIMITIVE_GETVM()->primitive_quotation_xt();
330 void factor_vm::compile_all_words()
332 gc_root<array> words(find_all_words(),this);
335 cell length = array_capacity(words.untagged());
336 for(i = 0; i < length; i++)
338 gc_root<word> word(array_nth(words.untagged(),i),this);
340 if(!word->code || !word_optimized_p(word.untagged()))
341 jit_compile_word(word.value(),word->def,false);
343 update_word_xt(word.value());
347 iterate_code_heap(factor::relocate_code_block);
350 /* Allocates memory */
351 fixnum factor_vm::quot_code_offset_to_scan(cell quot_, cell offset)
353 gc_root<quotation> quot(quot_,this);
354 gc_root<array> array(quot->array,this);
356 quotation_jit compiler(quot.value(),false,false,this);
357 compiler.compute_position(offset);
358 compiler.iterate_quotation();
360 return compiler.get_position();
363 cell factor_vm::lazy_jit_compile_impl(cell quot_, stack_frame *stack)
365 gc_root<quotation> quot(quot_,this);
366 stack_chain->callstack_top = stack;
367 jit_compile(quot.value(),true);
371 VM_ASM_API cell lazy_jit_compile_impl(cell quot_, stack_frame *stack, factor_vm *myvm)
374 return VM_PTR->lazy_jit_compile_impl(quot_,stack);
377 inline void factor_vm::primitive_quot_compiled_p()
379 tagged<quotation> quot(dpop());
380 quot.untag_check(this);
381 dpush(tag_boolean(quot->code != NULL));
384 PRIMITIVE(quot_compiled_p)
386 PRIMITIVE_GETVM()->primitive_quot_compiled_p();