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)
|
cell frame_type(stack_frame *frame)
|
||||||
{
|
{
|
||||||
return frame_code(frame)->block.type;
|
return frame_code(frame)->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
cell frame_executing(stack_frame *frame)
|
cell frame_executing(stack_frame *frame)
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace factor
|
||||||
|
|
||||||
void flush_icache_for(code_block *block)
|
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)
|
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. */
|
/* Update pointers to literals from compiled code. */
|
||||||
void update_literal_references(code_block *compiled)
|
void update_literal_references(code_block *compiled)
|
||||||
{
|
{
|
||||||
if(!compiled->block.needs_fixup)
|
if(!compiled->needs_fixup)
|
||||||
{
|
{
|
||||||
iterate_relocations(compiled,update_literal_references_step);
|
iterate_relocations(compiled,update_literal_references_step);
|
||||||
flush_icache_for(compiled);
|
flush_icache_for(compiled);
|
||||||
|
@ -133,12 +133,12 @@ void update_literal_references(code_block *compiled)
|
||||||
aging and nursery collections */
|
aging and nursery collections */
|
||||||
void copy_literal_references(code_block *compiled)
|
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())
|
if(collecting_accumulation_gen_p())
|
||||||
compiled->block.last_scan = collecting_gen;
|
compiled->last_scan = collecting_gen;
|
||||||
else
|
else
|
||||||
compiled->block.last_scan = collecting_gen + 1;
|
compiled->last_scan = collecting_gen + 1;
|
||||||
|
|
||||||
/* initialize chase pointer */
|
/* initialize chase pointer */
|
||||||
cell scan = newspace->here;
|
cell scan = newspace->here;
|
||||||
|
@ -208,7 +208,7 @@ to update references to other words, without worrying about literals
|
||||||
or dlsyms. */
|
or dlsyms. */
|
||||||
void update_word_references(code_block *compiled)
|
void update_word_references(code_block *compiled)
|
||||||
{
|
{
|
||||||
if(compiled->block.needs_fixup)
|
if(compiled->needs_fixup)
|
||||||
relocate_code_block(compiled);
|
relocate_code_block(compiled);
|
||||||
/* update_word_references() is always applied to every block in
|
/* update_word_references() is always applied to every block in
|
||||||
the code heap. Since it resets all call sites to point to
|
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
|
are referenced after this is done. So instead of polluting
|
||||||
the code heap with dead PICs that will be freed on the next
|
the code heap with dead PICs that will be freed on the next
|
||||||
GC, we add them to the free list immediately. */
|
GC, we add them to the free list immediately. */
|
||||||
else if(compiled->block.type == PIC_TYPE)
|
else if(compiled->type == PIC_TYPE)
|
||||||
heap_free(&code,&compiled->block);
|
heap_free(&code,compiled);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iterate_relocations(compiled,update_word_references_step);
|
iterate_relocations(compiled,update_word_references_step);
|
||||||
|
@ -248,7 +248,7 @@ void mark_code_block(code_block *compiled)
|
||||||
{
|
{
|
||||||
check_code_address((cell)compiled);
|
check_code_address((cell)compiled);
|
||||||
|
|
||||||
mark_block(&compiled->block);
|
mark_block(compiled);
|
||||||
|
|
||||||
copy_handle(&compiled->literals);
|
copy_handle(&compiled->literals);
|
||||||
copy_handle(&compiled->relocation);
|
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 */
|
/* Perform all fixups on a code block */
|
||||||
void relocate_code_block(code_block *compiled)
|
void relocate_code_block(code_block *compiled)
|
||||||
{
|
{
|
||||||
compiled->block.last_scan = NURSERY;
|
compiled->last_scan = NURSERY;
|
||||||
compiled->block.needs_fixup = false;
|
compiled->needs_fixup = false;
|
||||||
iterate_relocations(compiled,relocate_code_block_step);
|
iterate_relocations(compiled,relocate_code_block_step);
|
||||||
flush_icache_for(compiled);
|
flush_icache_for(compiled);
|
||||||
}
|
}
|
||||||
|
@ -474,9 +474,9 @@ code_block *add_code_block(
|
||||||
code_block *compiled = allot_code_block(code_length);
|
code_block *compiled = allot_code_block(code_length);
|
||||||
|
|
||||||
/* compiled header */
|
/* compiled header */
|
||||||
compiled->block.type = type;
|
compiled->type = type;
|
||||||
compiled->block.last_scan = NURSERY;
|
compiled->last_scan = NURSERY;
|
||||||
compiled->block.needs_fixup = true;
|
compiled->needs_fixup = true;
|
||||||
compiled->relocation = relocation.value();
|
compiled->relocation = relocation.value();
|
||||||
|
|
||||||
/* slight space optimization */
|
/* 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)
|
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];
|
block->next_free = heap->free.small_blocks[index];
|
||||||
heap->free.small_blocks[index] = block;
|
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 */
|
branch is only taken after loading a new image, not after code GC */
|
||||||
if((cell)(end + 1) <= heap->seg->end)
|
if((cell)(end + 1) <= heap->seg->end)
|
||||||
{
|
{
|
||||||
end->block.status = B_FREE;
|
end->status = B_FREE;
|
||||||
end->block.size = heap->seg->end - (cell)end;
|
end->size = heap->seg->end - (cell)end;
|
||||||
|
|
||||||
/* add final free block */
|
/* add final free block */
|
||||||
add_to_free_list(heap,end);
|
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)
|
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);
|
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)
|
while(block)
|
||||||
{
|
{
|
||||||
assert_free_block(block);
|
assert_free_block(block);
|
||||||
if(block->block.size >= size)
|
if(block->size >= size)
|
||||||
{
|
{
|
||||||
if(prev)
|
if(prev)
|
||||||
prev->next_free = block->next_free;
|
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)
|
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 */
|
/* split the block in two */
|
||||||
free_heap_block *split = (free_heap_block *)((cell)block + size);
|
free_heap_block *split = (free_heap_block *)((cell)block + size);
|
||||||
split->block.status = B_FREE;
|
split->status = B_FREE;
|
||||||
split->block.size = block->block.size - size;
|
split->size = block->size - size;
|
||||||
split->next_free = block->next_free;
|
split->next_free = block->next_free;
|
||||||
block->block.size = size;
|
block->size = size;
|
||||||
add_to_free_list(heap,split);
|
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 = split_free_block(heap,block,size);
|
||||||
|
|
||||||
block->block.status = B_ALLOCATED;
|
block->status = B_ALLOCATED;
|
||||||
return &block->block;
|
return block;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -303,16 +303,16 @@ cell heap_size(heap *heap)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute where each block is going to go, after compaction */
|
/* 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);
|
heap_block *scan = first_block(heap);
|
||||||
cell address = (cell)first_block(heap);
|
char *address = (char *)first_block(heap);
|
||||||
|
|
||||||
while(scan)
|
while(scan)
|
||||||
{
|
{
|
||||||
if(scan->status == B_ALLOCATED)
|
if(scan->status == B_ALLOCATED)
|
||||||
{
|
{
|
||||||
scan->forwarding = (heap_block *)address;
|
forwarding[scan] = address;
|
||||||
address += scan->size;
|
address += scan->size;
|
||||||
}
|
}
|
||||||
else if(scan->status == B_MARKED)
|
else if(scan->status == B_MARKED)
|
||||||
|
@ -321,10 +321,10 @@ cell compute_heap_forwarding(heap *heap)
|
||||||
scan = next_block(heap,scan);
|
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);
|
heap_block *scan = first_block(heap);
|
||||||
|
|
||||||
|
@ -332,8 +332,8 @@ void compact_heap(heap *heap)
|
||||||
{
|
{
|
||||||
heap_block *next = next_block(heap,scan);
|
heap_block *next = next_block(heap,scan);
|
||||||
|
|
||||||
if(scan->status == B_ALLOCATED && scan != scan->forwarding)
|
if(scan->status == B_ALLOCATED)
|
||||||
memcpy(scan->forwarding,scan,scan->size);
|
memmove(forwarding[scan],scan,scan->size);
|
||||||
scan = next;
|
scan = next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ void unmark_marked(heap *heap);
|
||||||
void free_unmarked(heap *heap, heap_iterator iter);
|
void free_unmarked(heap *heap, heap_iterator iter);
|
||||||
void heap_usage(heap *h, cell *used, cell *total_free, cell *max_free);
|
void heap_usage(heap *h, cell *used, cell *total_free, cell *max_free);
|
||||||
cell heap_size(heap *h);
|
cell heap_size(heap *h);
|
||||||
cell compute_heap_forwarding(heap *h);
|
cell compute_heap_forwarding(heap *h, std::tr1::unordered_map<heap_block *,char *> &forwarding);
|
||||||
void compact_heap(heap *h);
|
void compact_heap(heap *h, std::tr1::unordered_map<heap_block *,char *> &forwarding);
|
||||||
|
|
||||||
inline static heap_block *next_block(heap *h, heap_block *block)
|
inline static heap_block *next_block(heap *h, heap_block *block)
|
||||||
{
|
{
|
||||||
|
|
|
@ -119,9 +119,11 @@ PRIMITIVE(code_room)
|
||||||
dpush(tag_fixnum(max_free / 1024));
|
dpush(tag_fixnum(max_free / 1024));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::tr1::unordered_map<heap_block *,char *> forwarding;
|
||||||
|
|
||||||
code_block *forward_xt(code_block *compiled)
|
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)
|
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);
|
FRAME_RETURN_ADDRESS(frame) = (void *)((cell)forwarded + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
void forward_object_xts(void)
|
void forward_object_xts()
|
||||||
{
|
{
|
||||||
begin_scan();
|
begin_scan();
|
||||||
|
|
||||||
|
@ -215,13 +217,13 @@ void compact_code_heap(void)
|
||||||
gc();
|
gc();
|
||||||
|
|
||||||
/* Figure out where the code heap blocks are going to end up */
|
/* 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 */
|
/* Update word and quotation code pointers */
|
||||||
forward_object_xts();
|
forward_object_xts();
|
||||||
|
|
||||||
/* Actually perform the compaction */
|
/* Actually perform the compaction */
|
||||||
compact_heap(&code);
|
compact_heap(&code,forwarding);
|
||||||
|
|
||||||
/* Update word and quotation XTs */
|
/* Update word and quotation XTs */
|
||||||
fixup_object_xts();
|
fixup_object_xts();
|
||||||
|
|
|
@ -22,7 +22,7 @@ void deallocate_inline_cache(cell return_address)
|
||||||
/* Find the call target. */
|
/* Find the call target. */
|
||||||
void *old_xt = get_call_target(return_address);
|
void *old_xt = get_call_target(return_address);
|
||||||
code_block *old_block = (code_block *)old_xt - 1;
|
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
|
#ifdef FACTOR_DEBUG
|
||||||
/* The call target was either another PIC,
|
/* The call target was either another PIC,
|
||||||
|
@ -31,7 +31,7 @@ void deallocate_inline_cache(cell return_address)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(old_type == PIC_TYPE)
|
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
|
/* 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 status; /* free or allocated? */
|
||||||
unsigned char type; /* this is WORD_TYPE or QUOTATION_TYPE */
|
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 */
|
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 */
|
/* In bytes, includes this header */
|
||||||
cell size;
|
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;
|
free_heap_block *next_free;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct code_block
|
struct code_block : public heap_block
|
||||||
{
|
{
|
||||||
heap_block block;
|
|
||||||
cell literals; /* # bytes */
|
cell literals; /* # bytes */
|
||||||
cell relocation; /* tagged pointer to byte-array or f */
|
cell relocation; /* tagged pointer to byte-array or f */
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* C headers */
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
@ -20,6 +21,10 @@
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
|
||||||
|
/* C++ headers */
|
||||||
|
#include <tr1/unordered_map>
|
||||||
|
|
||||||
|
/* Factor headers */
|
||||||
#include "layouts.hpp"
|
#include "layouts.hpp"
|
||||||
#include "platform.hpp"
|
#include "platform.hpp"
|
||||||
#include "primitives.hpp"
|
#include "primitives.hpp"
|
||||||
|
|
|
@ -251,7 +251,7 @@ void quotation_jit::iterate_quotation()
|
||||||
|
|
||||||
void set_quot_xt(quotation *quot, code_block *code)
|
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);
|
critical_error("Bad param to set_quot_xt",(cell)code);
|
||||||
|
|
||||||
quot->code = code;
|
quot->code = code;
|
||||||
|
|
|
@ -44,7 +44,7 @@ PRIMITIVE(word_xt)
|
||||||
word *w = untag_check<word>(dpop());
|
word *w = untag_check<word>(dpop());
|
||||||
code_block *code = (profiling_p ? w->profiling : w->code);
|
code_block *code = (profiling_p ? w->profiling : w->code);
|
||||||
dpush(allot_cell((cell)code->xt()));
|
dpush(allot_cell((cell)code->xt()));
|
||||||
dpush(allot_cell((cell)code + code->block.size));
|
dpush(allot_cell((cell)code + code->size));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocates memory */
|
/* Allocates memory */
|
||||||
|
|
|
@ -9,7 +9,7 @@ void update_word_xt(cell word);
|
||||||
|
|
||||||
inline bool word_optimized_p(word *word)
|
inline bool word_optimized_p(word *word)
|
||||||
{
|
{
|
||||||
return word->code->block.type == WORD_TYPE;
|
return word->code->type == WORD_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
PRIMITIVE(optimized_p);
|
PRIMITIVE(optimized_p);
|
||||||
|
|
Loading…
Reference in New Issue