Store forwarding table off to the side instead of in the code block; saves one cell per code block
parent
8486e6db82
commit
786b9096e2
|
@ -100,7 +100,7 @@ code_block *frame_code(stack_frame *frame)
|
|||
|
||||
cell frame_type(stack_frame *frame)
|
||||
{
|
||||
return frame_code(frame)->block.type;
|
||||
return frame_code(frame)->type;
|
||||
}
|
||||
|
||||
cell frame_executing(stack_frame *frame)
|
||||
|
|
|
@ -5,7 +5,7 @@ namespace factor
|
|||
|
||||
void flush_icache_for(code_block *block)
|
||||
{
|
||||
flush_icache((cell)block,block->block.size);
|
||||
flush_icache((cell)block,block->size);
|
||||
}
|
||||
|
||||
void iterate_relocations(code_block *compiled, relocation_iterator iter)
|
||||
|
@ -122,7 +122,7 @@ void update_literal_references_step(relocation_entry rel, cell index, code_block
|
|||
/* Update pointers to literals from compiled code. */
|
||||
void update_literal_references(code_block *compiled)
|
||||
{
|
||||
if(!compiled->block.needs_fixup)
|
||||
if(!compiled->needs_fixup)
|
||||
{
|
||||
iterate_relocations(compiled,update_literal_references_step);
|
||||
flush_icache_for(compiled);
|
||||
|
@ -133,12 +133,12 @@ void update_literal_references(code_block *compiled)
|
|||
aging and nursery collections */
|
||||
void copy_literal_references(code_block *compiled)
|
||||
{
|
||||
if(collecting_gen >= compiled->block.last_scan)
|
||||
if(collecting_gen >= compiled->last_scan)
|
||||
{
|
||||
if(collecting_accumulation_gen_p())
|
||||
compiled->block.last_scan = collecting_gen;
|
||||
compiled->last_scan = collecting_gen;
|
||||
else
|
||||
compiled->block.last_scan = collecting_gen + 1;
|
||||
compiled->last_scan = collecting_gen + 1;
|
||||
|
||||
/* initialize chase pointer */
|
||||
cell scan = newspace->here;
|
||||
|
@ -208,7 +208,7 @@ to update references to other words, without worrying about literals
|
|||
or dlsyms. */
|
||||
void update_word_references(code_block *compiled)
|
||||
{
|
||||
if(compiled->block.needs_fixup)
|
||||
if(compiled->needs_fixup)
|
||||
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
|
||||
|
@ -217,8 +217,8 @@ void update_word_references(code_block *compiled)
|
|||
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)
|
||||
heap_free(&code,&compiled->block);
|
||||
else if(compiled->type == PIC_TYPE)
|
||||
heap_free(&code,compiled);
|
||||
else
|
||||
{
|
||||
iterate_relocations(compiled,update_word_references_step);
|
||||
|
@ -248,7 +248,7 @@ void mark_code_block(code_block *compiled)
|
|||
{
|
||||
check_code_address((cell)compiled);
|
||||
|
||||
mark_block(&compiled->block);
|
||||
mark_block(compiled);
|
||||
|
||||
copy_handle(&compiled->literals);
|
||||
copy_handle(&compiled->relocation);
|
||||
|
@ -405,8 +405,8 @@ void relocate_code_block_step(relocation_entry rel, cell index, code_block *comp
|
|||
/* Perform all fixups on a code block */
|
||||
void relocate_code_block(code_block *compiled)
|
||||
{
|
||||
compiled->block.last_scan = NURSERY;
|
||||
compiled->block.needs_fixup = false;
|
||||
compiled->last_scan = NURSERY;
|
||||
compiled->needs_fixup = false;
|
||||
iterate_relocations(compiled,relocate_code_block_step);
|
||||
flush_icache_for(compiled);
|
||||
}
|
||||
|
@ -474,9 +474,9 @@ code_block *add_code_block(
|
|||
code_block *compiled = allot_code_block(code_length);
|
||||
|
||||
/* compiled header */
|
||||
compiled->block.type = type;
|
||||
compiled->block.last_scan = NURSERY;
|
||||
compiled->block.needs_fixup = true;
|
||||
compiled->type = type;
|
||||
compiled->last_scan = NURSERY;
|
||||
compiled->needs_fixup = true;
|
||||
compiled->relocation = relocation.value();
|
||||
|
||||
/* slight space optimization */
|
||||
|
|
|
@ -22,9 +22,9 @@ void new_heap(heap *heap, cell size)
|
|||
|
||||
static void add_to_free_list(heap *heap, free_heap_block *block)
|
||||
{
|
||||
if(block->block.size < FREE_LIST_COUNT * BLOCK_SIZE_INCREMENT)
|
||||
if(block->size < FREE_LIST_COUNT * BLOCK_SIZE_INCREMENT)
|
||||
{
|
||||
int index = block->block.size / BLOCK_SIZE_INCREMENT;
|
||||
int index = block->size / BLOCK_SIZE_INCREMENT;
|
||||
block->next_free = heap->free.small_blocks[index];
|
||||
heap->free.small_blocks[index] = block;
|
||||
}
|
||||
|
@ -73,8 +73,8 @@ void build_free_list(heap *heap, cell size)
|
|||
branch is only taken after loading a new image, not after code GC */
|
||||
if((cell)(end + 1) <= heap->seg->end)
|
||||
{
|
||||
end->block.status = B_FREE;
|
||||
end->block.size = heap->seg->end - (cell)end;
|
||||
end->status = B_FREE;
|
||||
end->size = heap->seg->end - (cell)end;
|
||||
|
||||
/* add final free block */
|
||||
add_to_free_list(heap,end);
|
||||
|
@ -93,7 +93,7 @@ void build_free_list(heap *heap, cell size)
|
|||
|
||||
static void assert_free_block(free_heap_block *block)
|
||||
{
|
||||
if(block->block.status != B_FREE)
|
||||
if(block->status != B_FREE)
|
||||
critical_error("Invalid block in free list",(cell)block);
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ static free_heap_block *find_free_block(heap *heap, cell size)
|
|||
while(block)
|
||||
{
|
||||
assert_free_block(block);
|
||||
if(block->block.size >= size)
|
||||
if(block->size >= size)
|
||||
{
|
||||
if(prev)
|
||||
prev->next_free = block->next_free;
|
||||
|
@ -139,14 +139,14 @@ static free_heap_block *find_free_block(heap *heap, cell size)
|
|||
|
||||
static free_heap_block *split_free_block(heap *heap, free_heap_block *block, cell size)
|
||||
{
|
||||
if(block->block.size != size )
|
||||
if(block->size != size )
|
||||
{
|
||||
/* split the block in two */
|
||||
free_heap_block *split = (free_heap_block *)((cell)block + size);
|
||||
split->block.status = B_FREE;
|
||||
split->block.size = block->block.size - size;
|
||||
split->status = B_FREE;
|
||||
split->size = block->size - size;
|
||||
split->next_free = block->next_free;
|
||||
block->block.size = size;
|
||||
block->size = size;
|
||||
add_to_free_list(heap,split);
|
||||
}
|
||||
|
||||
|
@ -163,8 +163,8 @@ heap_block *heap_allot(heap *heap, cell size)
|
|||
{
|
||||
block = split_free_block(heap,block,size);
|
||||
|
||||
block->block.status = B_ALLOCATED;
|
||||
return &block->block;
|
||||
block->status = B_ALLOCATED;
|
||||
return block;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
@ -303,16 +303,16 @@ cell heap_size(heap *heap)
|
|||
}
|
||||
|
||||
/* Compute where each block is going to go, after compaction */
|
||||
cell compute_heap_forwarding(heap *heap)
|
||||
cell compute_heap_forwarding(heap *heap, std::tr1::unordered_map<heap_block *,char *> &forwarding)
|
||||
{
|
||||
heap_block *scan = first_block(heap);
|
||||
cell address = (cell)first_block(heap);
|
||||
char *address = (char *)first_block(heap);
|
||||
|
||||
while(scan)
|
||||
{
|
||||
if(scan->status == B_ALLOCATED)
|
||||
{
|
||||
scan->forwarding = (heap_block *)address;
|
||||
forwarding[scan] = address;
|
||||
address += scan->size;
|
||||
}
|
||||
else if(scan->status == B_MARKED)
|
||||
|
@ -321,10 +321,10 @@ cell compute_heap_forwarding(heap *heap)
|
|||
scan = next_block(heap,scan);
|
||||
}
|
||||
|
||||
return address - heap->seg->start;
|
||||
return (cell)address - heap->seg->start;
|
||||
}
|
||||
|
||||
void compact_heap(heap *heap)
|
||||
void compact_heap(heap *heap, std::tr1::unordered_map<heap_block *,char *> &forwarding)
|
||||
{
|
||||
heap_block *scan = first_block(heap);
|
||||
|
||||
|
@ -332,8 +332,8 @@ void compact_heap(heap *heap)
|
|||
{
|
||||
heap_block *next = next_block(heap,scan);
|
||||
|
||||
if(scan->status == B_ALLOCATED && scan != scan->forwarding)
|
||||
memcpy(scan->forwarding,scan,scan->size);
|
||||
if(scan->status == B_ALLOCATED)
|
||||
memmove(forwarding[scan],scan,scan->size);
|
||||
scan = next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ void unmark_marked(heap *heap);
|
|||
void free_unmarked(heap *heap, heap_iterator iter);
|
||||
void heap_usage(heap *h, cell *used, cell *total_free, cell *max_free);
|
||||
cell heap_size(heap *h);
|
||||
cell compute_heap_forwarding(heap *h);
|
||||
void compact_heap(heap *h);
|
||||
cell compute_heap_forwarding(heap *h, std::tr1::unordered_map<heap_block *,char *> &forwarding);
|
||||
void compact_heap(heap *h, std::tr1::unordered_map<heap_block *,char *> &forwarding);
|
||||
|
||||
inline static heap_block *next_block(heap *h, heap_block *block)
|
||||
{
|
||||
|
|
|
@ -119,9 +119,11 @@ PRIMITIVE(code_room)
|
|||
dpush(tag_fixnum(max_free / 1024));
|
||||
}
|
||||
|
||||
static std::tr1::unordered_map<heap_block *,char *> forwarding;
|
||||
|
||||
code_block *forward_xt(code_block *compiled)
|
||||
{
|
||||
return (code_block *)compiled->block.forwarding;
|
||||
return (code_block *)forwarding[compiled];
|
||||
}
|
||||
|
||||
void forward_frame_xt(stack_frame *frame)
|
||||
|
@ -132,7 +134,7 @@ void forward_frame_xt(stack_frame *frame)
|
|||
FRAME_RETURN_ADDRESS(frame) = (void *)((cell)forwarded + offset);
|
||||
}
|
||||
|
||||
void forward_object_xts(void)
|
||||
void forward_object_xts()
|
||||
{
|
||||
begin_scan();
|
||||
|
||||
|
@ -215,13 +217,13 @@ void compact_code_heap(void)
|
|||
gc();
|
||||
|
||||
/* Figure out where the code heap blocks are going to end up */
|
||||
cell size = compute_heap_forwarding(&code);
|
||||
cell size = compute_heap_forwarding(&code, forwarding);
|
||||
|
||||
/* Update word and quotation code pointers */
|
||||
forward_object_xts();
|
||||
|
||||
/* Actually perform the compaction */
|
||||
compact_heap(&code);
|
||||
compact_heap(&code,forwarding);
|
||||
|
||||
/* Update word and quotation XTs */
|
||||
fixup_object_xts();
|
||||
|
|
|
@ -22,7 +22,7 @@ void deallocate_inline_cache(cell return_address)
|
|||
/* Find the call target. */
|
||||
void *old_xt = get_call_target(return_address);
|
||||
code_block *old_block = (code_block *)old_xt - 1;
|
||||
cell old_type = old_block->block.type;
|
||||
cell old_type = old_block->type;
|
||||
|
||||
#ifdef FACTOR_DEBUG
|
||||
/* The call target was either another PIC,
|
||||
|
@ -31,7 +31,7 @@ void deallocate_inline_cache(cell return_address)
|
|||
#endif
|
||||
|
||||
if(old_type == PIC_TYPE)
|
||||
heap_free(&code,&old_block->block);
|
||||
heap_free(&code,old_block);
|
||||
}
|
||||
|
||||
/* Figure out what kind of type check the PIC needs based on the methods
|
||||
|
|
|
@ -193,26 +193,19 @@ struct heap_block
|
|||
unsigned char status; /* free or allocated? */
|
||||
unsigned char type; /* this is WORD_TYPE or QUOTATION_TYPE */
|
||||
unsigned char last_scan; /* the youngest generation in which this block's literals may live */
|
||||
char needs_fixup; /* is this a new block that needs full fixup? */
|
||||
unsigned char needs_fixup; /* is this a new block that needs full fixup? */
|
||||
|
||||
/* In bytes, includes this header */
|
||||
cell size;
|
||||
|
||||
/* Used during compaction */
|
||||
heap_block *forwarding;
|
||||
};
|
||||
|
||||
struct free_heap_block
|
||||
struct free_heap_block : public heap_block
|
||||
{
|
||||
heap_block block;
|
||||
|
||||
/* Filled in on image load */
|
||||
free_heap_block *next_free;
|
||||
};
|
||||
|
||||
struct code_block
|
||||
struct code_block : public heap_block
|
||||
{
|
||||
heap_block block;
|
||||
cell literals; /* # bytes */
|
||||
cell relocation; /* tagged pointer to byte-array or f */
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <assert.h>
|
||||
#endif
|
||||
|
||||
/* C headers */
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
|
@ -20,6 +21,10 @@
|
|||
#include <time.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
/* C++ headers */
|
||||
#include <tr1/unordered_map>
|
||||
|
||||
/* Factor headers */
|
||||
#include "layouts.hpp"
|
||||
#include "platform.hpp"
|
||||
#include "primitives.hpp"
|
||||
|
|
|
@ -251,7 +251,7 @@ void quotation_jit::iterate_quotation()
|
|||
|
||||
void set_quot_xt(quotation *quot, code_block *code)
|
||||
{
|
||||
if(code->block.type != QUOTATION_TYPE)
|
||||
if(code->type != QUOTATION_TYPE)
|
||||
critical_error("Bad param to set_quot_xt",(cell)code);
|
||||
|
||||
quot->code = code;
|
||||
|
|
|
@ -44,7 +44,7 @@ PRIMITIVE(word_xt)
|
|||
word *w = untag_check<word>(dpop());
|
||||
code_block *code = (profiling_p ? w->profiling : w->code);
|
||||
dpush(allot_cell((cell)code->xt()));
|
||||
dpush(allot_cell((cell)code + code->block.size));
|
||||
dpush(allot_cell((cell)code + code->size));
|
||||
}
|
||||
|
||||
/* Allocates memory */
|
||||
|
|
|
@ -9,7 +9,7 @@ void update_word_xt(cell word);
|
|||
|
||||
inline bool word_optimized_p(word *word)
|
||||
{
|
||||
return word->code->block.type == WORD_TYPE;
|
||||
return word->code->type == WORD_TYPE;
|
||||
}
|
||||
|
||||
PRIMITIVE(optimized_p);
|
||||
|
|
Loading…
Reference in New Issue