66 lines
		
	
	
		
			2.3 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			66 lines
		
	
	
		
			2.3 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;
 | |
| 
 | |
|   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;
 | |
|   }
 | |
| 
 | |
|   bool setup_seh_p();
 | |
|   bool return_takes_param_p();
 | |
|   instruction_operand callback_operand(code_block* stub, cell index);
 | |
|   void store_callback_operand(code_block* stub, cell index);
 | |
|   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);
 | |
|     }
 | |
|   }
 | |
| };
 | |
| 
 | |
| }
 |