vm: change code heap layout somewhat, remove unused allocation bitmap from mark_bits
parent
931307500e
commit
838a44e901
|
@ -346,7 +346,7 @@ void factor_vm::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->type() == PIC_TYPE)
|
||||
else if(compiled->pic_p())
|
||||
code->code_heap_free(compiled);
|
||||
else
|
||||
{
|
||||
|
@ -437,9 +437,9 @@ void factor_vm::fixup_labels(array *labels, code_block *compiled)
|
|||
}
|
||||
|
||||
/* Might GC */
|
||||
code_block *factor_vm::allot_code_block(cell size, cell type)
|
||||
code_block *factor_vm::allot_code_block(cell size, code_block_type type)
|
||||
{
|
||||
heap_block *block = code->heap_allot(size + sizeof(code_block),type);
|
||||
heap_block *block = code->heap_allot(size + sizeof(code_block));
|
||||
|
||||
/* If allocation failed, do a full GC and compact the code heap.
|
||||
A full GC that occurs as a result of the data heap filling up does not
|
||||
|
@ -449,7 +449,7 @@ code_block *factor_vm::allot_code_block(cell size, cell type)
|
|||
if(block == NULL)
|
||||
{
|
||||
primitive_compact_gc();
|
||||
block = code->heap_allot(size + sizeof(code_block),type);
|
||||
block = code->heap_allot(size + sizeof(code_block));
|
||||
|
||||
/* Insufficient room even after code GC, give up */
|
||||
if(block == NULL)
|
||||
|
@ -465,11 +465,13 @@ code_block *factor_vm::allot_code_block(cell size, cell type)
|
|||
}
|
||||
}
|
||||
|
||||
return (code_block *)block;
|
||||
code_block *compiled = (code_block *)block;
|
||||
compiled->set_type(type);
|
||||
return compiled;
|
||||
}
|
||||
|
||||
/* Might GC */
|
||||
code_block *factor_vm::add_code_block(cell type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_)
|
||||
code_block *factor_vm::add_code_block(code_block_type type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_)
|
||||
{
|
||||
gc_root<byte_array> code(code_,this);
|
||||
gc_root<object> labels(labels_,this);
|
||||
|
|
|
@ -144,7 +144,7 @@ void factor_vm::primitive_modify_code_heap()
|
|||
cell code = array_nth(compiled_data,4);
|
||||
|
||||
code_block *compiled = add_code_block(
|
||||
WORD_TYPE,
|
||||
code_block_optimized,
|
||||
code,
|
||||
labels,
|
||||
owner,
|
||||
|
|
|
@ -295,7 +295,7 @@ void factor_vm::dump_code_heap()
|
|||
while(scan != end)
|
||||
{
|
||||
const char *status;
|
||||
if(scan->type() == FREE_BLOCK_TYPE)
|
||||
if(scan->free_p())
|
||||
status = "free";
|
||||
else if(code->state->is_marked_p(scan))
|
||||
{
|
||||
|
|
47
vm/heap.cpp
47
vm/heap.cpp
|
@ -49,15 +49,16 @@ void heap::build_free_list(cell size)
|
|||
{
|
||||
clear_free_list();
|
||||
free_heap_block *end = (free_heap_block *)(seg->start + size);
|
||||
end->set_type(FREE_BLOCK_TYPE);
|
||||
end->set_free();
|
||||
end->set_size(seg->end - (cell)end);
|
||||
add_to_free_list(end);
|
||||
}
|
||||
|
||||
void heap::assert_free_block(free_heap_block *block)
|
||||
{
|
||||
if(block->type() != FREE_BLOCK_TYPE)
|
||||
critical_error("Invalid block in free list",(cell)block);
|
||||
#ifdef FACTOR_DEBUG
|
||||
assert(block->free_p());
|
||||
#endif
|
||||
}
|
||||
|
||||
free_heap_block *heap::find_free_block(cell size)
|
||||
|
@ -102,11 +103,11 @@ free_heap_block *heap::find_free_block(cell size)
|
|||
|
||||
free_heap_block *heap::split_free_block(free_heap_block *block, cell size)
|
||||
{
|
||||
if(block->size() != size )
|
||||
if(block->size() != size)
|
||||
{
|
||||
/* split the block in two */
|
||||
free_heap_block *split = (free_heap_block *)((cell)block + size);
|
||||
split->set_type(FREE_BLOCK_TYPE);
|
||||
split->set_free();
|
||||
split->set_size(block->size() - size);
|
||||
split->next_free = block->next_free;
|
||||
block->set_size(size);
|
||||
|
@ -116,27 +117,25 @@ free_heap_block *heap::split_free_block(free_heap_block *block, cell size)
|
|||
return block;
|
||||
}
|
||||
|
||||
/* Allocate a block of memory from the mark and sweep GC heap */
|
||||
heap_block *heap::heap_allot(cell size, cell type)
|
||||
heap_block *heap::heap_allot(cell size)
|
||||
{
|
||||
size = (size + block_size_increment - 1) & ~(block_size_increment - 1);
|
||||
size = align(size,block_size_increment);
|
||||
|
||||
free_heap_block *block = find_free_block(size);
|
||||
if(block)
|
||||
{
|
||||
block = split_free_block(block,size);
|
||||
block->set_type(type);
|
||||
return block;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Deallocates a block manually */
|
||||
void heap::heap_free(heap_block *block)
|
||||
{
|
||||
block->set_type(FREE_BLOCK_TYPE);
|
||||
add_to_free_list((free_heap_block *)block);
|
||||
free_heap_block *free_block = (free_heap_block *)block;
|
||||
free_block->set_free();
|
||||
add_to_free_list(free_block);
|
||||
}
|
||||
|
||||
void heap::mark_block(heap_block *block)
|
||||
|
@ -158,7 +157,7 @@ void heap::heap_usage(cell *used, cell *total_free, cell *max_free)
|
|||
{
|
||||
cell size = scan->size();
|
||||
|
||||
if(scan->type() == FREE_BLOCK_TYPE)
|
||||
if(scan->free_p())
|
||||
{
|
||||
*total_free += size;
|
||||
if(size > *max_free)
|
||||
|
@ -179,31 +178,19 @@ cell heap::heap_size()
|
|||
|
||||
while(scan != end)
|
||||
{
|
||||
if(scan->type() == FREE_BLOCK_TYPE) break;
|
||||
if(scan->free_p()) break;
|
||||
else scan = scan->next();
|
||||
}
|
||||
|
||||
assert(scan->type() == FREE_BLOCK_TYPE);
|
||||
if(scan != end)
|
||||
{
|
||||
assert(scan->free_p());
|
||||
assert((cell)scan + scan->size() == seg->end);
|
||||
|
||||
return (cell)scan - (cell)first_block();
|
||||
}
|
||||
|
||||
heap_block *heap::free_allocated(heap_block *prev, heap_block *scan)
|
||||
{
|
||||
if(secure_gc)
|
||||
memset(scan + 1,0,scan->size() - sizeof(heap_block));
|
||||
|
||||
if(prev && prev->type() == FREE_BLOCK_TYPE)
|
||||
{
|
||||
prev->set_size(prev->size() + scan->size());
|
||||
return prev;
|
||||
}
|
||||
else
|
||||
{
|
||||
scan->set_type(FREE_BLOCK_TYPE);
|
||||
return scan;
|
||||
}
|
||||
return seg->size;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
30
vm/heap.hpp
30
vm/heap.hpp
|
@ -34,15 +34,13 @@ struct heap {
|
|||
void assert_free_block(free_heap_block *block);
|
||||
free_heap_block *find_free_block(cell size);
|
||||
free_heap_block *split_free_block(free_heap_block *block, cell size);
|
||||
heap_block *heap_allot(cell size, cell type);
|
||||
heap_block *heap_allot(cell size);
|
||||
void heap_free(heap_block *block);
|
||||
void mark_block(heap_block *block);
|
||||
void heap_usage(cell *used, cell *total_free, cell *max_free);
|
||||
cell heap_size();
|
||||
void compact_heap();
|
||||
|
||||
heap_block *free_allocated(heap_block *prev, heap_block *scan);
|
||||
|
||||
template<typename Iterator> void sweep_heap(Iterator &iter);
|
||||
template<typename Iterator> void compact_heap(Iterator &iter);
|
||||
|
||||
|
@ -54,7 +52,7 @@ struct heap {
|
|||
while(scan != end)
|
||||
{
|
||||
heap_block *next = scan->next();
|
||||
if(scan->type() != FREE_BLOCK_TYPE) iter(scan,scan->size());
|
||||
if(!scan->free_p()) iter(scan,scan->size());
|
||||
scan = next;
|
||||
}
|
||||
}
|
||||
|
@ -72,27 +70,41 @@ template<typename Iterator> void heap::sweep_heap(Iterator &iter)
|
|||
|
||||
while(scan != end)
|
||||
{
|
||||
if(scan->type() == FREE_BLOCK_TYPE)
|
||||
if(scan->free_p())
|
||||
{
|
||||
if(prev && prev->type() == FREE_BLOCK_TYPE)
|
||||
if(prev && prev->free_p())
|
||||
prev->set_size(prev->size() + scan->size());
|
||||
else
|
||||
prev = scan;
|
||||
}
|
||||
else if(this->state->is_marked_p(scan))
|
||||
{
|
||||
if(prev && prev->type() == FREE_BLOCK_TYPE)
|
||||
if(prev && prev->free_p())
|
||||
this->add_to_free_list((free_heap_block *)prev);
|
||||
prev = scan;
|
||||
iter(scan,scan->size());
|
||||
}
|
||||
else
|
||||
prev = this->free_allocated(prev,scan);
|
||||
{
|
||||
if(secure_gc)
|
||||
memset(scan + 1,0,scan->size() - sizeof(heap_block));
|
||||
|
||||
if(prev && prev->free_p())
|
||||
{
|
||||
free_heap_block *free_prev = (free_heap_block *)prev;
|
||||
free_prev->set_size(free_prev->size() + scan->size());
|
||||
}
|
||||
else
|
||||
{
|
||||
scan->set_free();
|
||||
prev = scan;
|
||||
}
|
||||
}
|
||||
|
||||
scan = scan->next();
|
||||
}
|
||||
|
||||
if(prev && prev->type() == FREE_BLOCK_TYPE)
|
||||
if(prev && prev->free_p())
|
||||
this->add_to_free_list((free_heap_block *)prev);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,15 +19,9 @@ void factor_vm::deallocate_inline_cache(cell return_address)
|
|||
check_code_pointer((cell)old_xt);
|
||||
|
||||
code_block *old_block = (code_block *)old_xt - 1;
|
||||
cell old_type = old_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)
|
||||
/* Free the old PIC since we know its unreachable */
|
||||
if(old_block->pic_p())
|
||||
code->code_heap_free(old_block);
|
||||
}
|
||||
|
||||
|
@ -78,7 +72,7 @@ void factor_vm::update_pic_count(cell type)
|
|||
struct inline_cache_jit : public jit {
|
||||
fixnum index;
|
||||
|
||||
explicit inline_cache_jit(cell generic_word_,factor_vm *vm) : jit(PIC_TYPE,generic_word_,vm) {};
|
||||
explicit inline_cache_jit(cell generic_word_,factor_vm *vm) : jit(code_block_pic,generic_word_,vm) {};
|
||||
|
||||
void emit_check(cell klass);
|
||||
void compile_inline_cache(fixnum index,
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace factor
|
|||
- polymorphic inline caches (inline_cache.cpp) */
|
||||
|
||||
/* Allocates memory */
|
||||
jit::jit(cell type_, cell owner_, factor_vm *vm)
|
||||
jit::jit(code_block_type type_, cell owner_, factor_vm *vm)
|
||||
: type(type_),
|
||||
owner(owner_,vm),
|
||||
code(vm),
|
||||
|
|
|
@ -2,7 +2,7 @@ namespace factor
|
|||
{
|
||||
|
||||
struct jit {
|
||||
cell type;
|
||||
code_block_type type;
|
||||
gc_root<object> owner;
|
||||
growable_byte_array code;
|
||||
growable_byte_array relocation;
|
||||
|
@ -12,7 +12,7 @@ struct jit {
|
|||
cell offset;
|
||||
factor_vm *parent;
|
||||
|
||||
explicit jit(cell jit_type, cell owner, factor_vm *vm);
|
||||
explicit jit(code_block_type type, cell owner, factor_vm *parent);
|
||||
void compute_position(cell offset);
|
||||
|
||||
void emit_relocation(cell code_template);
|
||||
|
|
|
@ -62,8 +62,14 @@ inline static cell align8(cell a)
|
|||
#define TYPE_COUNT 15
|
||||
|
||||
/* Not real types, but code_block's type can be set to this */
|
||||
#define PIC_TYPE 16
|
||||
#define FREE_BLOCK_TYPE 17
|
||||
|
||||
enum code_block_type
|
||||
{
|
||||
code_block_unoptimized,
|
||||
code_block_optimized,
|
||||
code_block_profiling,
|
||||
code_block_pic
|
||||
};
|
||||
|
||||
/* Constants used when floating-point trap exceptions are thrown */
|
||||
enum
|
||||
|
@ -201,16 +207,29 @@ struct heap_block
|
|||
{
|
||||
cell header;
|
||||
|
||||
cell type() { return (header >> 1) & 0x1f; }
|
||||
void set_type(cell type)
|
||||
bool free_p()
|
||||
{
|
||||
header = ((header & ~(0x1f << 1)) | (type << 1));
|
||||
return header & 1 == 1;
|
||||
}
|
||||
|
||||
void set_free()
|
||||
{
|
||||
header |= 1;
|
||||
}
|
||||
|
||||
void clear_free()
|
||||
{
|
||||
header &= ~1;
|
||||
}
|
||||
|
||||
cell size()
|
||||
{
|
||||
return header >> 3;
|
||||
}
|
||||
|
||||
cell size() { return (header >> 6); }
|
||||
void set_size(cell size)
|
||||
{
|
||||
header = (header & 0x2f) | (size << 6);
|
||||
header = (header & 0x7) | (size << 3);
|
||||
}
|
||||
|
||||
inline heap_block *next()
|
||||
|
@ -230,7 +249,30 @@ struct code_block : public heap_block
|
|||
cell literals; /* tagged pointer to array or f */
|
||||
cell relocation; /* tagged pointer to byte-array or f */
|
||||
|
||||
void *xt() { return (void *)(this + 1); }
|
||||
void *xt()
|
||||
{
|
||||
return (void *)(this + 1);
|
||||
}
|
||||
|
||||
cell type()
|
||||
{
|
||||
return (header >> 1) & 0x3;
|
||||
}
|
||||
|
||||
void set_type(code_block_type type)
|
||||
{
|
||||
header = ((header & ~0x7) | (type << 1));
|
||||
}
|
||||
|
||||
bool pic_p()
|
||||
{
|
||||
return type() == code_block_pic;
|
||||
}
|
||||
|
||||
bool optimized_p()
|
||||
{
|
||||
return type() == code_block_optimized;
|
||||
}
|
||||
};
|
||||
|
||||
/* Assembly code makes assumptions about the layout of this struct */
|
||||
|
|
|
@ -8,7 +8,6 @@ template<typename Block, int Granularity> struct mark_bits {
|
|||
cell size;
|
||||
cell bits_size;
|
||||
u64 *marked;
|
||||
u64 *allocated;
|
||||
cell *forwarding;
|
||||
|
||||
void clear_mark_bits()
|
||||
|
@ -16,11 +15,6 @@ template<typename Block, int Granularity> struct mark_bits {
|
|||
memset(marked,0,bits_size * sizeof(u64));
|
||||
}
|
||||
|
||||
void clear_allocated_bits()
|
||||
{
|
||||
memset(allocated,0,bits_size * sizeof(u64));
|
||||
}
|
||||
|
||||
void clear_forwarding()
|
||||
{
|
||||
memset(forwarding,0,bits_size * sizeof(cell));
|
||||
|
@ -31,11 +25,9 @@ template<typename Block, int Granularity> struct mark_bits {
|
|||
size(size_),
|
||||
bits_size(size / Granularity / forwarding_granularity),
|
||||
marked(new u64[bits_size]),
|
||||
allocated(new u64[bits_size]),
|
||||
forwarding(new cell[bits_size])
|
||||
{
|
||||
clear_mark_bits();
|
||||
clear_allocated_bits();
|
||||
clear_forwarding();
|
||||
}
|
||||
|
||||
|
@ -43,8 +35,6 @@ template<typename Block, int Granularity> struct mark_bits {
|
|||
{
|
||||
delete[] marked;
|
||||
marked = NULL;
|
||||
delete[] allocated;
|
||||
allocated = NULL;
|
||||
delete[] forwarding;
|
||||
forwarding = NULL;
|
||||
}
|
||||
|
@ -109,16 +99,6 @@ template<typename Block, int Granularity> struct mark_bits {
|
|||
set_bitmap_range(marked,address);
|
||||
}
|
||||
|
||||
bool is_allocated_p(Block *address)
|
||||
{
|
||||
return bitmap_elt(allocated,address);
|
||||
}
|
||||
|
||||
void set_allocated_p(Block *address)
|
||||
{
|
||||
set_bitmap_range(allocated,address);
|
||||
}
|
||||
|
||||
/* From http://chessprogramming.wikispaces.com/Population+Count */
|
||||
cell popcount(u64 x)
|
||||
{
|
||||
|
|
|
@ -13,7 +13,7 @@ code_block *factor_vm::compile_profiling_stub(cell word_)
|
|||
{
|
||||
gc_root<word> word(word_,this);
|
||||
|
||||
jit jit(WORD_TYPE,word.value(),this);
|
||||
jit jit(code_block_profiling,word.value(),this);
|
||||
jit.emit_with(userenv[JIT_PROFILING],word.value());
|
||||
|
||||
return jit.to_code_block();
|
||||
|
|
|
@ -335,7 +335,7 @@ void factor_vm::compile_all_words()
|
|||
{
|
||||
gc_root<word> word(array_nth(words.untagged(),i),this);
|
||||
|
||||
if(!word->code || !word_optimized_p(word.untagged()))
|
||||
if(!word->code || !word->code->optimized_p())
|
||||
jit_compile_word(word.value(),word->def,false);
|
||||
|
||||
update_word_xt(word.value());
|
||||
|
|
|
@ -6,7 +6,7 @@ struct quotation_jit : public jit {
|
|||
bool compiling, relocate;
|
||||
|
||||
explicit quotation_jit(cell quot, bool compiling_, bool relocate_, factor_vm *vm)
|
||||
: jit(QUOTATION_TYPE,quot,vm),
|
||||
: jit(code_block_unoptimized,quot,vm),
|
||||
elements(owner.as<quotation>().untagged()->array,vm),
|
||||
compiling(compiling_),
|
||||
relocate(relocate_){};
|
||||
|
|
|
@ -27,23 +27,34 @@ struct tagged
|
|||
return tag;
|
||||
}
|
||||
|
||||
bool type_p(cell type_) const { return type() == type_; }
|
||||
bool type_p(cell type_) const
|
||||
{
|
||||
return type() == type_;
|
||||
}
|
||||
|
||||
bool type_p() const
|
||||
{
|
||||
if(Type::type_number == TYPE_COUNT)
|
||||
return true;
|
||||
else
|
||||
return type_p(Type::type_number);
|
||||
}
|
||||
|
||||
Type *untag_check(factor_vm *parent) const {
|
||||
if(Type::type_number != TYPE_COUNT && !type_p(Type::type_number))
|
||||
if(!type_p())
|
||||
parent->type_error(Type::type_number,value_);
|
||||
return untagged();
|
||||
}
|
||||
|
||||
explicit tagged(cell tagged) : value_(tagged) {
|
||||
#ifdef FACTOR_DEBUG
|
||||
untag_check(tls_vm());
|
||||
assert(type_p());
|
||||
#endif
|
||||
}
|
||||
|
||||
explicit tagged(Type *untagged) : value_(factor::tag(untagged)) {
|
||||
#ifdef FACTOR_DEBUG
|
||||
untag_check(tls_vm());
|
||||
assert(type_p());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -498,8 +498,8 @@ struct factor_vm
|
|||
void check_code_address(cell address);
|
||||
void relocate_code_block(code_block *compiled);
|
||||
void fixup_labels(array *labels, code_block *compiled);
|
||||
code_block *allot_code_block(cell size, cell type);
|
||||
code_block *add_code_block(cell type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_);
|
||||
code_block *allot_code_block(cell size, code_block_type type);
|
||||
code_block *add_code_block(code_block_type type, cell code_, cell labels_, cell owner_, cell relocation_, cell literals_);
|
||||
|
||||
//code heap
|
||||
inline void check_code_pointer(cell ptr)
|
||||
|
|
|
@ -82,7 +82,8 @@ void factor_vm::update_word_xt(cell w_)
|
|||
|
||||
void factor_vm::primitive_optimized_p()
|
||||
{
|
||||
drepl(tag_boolean(word_optimized_p(untag_check<word>(dpeek()))));
|
||||
word *w = untag_check<word>(dpeek());
|
||||
drepl(tag_boolean(w->code->optimized_p()));
|
||||
}
|
||||
|
||||
void factor_vm::primitive_wrapper()
|
||||
|
|
|
@ -1,9 +1,4 @@
|
|||
namespace factor
|
||||
{
|
||||
|
||||
inline bool word_optimized_p(word *word)
|
||||
{
|
||||
return word->code->type() == WORD_TYPE;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue