vm: mark sweep gc for tenured space work in progress
parent
f0816d72f1
commit
814f6371d6
|
@ -25,7 +25,7 @@ void factor_vm::collect_aging()
|
||||||
collector.trace_cards(data->tenured,
|
collector.trace_cards(data->tenured,
|
||||||
card_points_to_aging,
|
card_points_to_aging,
|
||||||
simple_unmarker(card_mark_mask));
|
simple_unmarker(card_mark_mask));
|
||||||
collector.cheneys_algorithm();
|
collector.tenure_reachable_objects();
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
/* If collection fails here, do a to_tenured collection. */
|
/* If collection fails here, do a to_tenured collection. */
|
||||||
|
|
|
@ -15,6 +15,10 @@ struct aging_policy {
|
||||||
{
|
{
|
||||||
return !(aging->contains_p(untagged) || tenured->contains_p(untagged));
|
return !(aging->contains_p(untagged) || tenured->contains_p(untagged));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void promoted_object(object *obj) {}
|
||||||
|
|
||||||
|
void visited_object(object *obj) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct aging_collector : copying_collector<aging_space,aging_policy> {
|
struct aging_collector : copying_collector<aging_space,aging_policy> {
|
||||||
|
|
|
@ -1,20 +1,29 @@
|
||||||
namespace factor
|
namespace factor
|
||||||
{
|
{
|
||||||
|
|
||||||
struct aging_space : bump_allocator {
|
struct aging_space : bump_allocator<object> {
|
||||||
object_start_map starts;
|
object_start_map starts;
|
||||||
|
|
||||||
aging_space(cell size, cell start) :
|
aging_space(cell size, cell start) :
|
||||||
bump_allocator(size,start), starts(size,start) {}
|
bump_allocator<object>(size,start), starts(size,start) {}
|
||||||
|
|
||||||
object *allot(cell size)
|
object *allot(cell size)
|
||||||
{
|
{
|
||||||
if(here + size > end) return NULL;
|
if(here + size > end) return NULL;
|
||||||
|
|
||||||
object *obj = bump_allocator::allot(size);
|
object *obj = bump_allocator<object>::allot(size);
|
||||||
starts.record_object_start_offset(obj);
|
starts.record_object_start_offset(obj);
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cell next_object_after(cell scan)
|
||||||
|
{
|
||||||
|
cell size = ((object *)scan)->size();
|
||||||
|
if(scan + size < here)
|
||||||
|
return scan + size;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
namespace factor
|
namespace factor
|
||||||
{
|
{
|
||||||
|
|
||||||
struct bump_allocator {
|
template<typename Block> struct bump_allocator {
|
||||||
/* offset of 'here' and 'end' is hardcoded in compiler backends */
|
/* offset of 'here' and 'end' is hardcoded in compiler backends */
|
||||||
cell here;
|
cell here;
|
||||||
cell start;
|
cell start;
|
||||||
|
@ -9,27 +9,18 @@ struct bump_allocator {
|
||||||
cell size;
|
cell size;
|
||||||
|
|
||||||
bump_allocator(cell size_, cell start_) :
|
bump_allocator(cell size_, cell start_) :
|
||||||
here(0), start(start_), end(start_ + size_), size(size_) {}
|
here(start_), start(start_), end(start_ + size_), size(size_) {}
|
||||||
|
|
||||||
inline bool contains_p(object *pointer)
|
inline bool contains_p(Block *block)
|
||||||
{
|
{
|
||||||
return ((cell)pointer - start) < size;
|
return ((cell)block - start) < size;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline object *allot(cell size)
|
inline Block *allot(cell size)
|
||||||
{
|
{
|
||||||
cell h = here;
|
cell h = here;
|
||||||
here = h + align(size,data_alignment);
|
here = h + align(size,data_alignment);
|
||||||
return (object *)h;
|
return (Block *)h;
|
||||||
}
|
|
||||||
|
|
||||||
cell next_allocated_block_after(cell scan)
|
|
||||||
{
|
|
||||||
cell size = ((object *)scan)->size();
|
|
||||||
if(scan + size < here)
|
|
||||||
return scan + size;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ code_heap::code_heap(cell size)
|
||||||
if(size > (1L << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size);
|
if(size > (1L << (sizeof(cell) * 8 - 6))) fatal_error("Heap too large",size);
|
||||||
seg = new segment(align_page(size),true);
|
seg = new segment(align_page(size),true);
|
||||||
if(!seg) fatal_error("Out of memory in heap allocator",size);
|
if(!seg) fatal_error("Out of memory in heap allocator",size);
|
||||||
allocator = new free_list_allocator<heap_block>(seg->start,size);
|
allocator = new free_list_allocator<heap_block>(size,seg->start);
|
||||||
}
|
}
|
||||||
|
|
||||||
code_heap::~code_heap()
|
code_heap::~code_heap()
|
||||||
|
|
143
vm/collector.hpp
143
vm/collector.hpp
|
@ -40,7 +40,10 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
|
|
||||||
object *untagged = parent->untag<object>(pointer);
|
object *untagged = parent->untag<object>(pointer);
|
||||||
if(!policy.should_copy_p(untagged))
|
if(!policy.should_copy_p(untagged))
|
||||||
|
{
|
||||||
|
policy.visited_object(untagged);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
object *forwarding = resolve_forwarding(untagged);
|
object *forwarding = resolve_forwarding(untagged);
|
||||||
|
|
||||||
|
@ -49,7 +52,10 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
else if(policy.should_copy_p(forwarding))
|
else if(policy.should_copy_p(forwarding))
|
||||||
untagged = promote_object(forwarding);
|
untagged = promote_object(forwarding);
|
||||||
else
|
else
|
||||||
|
{
|
||||||
untagged = forwarding;
|
untagged = forwarding;
|
||||||
|
policy.visited_object(untagged);
|
||||||
|
}
|
||||||
|
|
||||||
*handle = RETAG(untagged,TAG(pointer));
|
*handle = RETAG(untagged,TAG(pointer));
|
||||||
}
|
}
|
||||||
|
@ -79,6 +85,8 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
stats->object_count++;
|
stats->object_count++;
|
||||||
stats->bytes_copied += size;
|
stats->bytes_copied += size;
|
||||||
|
|
||||||
|
policy.promoted_object(newpointer);
|
||||||
|
|
||||||
return newpointer;
|
return newpointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -145,6 +153,141 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
ctx = ctx->next;
|
ctx = ctx->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline cell first_card_in_deck(cell deck)
|
||||||
|
{
|
||||||
|
return deck << (deck_bits - card_bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline cell last_card_in_deck(cell deck)
|
||||||
|
{
|
||||||
|
return first_card_in_deck(deck + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline cell card_deck_for_address(cell a)
|
||||||
|
{
|
||||||
|
return addr_to_deck(a - this->data->start);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline cell card_start_address(cell card)
|
||||||
|
{
|
||||||
|
return (card << card_bits) + this->data->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline cell card_end_address(cell card)
|
||||||
|
{
|
||||||
|
return ((card + 1) << card_bits) + this->data->start;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trace_partial_objects(cell start, cell end, cell card_start, cell card_end)
|
||||||
|
{
|
||||||
|
if(card_start < end)
|
||||||
|
{
|
||||||
|
start += sizeof(cell);
|
||||||
|
|
||||||
|
if(start < card_start) start = card_start;
|
||||||
|
if(end > card_end) end = card_end;
|
||||||
|
|
||||||
|
cell *slot_ptr = (cell *)start;
|
||||||
|
cell *end_ptr = (cell *)end;
|
||||||
|
|
||||||
|
if(slot_ptr != end_ptr)
|
||||||
|
{
|
||||||
|
for(; slot_ptr < end_ptr; slot_ptr++)
|
||||||
|
this->trace_handle(slot_ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename SourceGeneration, typename Unmarker>
|
||||||
|
void trace_cards(SourceGeneration *gen, card mask, Unmarker unmarker)
|
||||||
|
{
|
||||||
|
u64 start_time = current_micros();
|
||||||
|
|
||||||
|
card_deck *decks = this->data->decks;
|
||||||
|
card_deck *cards = this->data->cards;
|
||||||
|
|
||||||
|
cell gen_start_card = addr_to_card(gen->start - this->data->start);
|
||||||
|
|
||||||
|
cell first_deck = card_deck_for_address(gen->start);
|
||||||
|
cell last_deck = card_deck_for_address(gen->end);
|
||||||
|
|
||||||
|
cell start = 0, binary_start = 0, end = 0;
|
||||||
|
|
||||||
|
for(cell deck_index = first_deck; deck_index < last_deck; deck_index++)
|
||||||
|
{
|
||||||
|
if(decks[deck_index] & mask)
|
||||||
|
{
|
||||||
|
this->parent->gc_stats.decks_scanned++;
|
||||||
|
|
||||||
|
cell first_card = first_card_in_deck(deck_index);
|
||||||
|
cell last_card = last_card_in_deck(deck_index);
|
||||||
|
|
||||||
|
for(cell card_index = first_card; card_index < last_card; card_index++)
|
||||||
|
{
|
||||||
|
if(cards[card_index] & mask)
|
||||||
|
{
|
||||||
|
this->parent->gc_stats.cards_scanned++;
|
||||||
|
|
||||||
|
if(end < card_start_address(card_index))
|
||||||
|
{
|
||||||
|
start = gen->starts.find_object_containing_card(card_index - gen_start_card);
|
||||||
|
binary_start = start + this->parent->binary_payload_start((object *)start);
|
||||||
|
end = start + ((object *)start)->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef FACTOR_DEBUG
|
||||||
|
assert(addr_to_card(start - this->data->start) <= card_index);
|
||||||
|
assert(start < card_end_address(card_index));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
scan_next_object: {
|
||||||
|
trace_partial_objects(
|
||||||
|
start,
|
||||||
|
binary_start,
|
||||||
|
card_start_address(card_index),
|
||||||
|
card_end_address(card_index));
|
||||||
|
if(end < card_end_address(card_index))
|
||||||
|
{
|
||||||
|
start = gen->next_object_after(start);
|
||||||
|
if(start)
|
||||||
|
{
|
||||||
|
binary_start = start + this->parent->binary_payload_start((object *)start);
|
||||||
|
end = start + ((object *)start)->size();
|
||||||
|
goto scan_next_object;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unmarker(&cards[card_index]);
|
||||||
|
|
||||||
|
if(!start) goto end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unmarker(&decks[deck_index]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
end: this->parent->gc_stats.card_scan_time += (current_micros() - start_time);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Trace all literals referenced from a code block. Only for aging and nursery collections */
|
||||||
|
void trace_literal_references(code_block *compiled)
|
||||||
|
{
|
||||||
|
this->trace_handle(&compiled->owner);
|
||||||
|
this->trace_handle(&compiled->literals);
|
||||||
|
this->trace_handle(&compiled->relocation);
|
||||||
|
this->parent->gc_stats.code_blocks_scanned++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trace_code_heap_roots(std::set<code_block *> *remembered_set)
|
||||||
|
{
|
||||||
|
std::set<code_block *>::const_iterator iter = remembered_set->begin();
|
||||||
|
std::set<code_block *>::const_iterator end = remembered_set->end();
|
||||||
|
|
||||||
|
for(; iter != end; iter++) trace_literal_references(*iter);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,147 +18,12 @@ struct copying_collector : collector<TargetGeneration,Policy> {
|
||||||
explicit copying_collector(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) :
|
explicit copying_collector(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) :
|
||||||
collector<TargetGeneration,Policy>(parent_,stats_,target_,policy_), scan(target_->here) {}
|
collector<TargetGeneration,Policy>(parent_,stats_,target_,policy_), scan(target_->here) {}
|
||||||
|
|
||||||
inline cell first_card_in_deck(cell deck)
|
|
||||||
{
|
|
||||||
return deck << (deck_bits - card_bits);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline cell last_card_in_deck(cell deck)
|
|
||||||
{
|
|
||||||
return first_card_in_deck(deck + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline cell card_deck_for_address(cell a)
|
|
||||||
{
|
|
||||||
return addr_to_deck(a - this->data->start);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline cell card_start_address(cell card)
|
|
||||||
{
|
|
||||||
return (card << card_bits) + this->data->start;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline cell card_end_address(cell card)
|
|
||||||
{
|
|
||||||
return ((card + 1) << card_bits) + this->data->start;
|
|
||||||
}
|
|
||||||
|
|
||||||
void trace_partial_objects(cell start, cell end, cell card_start, cell card_end)
|
|
||||||
{
|
|
||||||
if(card_start < end)
|
|
||||||
{
|
|
||||||
start += sizeof(cell);
|
|
||||||
|
|
||||||
if(start < card_start) start = card_start;
|
|
||||||
if(end > card_end) end = card_end;
|
|
||||||
|
|
||||||
cell *slot_ptr = (cell *)start;
|
|
||||||
cell *end_ptr = (cell *)end;
|
|
||||||
|
|
||||||
if(slot_ptr != end_ptr)
|
|
||||||
{
|
|
||||||
for(; slot_ptr < end_ptr; slot_ptr++)
|
|
||||||
this->trace_handle(slot_ptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename SourceGeneration, typename Unmarker>
|
|
||||||
void trace_cards(SourceGeneration *gen, card mask, Unmarker unmarker)
|
|
||||||
{
|
|
||||||
u64 start_time = current_micros();
|
|
||||||
|
|
||||||
card_deck *decks = this->data->decks;
|
|
||||||
card_deck *cards = this->data->cards;
|
|
||||||
|
|
||||||
cell gen_start_card = addr_to_card(gen->start - this->data->start);
|
|
||||||
|
|
||||||
cell first_deck = card_deck_for_address(gen->start);
|
|
||||||
cell last_deck = card_deck_for_address(gen->end);
|
|
||||||
|
|
||||||
cell start = 0, binary_start = 0, end = 0;
|
|
||||||
|
|
||||||
for(cell deck_index = first_deck; deck_index < last_deck; deck_index++)
|
|
||||||
{
|
|
||||||
if(decks[deck_index] & mask)
|
|
||||||
{
|
|
||||||
this->parent->gc_stats.decks_scanned++;
|
|
||||||
|
|
||||||
cell first_card = first_card_in_deck(deck_index);
|
|
||||||
cell last_card = last_card_in_deck(deck_index);
|
|
||||||
|
|
||||||
for(cell card_index = first_card; card_index < last_card; card_index++)
|
|
||||||
{
|
|
||||||
if(cards[card_index] & mask)
|
|
||||||
{
|
|
||||||
this->parent->gc_stats.cards_scanned++;
|
|
||||||
|
|
||||||
if(end < card_start_address(card_index))
|
|
||||||
{
|
|
||||||
start = gen->starts.find_object_containing_card(card_index - gen_start_card);
|
|
||||||
binary_start = start + this->parent->binary_payload_start((object *)start);
|
|
||||||
end = start + ((object *)start)->size();
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef FACTOR_DEBUG
|
|
||||||
assert(addr_to_card(start - this->data->start) <= card_index);
|
|
||||||
assert(start < card_end_address(card_index));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
scan_next_object: {
|
|
||||||
trace_partial_objects(
|
|
||||||
start,
|
|
||||||
binary_start,
|
|
||||||
card_start_address(card_index),
|
|
||||||
card_end_address(card_index));
|
|
||||||
if(end < card_end_address(card_index))
|
|
||||||
{
|
|
||||||
start = gen->next_allocated_block_after(start);
|
|
||||||
if(start)
|
|
||||||
{
|
|
||||||
binary_start = start + this->parent->binary_payload_start((object *)start);
|
|
||||||
end = start + ((object *)start)->size();
|
|
||||||
goto scan_next_object;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unmarker(&cards[card_index]);
|
|
||||||
|
|
||||||
if(!start) goto end;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unmarker(&decks[deck_index]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
end: this->parent->gc_stats.card_scan_time += (current_micros() - start_time);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Trace all literals referenced from a code block. Only for aging and nursery collections */
|
|
||||||
void trace_literal_references(code_block *compiled)
|
|
||||||
{
|
|
||||||
this->trace_handle(&compiled->owner);
|
|
||||||
this->trace_handle(&compiled->literals);
|
|
||||||
this->trace_handle(&compiled->relocation);
|
|
||||||
this->parent->gc_stats.code_blocks_scanned++;
|
|
||||||
}
|
|
||||||
|
|
||||||
void trace_code_heap_roots(std::set<code_block *> *remembered_set)
|
|
||||||
{
|
|
||||||
std::set<code_block *>::const_iterator iter = remembered_set->begin();
|
|
||||||
std::set<code_block *>::const_iterator end = remembered_set->end();
|
|
||||||
|
|
||||||
for(; iter != end; iter++) trace_literal_references(*iter);
|
|
||||||
}
|
|
||||||
|
|
||||||
void cheneys_algorithm()
|
void cheneys_algorithm()
|
||||||
{
|
{
|
||||||
while(scan && scan < this->target->here)
|
while(scan && scan < this->target->here)
|
||||||
{
|
{
|
||||||
this->trace_slots((object *)scan);
|
this->trace_slots((object *)scan);
|
||||||
scan = this->target->next_allocated_block_after(scan);
|
scan = this->target->next_object_after(scan);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,7 +19,7 @@ data_heap::data_heap(cell young_size_, cell aging_size_, cell tenured_size_)
|
||||||
aging_size = aging_size_;
|
aging_size = aging_size_;
|
||||||
tenured_size = tenured_size_;
|
tenured_size = tenured_size_;
|
||||||
|
|
||||||
cell total_size = young_size + 2 * aging_size + 2 * tenured_size;
|
cell total_size = young_size + 2 * aging_size + tenured_size;
|
||||||
|
|
||||||
total_size += deck_size;
|
total_size += deck_size;
|
||||||
|
|
||||||
|
@ -29,20 +29,21 @@ data_heap::data_heap(cell young_size_, cell aging_size_, cell tenured_size_)
|
||||||
|
|
||||||
cards = new card[cards_size];
|
cards = new card[cards_size];
|
||||||
cards_end = cards + cards_size;
|
cards_end = cards + cards_size;
|
||||||
|
memset(cards,0,cards_size);
|
||||||
|
|
||||||
cell decks_size = addr_to_deck(total_size);
|
cell decks_size = addr_to_deck(total_size);
|
||||||
decks = new card_deck[decks_size];
|
decks = new card_deck[decks_size];
|
||||||
decks_end = decks + decks_size;
|
decks_end = decks + decks_size;
|
||||||
|
memset(decks,0,decks_size);
|
||||||
|
|
||||||
start = align(seg->start,deck_size);
|
start = align(seg->start,deck_size);
|
||||||
|
|
||||||
tenured = new tenured_space(tenured_size,start);
|
tenured = new tenured_space(tenured_size,start);
|
||||||
tenured_semispace = new tenured_space(tenured_size,tenured->end);
|
|
||||||
|
|
||||||
aging = new aging_space(aging_size,tenured_semispace->end);
|
aging = new aging_space(aging_size,tenured->end);
|
||||||
aging_semispace = new aging_space(aging_size,aging->end);
|
aging_semispace = new aging_space(aging_size,aging->end);
|
||||||
|
|
||||||
nursery = new bump_allocator(young_size,aging_semispace->end);
|
nursery = new nursery_space(young_size,aging_semispace->end);
|
||||||
|
|
||||||
assert(seg->end - nursery->end <= deck_size);
|
assert(seg->end - nursery->end <= deck_size);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +55,6 @@ data_heap::~data_heap()
|
||||||
delete aging;
|
delete aging;
|
||||||
delete aging_semispace;
|
delete aging_semispace;
|
||||||
delete tenured;
|
delete tenured;
|
||||||
delete tenured_semispace;
|
|
||||||
delete[] cards;
|
delete[] cards;
|
||||||
delete[] decks;
|
delete[] decks;
|
||||||
}
|
}
|
||||||
|
@ -71,8 +71,6 @@ void factor_vm::set_data_heap(data_heap *data_)
|
||||||
nursery = *data->nursery;
|
nursery = *data->nursery;
|
||||||
nursery.here = nursery.start;
|
nursery.here = nursery.start;
|
||||||
init_card_decks();
|
init_card_decks();
|
||||||
data->reset_generation(data->aging);
|
|
||||||
data->reset_generation(data->tenured);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_size)
|
void factor_vm::init_data_heap(cell young_size, cell aging_size, cell tenured_size)
|
||||||
|
@ -185,8 +183,11 @@ void factor_vm::primitive_data_room()
|
||||||
a.add(tag_fixnum((data->aging->end - data->aging->here) >> 10));
|
a.add(tag_fixnum((data->aging->end - data->aging->here) >> 10));
|
||||||
a.add(tag_fixnum((data->aging->size) >> 10));
|
a.add(tag_fixnum((data->aging->size) >> 10));
|
||||||
|
|
||||||
a.add(tag_fixnum((data->tenured->end - data->tenured->here) >> 10));
|
//XXX
|
||||||
a.add(tag_fixnum((data->tenured->size) >> 10));
|
cell used, total_free, max_free;
|
||||||
|
data->tenured->usage(&used,&total_free,&max_free);
|
||||||
|
a.add(tag_fixnum(total_free >> 10));
|
||||||
|
a.add(tag_fixnum(used >> 10));
|
||||||
|
|
||||||
a.trim();
|
a.trim();
|
||||||
dpush(a.elements.value());
|
dpush(a.elements.value());
|
||||||
|
@ -195,7 +196,7 @@ void factor_vm::primitive_data_room()
|
||||||
/* Disables GC and activates next-object ( -- obj ) primitive */
|
/* Disables GC and activates next-object ( -- obj ) primitive */
|
||||||
void factor_vm::begin_scan()
|
void factor_vm::begin_scan()
|
||||||
{
|
{
|
||||||
heap_scan_ptr = data->tenured->start;
|
heap_scan_ptr = data->tenured->first_object();
|
||||||
gc_off = true;
|
gc_off = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,12 +215,14 @@ cell factor_vm::next_object()
|
||||||
if(!gc_off)
|
if(!gc_off)
|
||||||
general_error(ERROR_HEAP_SCAN,false_object,false_object,NULL);
|
general_error(ERROR_HEAP_SCAN,false_object,false_object,NULL);
|
||||||
|
|
||||||
if(heap_scan_ptr >= data->tenured->here)
|
if(heap_scan_ptr)
|
||||||
|
{
|
||||||
|
cell current = heap_scan_ptr;
|
||||||
|
heap_scan_ptr = data->tenured->next_object_after(heap_scan_ptr);
|
||||||
|
return tag_dynamic((object *)current);
|
||||||
|
}
|
||||||
|
else
|
||||||
return false_object;
|
return false_object;
|
||||||
|
|
||||||
object *obj = (object *)heap_scan_ptr;
|
|
||||||
heap_scan_ptr += obj->size();
|
|
||||||
return tag_dynamic(obj);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push object at heap scan cursor and advance; pushes f when done */
|
/* Push object at heap scan cursor and advance; pushes f when done */
|
||||||
|
|
|
@ -10,11 +10,10 @@ struct data_heap {
|
||||||
|
|
||||||
segment *seg;
|
segment *seg;
|
||||||
|
|
||||||
bump_allocator *nursery;
|
nursery_space *nursery;
|
||||||
aging_space *aging;
|
aging_space *aging;
|
||||||
aging_space *aging_semispace;
|
aging_space *aging_semispace;
|
||||||
tenured_space *tenured;
|
tenured_space *tenured;
|
||||||
tenured_space *tenured_semispace;
|
|
||||||
|
|
||||||
card *cards;
|
card *cards;
|
||||||
card *cards_end;
|
card *cards_end;
|
||||||
|
@ -49,7 +48,6 @@ their allocation pointers and cards reset. */
|
||||||
template<typename Generation> void data_heap::reset_generation(Generation *gen)
|
template<typename Generation> void data_heap::reset_generation(Generation *gen)
|
||||||
{
|
{
|
||||||
gen->here = gen->start;
|
gen->here = gen->start;
|
||||||
|
|
||||||
clear_cards(gen);
|
clear_cards(gen);
|
||||||
clear_decks(gen);
|
clear_decks(gen);
|
||||||
gen->starts.clear_object_start_offsets();
|
gen->starts.clear_object_start_offsets();
|
||||||
|
|
16
vm/debug.cpp
16
vm/debug.cpp
|
@ -209,19 +209,21 @@ void factor_vm::dump_memory(cell from, cell to)
|
||||||
dump_cell(from);
|
dump_cell(from);
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::dump_zone(const char *name, bump_allocator *z)
|
template<typename Generation>
|
||||||
|
void factor_vm::dump_generation(const char *name, Generation *gen)
|
||||||
{
|
{
|
||||||
print_string(name); print_string(": ");
|
print_string(name); print_string(": ");
|
||||||
print_string("Start="); print_cell(z->start);
|
print_string("Start="); print_cell(gen->start);
|
||||||
print_string(", size="); print_cell(z->size);
|
print_string(", size="); print_cell(gen->size);
|
||||||
print_string(", here="); print_cell(z->here - z->start); nl();
|
print_string(", end="); print_cell(gen->end);
|
||||||
|
nl();
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::dump_generations()
|
void factor_vm::dump_generations()
|
||||||
{
|
{
|
||||||
dump_zone("Nursery",&nursery);
|
dump_generation("Nursery",&nursery);
|
||||||
dump_zone("Aging",data->aging);
|
dump_generation("Aging",data->aging);
|
||||||
dump_zone("Tenured",data->tenured);
|
dump_generation("Tenured",data->tenured);
|
||||||
|
|
||||||
print_string("Cards: base=");
|
print_string("Cards: base=");
|
||||||
print_cell((cell)data->cards);
|
print_cell((cell)data->cards);
|
||||||
|
|
|
@ -9,29 +9,17 @@ struct free_list {
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Block> struct free_list_allocator {
|
template<typename Block> struct free_list_allocator {
|
||||||
cell start;
|
|
||||||
cell size;
|
cell size;
|
||||||
|
cell start;
|
||||||
cell end;
|
cell end;
|
||||||
free_list free_blocks;
|
free_list free_blocks;
|
||||||
mark_bits<Block> state;
|
mark_bits<Block> state;
|
||||||
|
|
||||||
explicit free_list_allocator(cell start, cell size);
|
explicit free_list_allocator(cell size, cell start);
|
||||||
|
bool contains_p(Block *block);
|
||||||
inline Block *first_block()
|
Block *first_block();
|
||||||
{
|
Block *last_block();
|
||||||
return (Block *)start;
|
Block *next_block_after(Block *block);
|
||||||
}
|
|
||||||
|
|
||||||
inline Block *last_block()
|
|
||||||
{
|
|
||||||
return (Block *)end;
|
|
||||||
}
|
|
||||||
|
|
||||||
Block *next_block_after(heap_block *block)
|
|
||||||
{
|
|
||||||
return (Block *)((cell)block + block->size());
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_free_list();
|
void clear_free_list();
|
||||||
void add_to_free_list(free_heap_block *block);
|
void add_to_free_list(free_heap_block *block);
|
||||||
void build_free_list(cell size);
|
void build_free_list(cell size);
|
||||||
|
@ -42,35 +30,42 @@ template<typename Block> struct free_list_allocator {
|
||||||
void free(Block *block);
|
void free(Block *block);
|
||||||
void usage(cell *used, cell *total_free, cell *max_free);
|
void usage(cell *used, cell *total_free, cell *max_free);
|
||||||
cell occupied();
|
cell occupied();
|
||||||
|
void sweep();
|
||||||
template<typename Iterator> void sweep(Iterator &iter);
|
template<typename Iterator> void sweep(Iterator &iter);
|
||||||
template<typename Iterator> void compact(Iterator &iter);
|
template<typename Iterator> void compact(Iterator &iter);
|
||||||
|
template<typename Iterator> void iterate(Iterator &iter);
|
||||||
template<typename Iterator> void iterate(Iterator &iter)
|
|
||||||
{
|
|
||||||
Block *scan = first_block();
|
|
||||||
Block *end = last_block();
|
|
||||||
|
|
||||||
while(scan != end)
|
|
||||||
{
|
|
||||||
cell size = scan->size();
|
|
||||||
Block *next = (Block *)((cell)scan + size);
|
|
||||||
if(!scan->free_p()) iter(scan,size);
|
|
||||||
scan = next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<typename Block>
|
||||||
|
free_list_allocator<Block>::free_list_allocator(cell size_, cell start_) :
|
||||||
|
size(size_), start(start_), end(start_ + size_), state(mark_bits<Block>(size_,start_))
|
||||||
|
{
|
||||||
|
clear_free_list();
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Block> void free_list_allocator<Block>::clear_free_list()
|
template<typename Block> void free_list_allocator<Block>::clear_free_list()
|
||||||
{
|
{
|
||||||
memset(&free_blocks,0,sizeof(free_list));
|
memset(&free_blocks,0,sizeof(free_list));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Block>
|
template<typename Block> bool free_list_allocator<Block>::contains_p(Block *block)
|
||||||
free_list_allocator<Block>::free_list_allocator(cell start_, cell size_) :
|
|
||||||
start(start_), size(size_), end(start_ + size_), state(mark_bits<Block>(start_,size_))
|
|
||||||
{
|
{
|
||||||
clear_free_list();
|
return ((cell)block - start) < size;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Block> Block *free_list_allocator<Block>::first_block()
|
||||||
|
{
|
||||||
|
return (Block *)start;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Block> Block *free_list_allocator<Block>::last_block()
|
||||||
|
{
|
||||||
|
return (Block *)end;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Block> Block *free_list_allocator<Block>::next_block_after(Block *block)
|
||||||
|
{
|
||||||
|
return (Block *)((cell)block + block->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Block> void free_list_allocator<Block>::add_to_free_list(free_heap_block *block)
|
template<typename Block> void free_list_allocator<Block>::add_to_free_list(free_heap_block *block)
|
||||||
|
@ -234,8 +229,56 @@ template<typename Block> cell free_list_allocator<Block>::occupied()
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* After code GC, all live code blocks are marked, so any
|
template<typename Block>
|
||||||
which are not marked can be reclaimed. */
|
void free_list_allocator<Block>::sweep()
|
||||||
|
{
|
||||||
|
this->clear_free_list();
|
||||||
|
|
||||||
|
Block *prev = NULL;
|
||||||
|
Block *scan = this->first_block();
|
||||||
|
Block *end = this->last_block();
|
||||||
|
|
||||||
|
while(scan != end)
|
||||||
|
{
|
||||||
|
cell size = scan->size();
|
||||||
|
|
||||||
|
if(scan->free_p())
|
||||||
|
{
|
||||||
|
if(prev && prev->free_p())
|
||||||
|
{
|
||||||
|
free_heap_block *free_prev = (free_heap_block *)prev;
|
||||||
|
free_prev->set_size(free_prev->size() + size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
prev = scan;
|
||||||
|
}
|
||||||
|
else if(this->state.marked_p(scan))
|
||||||
|
{
|
||||||
|
if(prev && prev->free_p())
|
||||||
|
this->add_to_free_list((free_heap_block *)prev);
|
||||||
|
prev = scan;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if(prev && prev->free_p())
|
||||||
|
{
|
||||||
|
free_heap_block *free_prev = (free_heap_block *)prev;
|
||||||
|
free_prev->set_size(free_prev->size() + size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
((free_heap_block *)scan)->set_free();
|
||||||
|
prev = scan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
scan = (Block *)((cell)scan + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(prev && prev->free_p())
|
||||||
|
this->add_to_free_list((free_heap_block *)prev);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Block>
|
template<typename Block>
|
||||||
template<typename Iterator>
|
template<typename Iterator>
|
||||||
void free_list_allocator<Block>::sweep(Iterator &iter)
|
void free_list_allocator<Block>::sweep(Iterator &iter)
|
||||||
|
@ -302,4 +345,20 @@ void free_list_allocator<Block>::compact(Iterator &iter)
|
||||||
this->build_free_list((cell)compactor.address - this->start);
|
this->build_free_list((cell)compactor.address - this->start);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Block>
|
||||||
|
template<typename Iterator>
|
||||||
|
void free_list_allocator<Block>::iterate(Iterator &iter)
|
||||||
|
{
|
||||||
|
Block *scan = first_block();
|
||||||
|
Block *end = last_block();
|
||||||
|
|
||||||
|
while(scan != end)
|
||||||
|
{
|
||||||
|
cell size = scan->size();
|
||||||
|
Block *next = (Block *)((cell)scan + size);
|
||||||
|
if(!scan->free_p()) iter(scan,size);
|
||||||
|
scan = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ namespace factor
|
||||||
{
|
{
|
||||||
|
|
||||||
full_collector::full_collector(factor_vm *parent_) :
|
full_collector::full_collector(factor_vm *parent_) :
|
||||||
copying_collector<tenured_space,full_policy>(
|
collector<tenured_space,full_policy>(
|
||||||
parent_,
|
parent_,
|
||||||
&parent_->gc_stats.full_stats,
|
&parent_->gc_stats.full_stats,
|
||||||
parent_->data->tenured,
|
parent_->data->tenured,
|
||||||
|
@ -89,18 +89,22 @@ void full_collector::trace_literal_references(code_block *compiled)
|
||||||
collections */
|
collections */
|
||||||
void full_collector::mark_code_block(code_block *compiled)
|
void full_collector::mark_code_block(code_block *compiled)
|
||||||
{
|
{
|
||||||
this->code->set_marked_p(compiled);
|
if(!this->code->marked_p(compiled))
|
||||||
trace_literal_references(compiled);
|
{
|
||||||
|
this->code->set_marked_p(compiled);
|
||||||
|
trace_literal_references(compiled);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void full_collector::cheneys_algorithm()
|
void full_collector::mark_reachable_objects()
|
||||||
{
|
{
|
||||||
while(scan && scan < target->here)
|
std::vector<object *> *mark_stack = &this->target->mark_stack;
|
||||||
|
while(!mark_stack->empty())
|
||||||
{
|
{
|
||||||
object *obj = (object *)scan;
|
object *obj = mark_stack->back();
|
||||||
|
mark_stack->pop_back();
|
||||||
this->trace_slots(obj);
|
this->trace_slots(obj);
|
||||||
this->mark_object_code_block(obj);
|
this->mark_object_code_block(obj);
|
||||||
scan = target->next_allocated_block_after(scan);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +113,7 @@ void factor_vm::collect_full_impl(bool trace_contexts_p)
|
||||||
full_collector collector(this);
|
full_collector collector(this);
|
||||||
|
|
||||||
code->clear_mark_bits();
|
code->clear_mark_bits();
|
||||||
|
data->tenured->clear_mark_bits();
|
||||||
|
|
||||||
collector.trace_roots();
|
collector.trace_roots();
|
||||||
if(trace_contexts_p)
|
if(trace_contexts_p)
|
||||||
|
@ -118,8 +123,9 @@ void factor_vm::collect_full_impl(bool trace_contexts_p)
|
||||||
collector.trace_callbacks();
|
collector.trace_callbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
collector.cheneys_algorithm();
|
collector.mark_reachable_objects();
|
||||||
|
|
||||||
|
data->tenured->sweep();
|
||||||
data->reset_generation(data->aging);
|
data->reset_generation(data->aging);
|
||||||
nursery.here = nursery.start;
|
nursery.here = nursery.start;
|
||||||
}
|
}
|
||||||
|
@ -144,9 +150,6 @@ void factor_vm::collect_growing_heap(cell requested_bytes,
|
||||||
|
|
||||||
void factor_vm::collect_full(bool trace_contexts_p, bool compact_code_heap_p)
|
void factor_vm::collect_full(bool trace_contexts_p, bool compact_code_heap_p)
|
||||||
{
|
{
|
||||||
/* Copy all live objects to the tenured semispace. */
|
|
||||||
std::swap(data->tenured,data->tenured_semispace);
|
|
||||||
data->reset_generation(data->tenured);
|
|
||||||
collect_full_impl(trace_contexts_p);
|
collect_full_impl(trace_contexts_p);
|
||||||
|
|
||||||
if(compact_code_heap_p)
|
if(compact_code_heap_p)
|
||||||
|
|
|
@ -11,9 +11,20 @@ struct full_policy {
|
||||||
{
|
{
|
||||||
return !tenured->contains_p(untagged);
|
return !tenured->contains_p(untagged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void promoted_object(object *obj)
|
||||||
|
{
|
||||||
|
tenured->mark_and_push(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visited_object(object *obj)
|
||||||
|
{
|
||||||
|
if(!tenured->marked_p(obj))
|
||||||
|
tenured->mark_and_push(obj);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct full_collector : copying_collector<tenured_space,full_policy> {
|
struct full_collector : collector<tenured_space,full_policy> {
|
||||||
bool trace_contexts_p;
|
bool trace_contexts_p;
|
||||||
|
|
||||||
full_collector(factor_vm *parent_);
|
full_collector(factor_vm *parent_);
|
||||||
|
@ -22,7 +33,7 @@ struct full_collector : copying_collector<tenured_space,full_policy> {
|
||||||
void trace_callbacks();
|
void trace_callbacks();
|
||||||
void trace_literal_references(code_block *compiled);
|
void trace_literal_references(code_block *compiled);
|
||||||
void mark_code_block(code_block *compiled);
|
void mark_code_block(code_block *compiled);
|
||||||
void cheneys_algorithm();
|
void mark_reachable_objects();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,11 +235,13 @@ object *factor_vm::allot_object(header header, cell size)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* If tenured space does not have enough room, collect */
|
/* If tenured space does not have enough room, collect */
|
||||||
if(data->tenured->here + size > data->tenured->end)
|
//XXX
|
||||||
|
//if(data->tenured->here + size > data->tenured->end)
|
||||||
primitive_full_gc();
|
primitive_full_gc();
|
||||||
|
|
||||||
/* If it still won't fit, grow the heap */
|
/* If it still won't fit, grow the heap */
|
||||||
if(data->tenured->here + size > data->tenured->end)
|
//XXX
|
||||||
|
//if(data->tenured->here + size > data->tenured->end)
|
||||||
{
|
{
|
||||||
gc(collect_growing_heap_op,
|
gc(collect_growing_heap_op,
|
||||||
size, /* requested size */
|
size, /* requested size */
|
||||||
|
|
|
@ -39,7 +39,7 @@ void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p)
|
||||||
fatal_error("load_data_heap failed",0);
|
fatal_error("load_data_heap failed",0);
|
||||||
}
|
}
|
||||||
|
|
||||||
data->tenured->here = data->tenured->start + h->data_size;
|
data->tenured->build_free_list(h->data_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p)
|
void factor_vm::load_code_heap(FILE *file, image_header *h, vm_parameters *p)
|
||||||
|
@ -203,7 +203,7 @@ void factor_vm::relocate_data(cell data_relocation_base, cell code_relocation_ba
|
||||||
{
|
{
|
||||||
relocate_object((object *)obj,data_relocation_base,code_relocation_base);
|
relocate_object((object *)obj,data_relocation_base,code_relocation_base);
|
||||||
data->tenured->starts.record_object_start_offset((object *)obj);
|
data->tenured->starts.record_object_start_offset((object *)obj);
|
||||||
obj = data->tenured->next_allocated_block_after(obj);
|
obj = data->tenured->next_object_after(obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ bool factor_vm::save_image(const vm_char *filename)
|
||||||
h.magic = image_magic;
|
h.magic = image_magic;
|
||||||
h.version = image_version;
|
h.version = image_version;
|
||||||
h.data_relocation_base = data->tenured->start;
|
h.data_relocation_base = data->tenured->start;
|
||||||
h.data_size = data->tenured->here - data->tenured->start;
|
h.data_size = data->tenured->occupied();
|
||||||
h.code_relocation_base = code->seg->start;
|
h.code_relocation_base = code->seg->start;
|
||||||
h.code_size = code->allocator->occupied();
|
h.code_size = code->allocator->occupied();
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ namespace factor
|
||||||
#include "free_list_allocator.hpp"
|
#include "free_list_allocator.hpp"
|
||||||
#include "write_barrier.hpp"
|
#include "write_barrier.hpp"
|
||||||
#include "object_start_map.hpp"
|
#include "object_start_map.hpp"
|
||||||
|
#include "nursery_space.hpp"
|
||||||
#include "aging_space.hpp"
|
#include "aging_space.hpp"
|
||||||
#include "tenured_space.hpp"
|
#include "tenured_space.hpp"
|
||||||
#include "data_heap.hpp"
|
#include "data_heap.hpp"
|
||||||
|
|
|
@ -6,10 +6,14 @@ struct nursery_policy {
|
||||||
|
|
||||||
nursery_policy(factor_vm *parent_) : parent(parent_) {}
|
nursery_policy(factor_vm *parent_) : parent(parent_) {}
|
||||||
|
|
||||||
bool should_copy_p(object *untagged)
|
bool should_copy_p(object *obj)
|
||||||
{
|
{
|
||||||
return parent->nursery.contains_p(untagged);
|
return parent->nursery.contains_p(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void promoted_object(object *obj) {}
|
||||||
|
|
||||||
|
void visited_object(object *obj) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct nursery_collector : copying_collector<aging_space,nursery_policy> {
|
struct nursery_collector : copying_collector<aging_space,nursery_policy> {
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
namespace factor
|
||||||
|
{
|
||||||
|
|
||||||
|
struct nursery_space : bump_allocator<object>
|
||||||
|
{
|
||||||
|
nursery_space(cell size, cell start) : bump_allocator<object>(size,start) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,19 +1,65 @@
|
||||||
namespace factor
|
namespace factor
|
||||||
{
|
{
|
||||||
|
|
||||||
struct tenured_space : bump_allocator {
|
struct tenured_space : free_list_allocator<object> {
|
||||||
object_start_map starts;
|
object_start_map starts;
|
||||||
|
std::vector<object *> mark_stack;
|
||||||
|
|
||||||
tenured_space(cell size, cell start) :
|
tenured_space(cell size, cell start) :
|
||||||
bump_allocator(size,start), starts(size,start) {}
|
free_list_allocator<object>(size,start), starts(size,start) {}
|
||||||
|
|
||||||
object *allot(cell size)
|
object *allot(cell size)
|
||||||
{
|
{
|
||||||
if(here + size > end) return NULL;
|
object *obj = free_list_allocator<object>::allot(size);
|
||||||
|
if(obj)
|
||||||
|
{
|
||||||
|
starts.record_object_start_offset(obj);
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
object *obj = bump_allocator::allot(size);
|
object *first_allocated_block_after(object *block)
|
||||||
starts.record_object_start_offset(obj);
|
{
|
||||||
return obj;
|
while(block != this->last_block() && block->free_p())
|
||||||
|
{
|
||||||
|
free_heap_block *free_block = (free_heap_block *)block;
|
||||||
|
block = (object *)((cell)free_block + free_block->size());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(block == this->last_block())
|
||||||
|
return NULL;
|
||||||
|
else
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell first_object()
|
||||||
|
{
|
||||||
|
return (cell)first_allocated_block_after(this->first_block());
|
||||||
|
}
|
||||||
|
|
||||||
|
cell next_object_after(cell scan)
|
||||||
|
{
|
||||||
|
cell size = ((object *)scan)->size();
|
||||||
|
object *next = (object *)(scan + size);
|
||||||
|
return (cell)first_allocated_block_after(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_mark_bits()
|
||||||
|
{
|
||||||
|
state.clear_mark_bits();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool marked_p(object *obj)
|
||||||
|
{
|
||||||
|
return this->state.marked_p(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mark_and_push(object *obj)
|
||||||
|
{
|
||||||
|
this->state.set_marked_p(obj);
|
||||||
|
this->mark_stack.push_back(obj);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -4,12 +4,23 @@ namespace factor
|
||||||
{
|
{
|
||||||
|
|
||||||
to_tenured_collector::to_tenured_collector(factor_vm *myvm_) :
|
to_tenured_collector::to_tenured_collector(factor_vm *myvm_) :
|
||||||
copying_collector<tenured_space,to_tenured_policy>(
|
collector<tenured_space,to_tenured_policy>(
|
||||||
myvm_,
|
myvm_,
|
||||||
&myvm_->gc_stats.aging_stats,
|
&myvm_->gc_stats.aging_stats,
|
||||||
myvm_->data->tenured,
|
myvm_->data->tenured,
|
||||||
to_tenured_policy(myvm_)) {}
|
to_tenured_policy(myvm_)) {}
|
||||||
|
|
||||||
|
void to_tenured_collector::tenure_reachable_objects()
|
||||||
|
{
|
||||||
|
std::vector<object *> *mark_stack = &this->target->mark_stack;
|
||||||
|
while(!mark_stack->empty())
|
||||||
|
{
|
||||||
|
object *obj = mark_stack->back();
|
||||||
|
mark_stack->pop_back();
|
||||||
|
this->trace_slots(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void factor_vm::collect_to_tenured()
|
void factor_vm::collect_to_tenured()
|
||||||
{
|
{
|
||||||
/* Copy live objects from aging space to tenured space. */
|
/* Copy live objects from aging space to tenured space. */
|
||||||
|
@ -21,7 +32,7 @@ void factor_vm::collect_to_tenured()
|
||||||
card_points_to_aging,
|
card_points_to_aging,
|
||||||
dummy_unmarker());
|
dummy_unmarker());
|
||||||
collector.trace_code_heap_roots(&code->points_to_aging);
|
collector.trace_code_heap_roots(&code->points_to_aging);
|
||||||
collector.cheneys_algorithm();
|
collector.tenure_reachable_objects();
|
||||||
update_code_heap_for_minor_gc(&code->points_to_aging);
|
update_code_heap_for_minor_gc(&code->points_to_aging);
|
||||||
|
|
||||||
nursery.here = nursery.start;
|
nursery.here = nursery.start;
|
||||||
|
|
|
@ -11,10 +11,18 @@ struct to_tenured_policy {
|
||||||
{
|
{
|
||||||
return !tenured->contains_p(untagged);
|
return !tenured->contains_p(untagged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void promoted_object(object *obj)
|
||||||
|
{
|
||||||
|
tenured->mark_stack.push_back(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visited_object(object *obj) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct to_tenured_collector : copying_collector<tenured_space,to_tenured_policy> {
|
struct to_tenured_collector : collector<tenured_space,to_tenured_policy> {
|
||||||
to_tenured_collector(factor_vm *myvm_);
|
to_tenured_collector(factor_vm *myvm_);
|
||||||
|
void tenure_reachable_objects();
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct factor_vm
|
||||||
context *ctx;
|
context *ctx;
|
||||||
|
|
||||||
/* New objects are allocated here */
|
/* New objects are allocated here */
|
||||||
bump_allocator nursery;
|
nursery_space nursery;
|
||||||
|
|
||||||
/* Add this to a shifted address to compute write barrier offsets */
|
/* Add this to a shifted address to compute write barrier offsets */
|
||||||
cell cards_offset;
|
cell cards_offset;
|
||||||
|
@ -308,7 +308,7 @@ struct factor_vm
|
||||||
void print_callstack();
|
void print_callstack();
|
||||||
void dump_cell(cell x);
|
void dump_cell(cell x);
|
||||||
void dump_memory(cell from, cell to);
|
void dump_memory(cell from, cell to);
|
||||||
void dump_zone(const char *name, bump_allocator *z);
|
template<typename Generation> void dump_generation(const char *name, Generation *gen);
|
||||||
void dump_generations();
|
void dump_generations();
|
||||||
void dump_objects(cell type);
|
void dump_objects(cell type);
|
||||||
void find_data_references_step(cell *scan);
|
void find_data_references_step(cell *scan);
|
||||||
|
|
Loading…
Reference in New Issue