67 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			67 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			C++
		
	
	
namespace factor
 | 
						|
{
 | 
						|
 | 
						|
/* The callback heap is used to store the machine code that alien-callbacks
 | 
						|
actually jump to when C code invokes them.
 | 
						|
 | 
						|
The callback heap has entries that look like code_blocks from the code heap, but
 | 
						|
callback heap entries are allocated contiguously, never deallocated, and all
 | 
						|
fields but the owner are set to false_object. The owner points to the callback
 | 
						|
bottom word, whose entry point is the callback body itself, generated by the
 | 
						|
optimizing compiler. The machine code that follows a callback stub consists of a
 | 
						|
single CALLBACK_STUB machine code template, which performs a jump to a "far"
 | 
						|
address (on PowerPC and x86-64, its loaded into a register first).
 | 
						|
 | 
						|
GC updates the CALLBACK_STUB code if the code block of the callback bottom word
 | 
						|
is ever moved. The callback stub itself won't move, though, and is never
 | 
						|
deallocated. This means that the callback stub itself is a stable function
 | 
						|
pointer that C code can hold on to until the associated Factor VM exits.
 | 
						|
 | 
						|
Since callback stubs are GC roots, and are never deallocated, the associated
 | 
						|
callback code in the code heap is also never deallocated.
 | 
						|
 | 
						|
The callback heap is not saved in the image. Running GC in a new session after
 | 
						|
saving the image will deallocate any code heap entries that were only reachable
 | 
						|
from the callback heap in the previous session when the image was saved. */
 | 
						|
 | 
						|
struct callback_heap {
 | 
						|
	segment *seg;
 | 
						|
	cell here;
 | 
						|
	factor_vm *parent;
 | 
						|
 | 
						|
	explicit callback_heap(cell size, factor_vm *parent);
 | 
						|
	~callback_heap();
 | 
						|
 | 
						|
	void *callback_entry_point(code_block *stub)
 | 
						|
	{
 | 
						|
		word *w = (word *)UNTAG(stub->owner);
 | 
						|
		return w->entry_point;
 | 
						|
	}
 | 
						|
 | 
						|
	void store_callback_operand(code_block *stub, cell index, cell value);
 | 
						|
 | 
						|
	void update(code_block *stub);
 | 
						|
 | 
						|
	code_block *add(cell owner, cell return_rewind);
 | 
						|
 | 
						|
	void update();
 | 
						|
 | 
						|
	code_block *next(code_block *stub)
 | 
						|
	{
 | 
						|
		return (code_block *)((cell)stub + stub->size());
 | 
						|
	}
 | 
						|
 | 
						|
	template<typename Iterator> void each_callback(Iterator &iter)
 | 
						|
	{
 | 
						|
		code_block *scan = (code_block *)seg->start;
 | 
						|
		code_block *end = (code_block *)here;
 | 
						|
		while(scan < end)
 | 
						|
		{
 | 
						|
			iter(scan);
 | 
						|
			scan = next(scan);
 | 
						|
		}
 | 
						|
	}
 | 
						|
};
 | 
						|
 | 
						|
}
 |