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, cell length)
41 return (i + 2) == length && array_nth(elements.untagged(),i + 1) == parent_vm->userenv[JIT_PRIMITIVE_WORD];
44 bool quotation_jit::fast_if_p(cell i, cell length)
46 return (i + 3) == length
47 && tagged<object>(array_nth(elements.untagged(),i + 1)).type_p(QUOTATION_TYPE)
48 && array_nth(elements.untagged(),i + 2) == parent_vm->userenv[JIT_IF_WORD];
51 bool quotation_jit::fast_dip_p(cell i, cell length)
53 return (i + 2) <= length && array_nth(elements.untagged(),i + 1) == parent_vm->userenv[JIT_DIP_WORD];
56 bool quotation_jit::fast_2dip_p(cell i, cell length)
58 return (i + 2) <= length && array_nth(elements.untagged(),i + 1) == parent_vm->userenv[JIT_2DIP_WORD];
61 bool quotation_jit::fast_3dip_p(cell i, cell length)
63 return (i + 2) <= length && array_nth(elements.untagged(),i + 1) == parent_vm->userenv[JIT_3DIP_WORD];
66 bool quotation_jit::mega_lookup_p(cell i, cell length)
68 return (i + 4) <= length
69 && tagged<object>(array_nth(elements.untagged(),i + 1)).type_p(FIXNUM_TYPE)
70 && tagged<object>(array_nth(elements.untagged(),i + 2)).type_p(ARRAY_TYPE)
71 && array_nth(elements.untagged(),i + 3) == parent_vm->userenv[MEGA_LOOKUP_WORD];
74 bool quotation_jit::declare_p(cell i, cell length)
76 return (i + 2) <= length
77 && array_nth(elements.untagged(),i + 1) == parent_vm->userenv[JIT_DECLARE_WORD];
80 bool quotation_jit::stack_frame_p()
82 fixnum length = array_capacity(elements.untagged());
85 for(i = 0; i < length - 1; i++)
87 cell obj = array_nth(elements.untagged(),i);
88 switch(tagged<object>(obj).type())
91 if(parent_vm->untag<word>(obj)->subprimitive == F)
95 if(fast_dip_p(i,length) || fast_2dip_p(i,length) || fast_3dip_p(i,length))
106 /* Allocates memory */
107 void quotation_jit::iterate_quotation()
109 bool stack_frame = stack_frame_p();
114 emit(parent_vm->userenv[JIT_PROLOG]);
117 cell length = array_capacity(elements.untagged());
118 bool tail_call = false;
120 for(i = 0; i < length; i++)
124 gc_root<object> obj(array_nth(elements.untagged(),i),parent_vm);
130 if(obj.as<word>()->subprimitive != F)
131 emit_subprimitive(obj.value());
132 /* The (execute) primitive is special-cased */
133 else if(obj.value() == parent_vm->userenv[JIT_EXECUTE_WORD])
137 if(stack_frame) emit(parent_vm->userenv[JIT_EPILOG]);
139 emit(parent_vm->userenv[JIT_EXECUTE_JUMP]);
142 emit(parent_vm->userenv[JIT_EXECUTE_CALL]);
144 /* Everything else */
149 if(stack_frame) emit(parent_vm->userenv[JIT_EPILOG]);
151 /* Inline cache misses are special-cased.
152 The calling convention for tail
153 calls stores the address of the next
154 instruction in a register. However,
155 PIC miss stubs themselves tail-call
156 the inline cache miss primitive, and
157 we don't want to clobber the saved
159 if(obj.value() == parent_vm->userenv[PIC_MISS_WORD]
160 || obj.value() == parent_vm->userenv[PIC_MISS_TAIL_WORD])
162 word_special(obj.value());
166 word_jump(obj.value());
170 word_call(obj.value());
174 push(obj.as<wrapper>()->object);
177 /* Primitive calls */
178 if(primitive_call_p(i,length))
180 emit_with(parent_vm->userenv[JIT_PRIMITIVE],obj.value());
190 /* 'if' preceeded by two literal quotations (this is why if and ? are
191 mutually recursive in the library, but both still work) */
192 if(fast_if_p(i,length))
194 if(stack_frame) emit(parent_vm->userenv[JIT_EPILOG]);
199 parent_vm->jit_compile(array_nth(elements.untagged(),i),relocate);
200 parent_vm->jit_compile(array_nth(elements.untagged(),i + 1),relocate);
203 literal(array_nth(elements.untagged(),i));
204 literal(array_nth(elements.untagged(),i + 1));
205 emit(parent_vm->userenv[JIT_IF]);
210 else if(fast_dip_p(i,length))
213 parent_vm->jit_compile(obj.value(),relocate);
214 emit_with(parent_vm->userenv[JIT_DIP],obj.value());
218 else if(fast_2dip_p(i,length))
221 parent_vm->jit_compile(obj.value(),relocate);
222 emit_with(parent_vm->userenv[JIT_2DIP],obj.value());
226 else if(fast_3dip_p(i,length))
229 parent_vm->jit_compile(obj.value(),relocate);
230 emit_with(parent_vm->userenv[JIT_3DIP],obj.value());
237 /* Method dispatch */
238 if(mega_lookup_p(i,length))
240 emit_mega_cache_lookup(
241 array_nth(elements.untagged(),i),
242 untag_fixnum(array_nth(elements.untagged(),i + 1)),
243 array_nth(elements.untagged(),i + 2));
247 /* Non-optimizing compiler ignores declarations */
248 else if(declare_p(i,length))
261 set_position(length);
264 emit(parent_vm->userenv[JIT_EPILOG]);
265 emit(parent_vm->userenv[JIT_RETURN]);
269 void factor_vm::set_quot_xt(quotation *quot, code_block *code)
271 if(code->type != QUOTATION_TYPE)
272 critical_error("Bad param to set_quot_xt",(cell)code);
275 quot->xt = code->xt();
278 /* Allocates memory */
279 void factor_vm::jit_compile(cell quot_, bool relocating)
281 gc_root<quotation> quot(quot_,this);
282 if(quot->code) return;
284 quotation_jit compiler(quot.value(),true,relocating,this);
285 compiler.iterate_quotation();
287 code_block *compiled = compiler.to_code_block();
288 set_quot_xt(quot.untagged(),compiled);
290 if(relocating) relocate_code_block(compiled);
293 inline void factor_vm::primitive_jit_compile()
295 jit_compile(dpop(),true);
298 PRIMITIVE(jit_compile)
300 PRIMITIVE_GETVM()->primitive_jit_compile();
303 /* push a new quotation on the stack */
304 inline void factor_vm::primitive_array_to_quotation()
306 quotation *quot = allot<quotation>(sizeof(quotation));
307 quot->array = dpeek();
308 quot->cached_effect = F;
309 quot->cache_counter = F;
310 quot->xt = (void *)lazy_jit_compile;
312 drepl(tag<quotation>(quot));
315 PRIMITIVE(array_to_quotation)
317 PRIMITIVE_GETVM()->primitive_array_to_quotation();
320 inline void factor_vm::primitive_quotation_xt()
322 quotation *quot = untag_check<quotation>(dpeek());
323 drepl(allot_cell((cell)quot->xt));
326 PRIMITIVE(quotation_xt)
328 PRIMITIVE_GETVM()->primitive_quotation_xt();
331 void factor_vm::compile_all_words()
333 gc_root<array> words(find_all_words(),this);
336 cell length = array_capacity(words.untagged());
337 for(i = 0; i < length; i++)
339 gc_root<word> word(array_nth(words.untagged(),i),this);
341 if(!word->code || !word_optimized_p(word.untagged()))
342 jit_compile_word(word.value(),word->def,false);
344 update_word_xt(word.value());
348 iterate_code_heap(factor::relocate_code_block);
351 /* Allocates memory */
352 fixnum factor_vm::quot_code_offset_to_scan(cell quot_, cell offset)
354 gc_root<quotation> quot(quot_,this);
355 gc_root<array> array(quot->array,this);
357 quotation_jit compiler(quot.value(),false,false,this);
358 compiler.compute_position(offset);
359 compiler.iterate_quotation();
361 return compiler.get_position();
364 cell factor_vm::lazy_jit_compile_impl(cell quot_, stack_frame *stack)
366 gc_root<quotation> quot(quot_,this);
367 stack_chain->callstack_top = stack;
368 jit_compile(quot.value(),true);
372 VM_ASM_API_OVERFLOW cell lazy_jit_compile_impl(cell quot_, stack_frame *stack, factor_vm *myvm)
375 return VM_PTR->lazy_jit_compile_impl(quot_,stack);
378 inline void factor_vm::primitive_quot_compiled_p()
380 tagged<quotation> quot(dpop());
381 quot.untag_check(this);
382 dpush(tag_boolean(quot->code != NULL));
385 PRIMITIVE(quot_compiled_p)
387 PRIMITIVE_GETVM()->primitive_quot_compiled_p();