273 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			273 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C++
		
	
	
| namespace factor
 | |
| {
 | |
| 
 | |
| struct must_start_gc_again {};
 | |
| 
 | |
| template<typename TargetGeneration, typename Policy> struct gc_workhorse : no_fixup {
 | |
| 	factor_vm *parent;
 | |
| 	TargetGeneration *target;
 | |
| 	Policy policy;
 | |
| 	code_heap *code;
 | |
| 
 | |
| 	explicit gc_workhorse(factor_vm *parent_, TargetGeneration *target_, Policy policy_) :
 | |
| 		parent(parent_),
 | |
| 		target(target_),
 | |
| 		policy(policy_),
 | |
| 		code(parent->code) {}
 | |
| 
 | |
| 	object *resolve_forwarding(object *untagged)
 | |
| 	{
 | |
| 		parent->check_data_pointer(untagged);
 | |
| 
 | |
| 		/* is there another forwarding pointer? */
 | |
| 		while(untagged->forwarding_pointer_p())
 | |
| 			untagged = untagged->forwarding_pointer();
 | |
| 
 | |
| 		/* we've found the destination */
 | |
| 		return untagged;
 | |
| 	}
 | |
| 
 | |
| 	object *promote_object(object *untagged)
 | |
| 	{
 | |
| 		cell size = untagged->size();
 | |
| 		object *newpointer = target->allot(size);
 | |
| 		if(!newpointer) throw must_start_gc_again();
 | |
| 
 | |
| 		memcpy(newpointer,untagged,size);
 | |
| 		untagged->forward_to(newpointer);
 | |
| 
 | |
| 		policy.promoted_object(newpointer);
 | |
| 
 | |
| 		return newpointer;
 | |
| 	}
 | |
| 
 | |
| 	object *fixup_data(object *obj)
 | |
| 	{
 | |
| 		parent->check_data_pointer(obj);
 | |
| 
 | |
| 		if(!policy.should_copy_p(obj))
 | |
| 		{
 | |
| 			policy.visited_object(obj);
 | |
| 			return obj;
 | |
| 		}
 | |
| 
 | |
| 		object *forwarding = resolve_forwarding(obj);
 | |
| 
 | |
| 		if(forwarding == obj)
 | |
| 			return promote_object(obj);
 | |
| 		else if(policy.should_copy_p(forwarding))
 | |
| 			return promote_object(forwarding);
 | |
| 		else
 | |
| 		{
 | |
| 			policy.visited_object(forwarding);
 | |
| 			return forwarding;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	code_block *fixup_code(code_block *compiled)
 | |
| 	{
 | |
| 		if(!code->marked_p(compiled))
 | |
| 		{
 | |
| 			code->set_marked_p(compiled);
 | |
| 			parent->mark_stack.push_back((cell)compiled + 1);
 | |
| 		}
 | |
| 
 | |
| 		return compiled;
 | |
| 	}
 | |
| };
 | |
| 
 | |
| struct dummy_unmarker {
 | |
| 	void operator()(card *ptr) {}
 | |
| };
 | |
| 
 | |
| struct simple_unmarker {
 | |
| 	card unmask;
 | |
| 	explicit simple_unmarker(card unmask_) : unmask(unmask_) {}
 | |
| 	void operator()(card *ptr) { *ptr &= ~unmask; }
 | |
| };
 | |
| 
 | |
| struct full_unmarker {
 | |
| 	explicit full_unmarker() {}
 | |
| 	void operator()(card *ptr) { *ptr = 0; }
 | |
| };
 | |
| 
 | |
| template<typename TargetGeneration, typename Policy>
 | |
| struct collector {
 | |
| 	factor_vm *parent;
 | |
| 	data_heap *data;
 | |
| 	code_heap *code;
 | |
| 	TargetGeneration *target;
 | |
| 	gc_workhorse<TargetGeneration,Policy> workhorse;
 | |
| 	slot_visitor<gc_workhorse<TargetGeneration,Policy> > data_visitor;
 | |
| 	cell cards_scanned;
 | |
| 	cell decks_scanned;
 | |
| 	cell code_blocks_scanned;
 | |
| 
 | |
| 	explicit collector(factor_vm *parent_, TargetGeneration *target_, Policy policy_) :
 | |
| 		parent(parent_),
 | |
| 		data(parent_->data),
 | |
| 		code(parent_->code),
 | |
| 		target(target_),
 | |
| 		workhorse(parent,target,policy_),
 | |
| 		data_visitor(parent,workhorse),
 | |
| 		cards_scanned(0),
 | |
| 		decks_scanned(0),
 | |
| 		code_blocks_scanned(0) {}
 | |
| 
 | |
| 	void trace_handle(cell *handle)
 | |
| 	{
 | |
| 		data_visitor.visit_handle(handle);
 | |
| 	}
 | |
| 
 | |
| 	void trace_object(object *ptr)
 | |
| 	{
 | |
| 		data_visitor.visit_slots(ptr);
 | |
| 		if(ptr->type() == ALIEN_TYPE)
 | |
| 			((alien *)ptr)->update_address();
 | |
| 	}
 | |
| 
 | |
| 	void trace_roots()
 | |
| 	{
 | |
| 		data_visitor.visit_roots();
 | |
| 	}
 | |
| 
 | |
| 	void trace_contexts()
 | |
| 	{
 | |
| 		data_visitor.visit_contexts();
 | |
| 	}
 | |
| 
 | |
| 	void trace_code_block_objects(code_block *compiled)
 | |
| 	{
 | |
| 		data_visitor.visit_code_block_objects(compiled);
 | |
| 	}
 | |
| 
 | |
| 	void trace_embedded_literals(code_block *compiled)
 | |
| 	{
 | |
| 		data_visitor.visit_embedded_literals(compiled);
 | |
| 	}
 | |
| 
 | |
| 	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++)
 | |
| 		{
 | |
| 			code_block *compiled = *iter;
 | |
| 			trace_code_block_objects(compiled);
 | |
| 			trace_embedded_literals(compiled);
 | |
| 			compiled->flush_icache();
 | |
| 			code_blocks_scanned++;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	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 - data->start);
 | |
| 	}
 | |
| 
 | |
| 	inline cell card_start_address(cell card)
 | |
| 	{
 | |
| 		return (card << card_bits) + data->start;
 | |
| 	}
 | |
| 
 | |
| 	inline cell card_end_address(cell card)
 | |
| 	{
 | |
| 		return ((card + 1) << card_bits) + 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;
 | |
| 
 | |
| 			for(; slot_ptr < end_ptr; slot_ptr++)
 | |
| 				data_visitor.visit_handle(slot_ptr);
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	template<typename SourceGeneration, typename Unmarker>
 | |
| 	void trace_cards(SourceGeneration *gen, card mask, Unmarker unmarker)
 | |
| 	{
 | |
| 		card_deck *decks = data->decks;
 | |
| 		card_deck *cards = data->cards;
 | |
| 
 | |
| 		cell gen_start_card = addr_to_card(gen->start - 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)
 | |
| 			{
 | |
| 				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)
 | |
| 					{
 | |
| 						cards_scanned++;
 | |
| 
 | |
| 						if(end < card_start_address(card_index))
 | |
| 						{
 | |
| 							start = gen->starts.find_object_containing_card(card_index - gen_start_card);
 | |
| 							binary_start = start + ((object *)start)->binary_payload_start();
 | |
| 							end = start + ((object *)start)->size();
 | |
| 						}
 | |
| 
 | |
| scan_next_object:				if(start < card_end_address(card_index))
 | |
| 						{
 | |
| 							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 + ((object *)start)->binary_payload_start();
 | |
| 									end = start + ((object *)start)->size();
 | |
| 									goto scan_next_object;
 | |
| 								}
 | |
| 							}
 | |
| 						}
 | |
| 
 | |
| 						unmarker(&cards[card_index]);
 | |
| 
 | |
| 						if(!start) return;
 | |
| 					}
 | |
| 				}
 | |
| 
 | |
| 				unmarker(&decks[deck_index]);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| };
 | |
| 
 | |
| }
 |