At the end of a compilation unit, all PICs become dead so add them to the free list immediately instead of having them waste space until the next GC.

Similarly, when a PIC transition occurs, add the old PIC to the free list immediately. 
Remove an unused function update_code_heap_roots()
db4
Slava Pestov 2009-04-30 05:59:44 -05:00
parent 5fb5c19d61
commit 5bc63fc237
8 changed files with 68 additions and 21 deletions

View File

@ -154,16 +154,16 @@ void copy_literal_references(F_CODE_BLOCK *compiled)
CELL object_xt(CELL obj) CELL object_xt(CELL obj)
{ {
if(type_of(obj) == WORD_TYPE) if(TAG(obj) == QUOTATION_TYPE)
{
F_WORD *word = untag_object(obj);
return (CELL)word->xt;
}
else
{ {
F_QUOTATION *quot = untag_object(obj); F_QUOTATION *quot = untag_object(obj);
return (CELL)quot->xt; return (CELL)quot->xt;
} }
else
{
F_WORD *word = untag_object(obj);
return (CELL)word->xt;
}
} }
CELL word_direct_xt(CELL obj) CELL word_direct_xt(CELL obj)
@ -215,6 +215,18 @@ void update_word_references(F_CODE_BLOCK *compiled)
{ {
if(compiled->block.needs_fixup) if(compiled->block.needs_fixup)
relocate_code_block(compiled); relocate_code_block(compiled);
/* update_word_references() is always applied to every block in
the code heap. Since it resets all call sites to point to
their canonical XT (cold entry point for non-tail calls,
standard entry point for tail calls), it means that no PICs
are referenced after this is done. So instead of polluting
the code heap with dead PICs that will be freed on the next
GC, we add them to the free list immediately. */
else if(compiled->block.type == PIC_TYPE)
{
fflush(stdout);
heap_free(&code_heap,&compiled->block);
}
else else
{ {
iterate_relocations(compiled,update_word_references_step); iterate_relocations(compiled,update_word_references_step);

View File

@ -17,7 +17,7 @@ void new_heap(F_HEAP *heap, CELL size)
clear_free_list(heap); clear_free_list(heap);
} }
void add_to_free_list(F_HEAP *heap, F_FREE_BLOCK *block) static void add_to_free_list(F_HEAP *heap, F_FREE_BLOCK *block)
{ {
if(block->block.size < FREE_LIST_COUNT * BLOCK_SIZE_INCREMENT) if(block->block.size < FREE_LIST_COUNT * BLOCK_SIZE_INCREMENT)
{ {
@ -94,7 +94,7 @@ static void assert_free_block(F_FREE_BLOCK *block)
critical_error("Invalid block in free list",(CELL)block); critical_error("Invalid block in free list",(CELL)block);
} }
F_FREE_BLOCK *find_free_block(F_HEAP *heap, CELL size) static F_FREE_BLOCK *find_free_block(F_HEAP *heap, CELL size)
{ {
CELL attempt = size; CELL attempt = size;
@ -134,7 +134,7 @@ F_FREE_BLOCK *find_free_block(F_HEAP *heap, CELL size)
return NULL; return NULL;
} }
F_FREE_BLOCK *split_free_block(F_HEAP *heap, F_FREE_BLOCK *block, CELL size) static F_FREE_BLOCK *split_free_block(F_HEAP *heap, F_FREE_BLOCK *block, CELL size)
{ {
if(block->block.size != size ) if(block->block.size != size )
{ {
@ -167,6 +167,13 @@ F_BLOCK *heap_allot(F_HEAP *heap, CELL size)
return NULL; return NULL;
} }
/* Deallocates a block manually */
void heap_free(F_HEAP *heap, F_BLOCK *block)
{
block->status = B_FREE;
add_to_free_list(heap,(F_FREE_BLOCK *)block);
}
void mark_block(F_BLOCK *block) void mark_block(F_BLOCK *block)
{ {
/* If already marked, do nothing */ /* If already marked, do nothing */

View File

@ -16,6 +16,7 @@ typedef void (*HEAP_ITERATOR)(F_BLOCK *compiled);
void new_heap(F_HEAP *heap, CELL size); void new_heap(F_HEAP *heap, CELL size);
void build_free_list(F_HEAP *heap, CELL size); void build_free_list(F_HEAP *heap, CELL size);
F_BLOCK *heap_allot(F_HEAP *heap, CELL size); F_BLOCK *heap_allot(F_HEAP *heap, CELL size);
void heap_free(F_HEAP *heap, F_BLOCK *block);
void mark_block(F_BLOCK *block); void mark_block(F_BLOCK *block);
void unmark_marked(F_HEAP *heap); void unmark_marked(F_HEAP *heap);
void free_unmarked(F_HEAP *heap, HEAP_ITERATOR iter); void free_unmarked(F_HEAP *heap, HEAP_ITERATOR iter);

View File

@ -47,13 +47,6 @@ void copy_code_heap_roots(void)
iterate_code_heap(copy_literal_references); iterate_code_heap(copy_literal_references);
} }
/* Update literals referenced from all code blocks. Only for tenured
collections, done at the end. */
void update_code_heap_roots(void)
{
iterate_code_heap(update_literal_and_word_references);
}
/* Update pointers to words referenced from all code blocks. Only after /* Update pointers to words referenced from all code blocks. Only after
defining a new word. */ defining a new word. */
void update_code_heap_words(void) void update_code_heap_words(void)

View File

@ -13,8 +13,6 @@ void iterate_code_heap(CODE_HEAP_ITERATOR iter);
void copy_code_heap_roots(void); void copy_code_heap_roots(void);
void update_code_heap_roots(void);
void primitive_modify_code_heap(void); void primitive_modify_code_heap(void);
void primitive_code_room(void); void primitive_code_room(void);

View File

@ -10,7 +10,7 @@ F_FASTCALL void lazy_jit_compile(CELL quot);
void set_callstack(F_STACK_FRAME *to, F_STACK_FRAME *from, CELL length, void *memcpy); void set_callstack(F_STACK_FRAME *to, F_STACK_FRAME *from, CELL length, void *memcpy);
INLINE void set_call_site(CELL return_address, CELL target) INLINE void check_call_site(CELL return_address)
{ {
/* An x86 CALL instruction looks like so: /* An x86 CALL instruction looks like so:
|e8|..|..|..|..| |e8|..|..|..|..|
@ -20,5 +20,16 @@ INLINE void set_call_site(CELL return_address, CELL target)
#ifdef FACTOR_DEBUG #ifdef FACTOR_DEBUG
assert(*(unsigned char *)(return_address - 5) == 0xe8); assert(*(unsigned char *)(return_address - 5) == 0xe8);
#endif #endif
}
INLINE CELL get_call_target(CELL return_address)
{
check_call_site(return_address);
return *(F_FIXNUM *)(return_address - 4) + return_address;
}
INLINE void set_call_target(CELL return_address, CELL target)
{
check_call_site(return_address);
*(F_FIXNUM *)(return_address - 4) = (target - return_address); *(F_FIXNUM *)(return_address - 4) = (target - return_address);
} }

View File

@ -5,6 +5,23 @@ void init_inline_caching(int max_size)
max_pic_size = max_size; max_pic_size = max_size;
} }
void deallocate_inline_cache(CELL return_address)
{
/* Find the call target. */
XT old_xt = (XT)get_call_target(return_address);
F_CODE_BLOCK *old_block = (F_CODE_BLOCK *)old_xt - 1;
CELL old_type = old_block->block.type;
#ifdef FACTOR_DEBUG
/* The call target was either another PIC,
or a compiled quotation (megamorphic stub) */
assert(old_type == PIC_TYPE || old_type == QUOTATION_TYPE);
#endif
if(old_type == PIC_TYPE)
heap_free(&code_heap,&old_block->block);
}
/* Figure out what kind of type check the PIC needs based on the methods /* Figure out what kind of type check the PIC needs based on the methods
it contains */ it contains */
static CELL determine_inline_cache_type(CELL cache_entries) static CELL determine_inline_cache_type(CELL cache_entries)
@ -79,7 +96,7 @@ static F_CODE_BLOCK *compile_inline_cache(F_FIXNUM index, CELL generic_word, CEL
update_pic_count(inline_cache_type); update_pic_count(inline_cache_type);
F_JIT jit; F_JIT jit;
jit_init(&jit,WORD_TYPE,generic_word); jit_init(&jit,PIC_TYPE,generic_word);
/* Generate machine code to determine the object's class. */ /* Generate machine code to determine the object's class. */
jit_emit_class_lookup(&jit,index,inline_cache_type); jit_emit_class_lookup(&jit,index,inline_cache_type);
@ -163,6 +180,11 @@ XT inline_cache_miss(CELL return_address)
{ {
check_code_pointer(return_address); check_code_pointer(return_address);
/* Since each PIC is only referenced from a single call site,
if the old call target was a PIC, we can deallocate it immediately,
instead of leaving dead PICs around until the next GC. */
deallocate_inline_cache(return_address);
CELL cache_entries = dpop(); CELL cache_entries = dpop();
F_FIXNUM index = untag_fixnum_fast(dpop()); F_FIXNUM index = untag_fixnum_fast(dpop());
CELL methods = dpop(); CELL methods = dpop();
@ -195,7 +217,7 @@ XT inline_cache_miss(CELL return_address)
} }
/* Install the new stub. */ /* Install the new stub. */
set_call_site(return_address,(CELL)xt); set_call_target(return_address,(CELL)xt);
#ifdef PIC_DEBUG #ifdef PIC_DEBUG
printf("Updated call site 0x%lx with 0x%lx\n",return_address,(CELL)xt); printf("Updated call site 0x%lx with 0x%lx\n",return_address,(CELL)xt);

View File

@ -60,6 +60,9 @@ typedef signed long long s64;
#define TYPE_COUNT 15 #define TYPE_COUNT 15
/* Not a real type, but F_CODE_BLOCK's type field can be set to this */
#define PIC_TYPE 69
INLINE bool immediate_p(CELL obj) INLINE bool immediate_p(CELL obj)
{ {
return (obj == F || TAG(obj) == FIXNUM_TYPE); return (obj == F || TAG(obj) == FIXNUM_TYPE);