VM: Refactor callbacks to Factor style
parent
22eed89484
commit
7aae3c04ce
|
@ -1,26 +1,20 @@
|
||||||
#include "master.hpp"
|
#include "master.hpp"
|
||||||
|
|
||||||
namespace factor
|
namespace factor {
|
||||||
{
|
|
||||||
|
|
||||||
callback_heap::callback_heap(cell size, factor_vm *parent_) :
|
callback_heap::callback_heap(cell size, factor_vm* parent_)
|
||||||
seg(new segment(size,true)),
|
: seg(new segment(size, true)), here(seg->start), parent(parent_) {}
|
||||||
here(seg->start),
|
|
||||||
parent(parent_) {}
|
|
||||||
|
|
||||||
callback_heap::~callback_heap()
|
callback_heap::~callback_heap() {
|
||||||
{
|
|
||||||
delete seg;
|
delete seg;
|
||||||
seg = NULL;
|
seg = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::init_callbacks(cell size)
|
void factor_vm::init_callbacks(cell size) {
|
||||||
{
|
callbacks = new callback_heap(size, this);
|
||||||
callbacks = new callback_heap(size,this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool callback_heap::setup_seh_p()
|
bool callback_heap::setup_seh_p() {
|
||||||
{
|
|
||||||
#if defined(WINDOWS) && defined(FACTOR_X86)
|
#if defined(WINDOWS) && defined(FACTOR_X86)
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
|
@ -28,8 +22,7 @@ bool callback_heap::setup_seh_p()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool callback_heap::return_takes_param_p()
|
bool callback_heap::return_takes_param_p() {
|
||||||
{
|
|
||||||
#if defined(FACTOR_X86) || defined(FACTOR_AMD64)
|
#if defined(FACTOR_X86) || defined(FACTOR_AMD64)
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
|
@ -37,71 +30,69 @@ bool callback_heap::return_takes_param_p()
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
instruction_operand callback_heap::callback_operand(code_block *stub, cell index)
|
instruction_operand callback_heap::callback_operand(code_block* stub,
|
||||||
{
|
cell index) {
|
||||||
tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
|
tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
|
||||||
tagged<byte_array> relocation_template(array_nth(code_template.untagged(),0));
|
tagged<byte_array> relocation_template(
|
||||||
|
array_nth(code_template.untagged(), 0));
|
||||||
|
|
||||||
relocation_entry entry(relocation_template->data<relocation_entry>()[index]);
|
relocation_entry entry(relocation_template->data<relocation_entry>()[index]);
|
||||||
return instruction_operand(entry,stub,0);
|
return instruction_operand(entry, stub, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_heap::store_callback_operand(code_block *stub, cell index)
|
void callback_heap::store_callback_operand(code_block* stub, cell index) {
|
||||||
{
|
parent->store_external_address(callback_operand(stub, index));
|
||||||
parent->store_external_address(callback_operand(stub,index));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_heap::store_callback_operand(code_block *stub, cell index, cell value)
|
void callback_heap::store_callback_operand(code_block* stub, cell index,
|
||||||
{
|
cell value) {
|
||||||
callback_operand(stub,index).store_value(value);
|
callback_operand(stub, index).store_value(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void callback_heap::update(code_block *stub)
|
void callback_heap::update(code_block* stub) {
|
||||||
{
|
store_callback_operand(stub, setup_seh_p() ? 2 : 1,
|
||||||
store_callback_operand(stub,setup_seh_p() ? 2 : 1,(cell)callback_entry_point(stub));
|
(cell) callback_entry_point(stub));
|
||||||
stub->flush_icache();
|
stub->flush_icache();
|
||||||
}
|
}
|
||||||
|
|
||||||
code_block *callback_heap::add(cell owner, cell return_rewind)
|
code_block* callback_heap::add(cell owner, cell return_rewind) {
|
||||||
{
|
|
||||||
tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
|
tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
|
||||||
tagged<byte_array> insns(array_nth(code_template.untagged(),1));
|
tagged<byte_array> insns(array_nth(code_template.untagged(), 1));
|
||||||
cell size = array_capacity(insns.untagged());
|
cell size = array_capacity(insns.untagged());
|
||||||
|
|
||||||
cell bump = align(size + sizeof(code_block),data_alignment);
|
cell bump = align(size + sizeof(code_block), data_alignment);
|
||||||
if(here + bump > seg->end) fatal_error("Out of callback space",0);
|
if (here + bump > seg->end)
|
||||||
|
fatal_error("Out of callback space", 0);
|
||||||
|
|
||||||
free_heap_block *free_block = (free_heap_block *)here;
|
free_heap_block* free_block = (free_heap_block*)here;
|
||||||
free_block->make_free(bump);
|
free_block->make_free(bump);
|
||||||
here += bump;
|
here += bump;
|
||||||
|
|
||||||
code_block *stub = (code_block *)free_block;
|
code_block* stub = (code_block*)free_block;
|
||||||
stub->owner = owner;
|
stub->owner = owner;
|
||||||
stub->parameters = false_object;
|
stub->parameters = false_object;
|
||||||
stub->relocation = false_object;
|
stub->relocation = false_object;
|
||||||
|
|
||||||
memcpy(stub->entry_point(),insns->data<void>(),size);
|
memcpy(stub->entry_point(), insns->data<void>(), size);
|
||||||
|
|
||||||
/* Store VM pointer */
|
/* Store VM pointer */
|
||||||
store_callback_operand(stub,0,(cell)parent);
|
store_callback_operand(stub, 0, (cell) parent);
|
||||||
|
|
||||||
cell index;
|
cell index;
|
||||||
|
|
||||||
if(setup_seh_p())
|
if (setup_seh_p()) {
|
||||||
{
|
store_callback_operand(stub, 1);
|
||||||
store_callback_operand(stub,1);
|
|
||||||
index = 1;
|
index = 1;
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
index = 0;
|
index = 0;
|
||||||
|
|
||||||
/* Store VM pointer */
|
/* Store VM pointer */
|
||||||
store_callback_operand(stub,index + 2,(cell)parent);
|
store_callback_operand(stub, index + 2, (cell) parent);
|
||||||
|
|
||||||
/* On x86, the RET instruction takes an argument which depends on
|
/* On x86, the RET instruction takes an argument which depends on
|
||||||
the callback's calling convention */
|
the callback's calling convention */
|
||||||
if(return_takes_param_p())
|
if (return_takes_param_p())
|
||||||
store_callback_operand(stub,index + 3,return_rewind);
|
store_callback_operand(stub, index + 3, return_rewind);
|
||||||
|
|
||||||
update(stub);
|
update(stub);
|
||||||
|
|
||||||
|
@ -109,31 +100,27 @@ code_block *callback_heap::add(cell owner, cell return_rewind)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct callback_updater {
|
struct callback_updater {
|
||||||
callback_heap *callbacks;
|
callback_heap* callbacks;
|
||||||
|
|
||||||
explicit callback_updater(callback_heap *callbacks_) : callbacks(callbacks_) {}
|
explicit callback_updater(callback_heap* callbacks_)
|
||||||
|
: callbacks(callbacks_) {}
|
||||||
|
|
||||||
void operator()(code_block *stub)
|
void operator()(code_block* stub) { callbacks->update(stub); }
|
||||||
{
|
|
||||||
callbacks->update(stub);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void callback_heap::update()
|
void callback_heap::update() {
|
||||||
{
|
|
||||||
callback_updater updater(this);
|
callback_updater updater(this);
|
||||||
each_callback(updater);
|
each_callback(updater);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocates memory */
|
/* Allocates memory */
|
||||||
void factor_vm::primitive_callback()
|
void factor_vm::primitive_callback() {
|
||||||
{
|
|
||||||
cell return_rewind = to_cell(ctx->pop());
|
cell return_rewind = to_cell(ctx->pop());
|
||||||
tagged<word> w(ctx->pop());
|
tagged<word> w(ctx->pop());
|
||||||
|
|
||||||
w.untag_check(this);
|
w.untag_check(this);
|
||||||
|
|
||||||
void* func = callbacks->add(w.value(),return_rewind)->entry_point();
|
void* func = callbacks->add(w.value(), return_rewind)->entry_point();
|
||||||
CODE_TO_FUNCTION_POINTER_CALLBACK(this, func);
|
CODE_TO_FUNCTION_POINTER_CALLBACK(this, func);
|
||||||
ctx->push(allot_alien(func));
|
ctx->push(allot_alien(func));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
namespace factor
|
namespace factor {
|
||||||
{
|
|
||||||
|
|
||||||
/* The callback heap is used to store the machine code that alien-callbacks
|
/* The callback heap is used to store the machine code that alien-callbacks
|
||||||
actually jump to when C code invokes them.
|
actually jump to when C code invokes them.
|
||||||
|
@ -25,42 +24,38 @@ 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. */
|
from the callback heap in the previous session when the image was saved. */
|
||||||
|
|
||||||
struct callback_heap {
|
struct callback_heap {
|
||||||
segment *seg;
|
segment* seg;
|
||||||
cell here;
|
cell here;
|
||||||
factor_vm *parent;
|
factor_vm* parent;
|
||||||
|
|
||||||
explicit callback_heap(cell size, factor_vm *parent);
|
explicit callback_heap(cell size, factor_vm* parent);
|
||||||
~callback_heap();
|
~callback_heap();
|
||||||
|
|
||||||
void *callback_entry_point(code_block *stub)
|
void* callback_entry_point(code_block* stub) {
|
||||||
{
|
word* w = (word*)UNTAG(stub->owner);
|
||||||
word *w = (word *)UNTAG(stub->owner);
|
|
||||||
return w->entry_point;
|
return w->entry_point;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setup_seh_p();
|
bool setup_seh_p();
|
||||||
bool return_takes_param_p();
|
bool return_takes_param_p();
|
||||||
instruction_operand callback_operand(code_block *stub, cell index);
|
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);
|
||||||
void store_callback_operand(code_block *stub, cell index, cell value);
|
void store_callback_operand(code_block* stub, cell index, cell value);
|
||||||
|
|
||||||
void update(code_block *stub);
|
void update(code_block* stub);
|
||||||
|
|
||||||
code_block *add(cell owner, cell return_rewind);
|
code_block* add(cell owner, cell return_rewind);
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
|
|
||||||
code_block *next(code_block *stub)
|
code_block* next(code_block* stub) {
|
||||||
{
|
return (code_block*)((cell) stub + stub->size());
|
||||||
return (code_block *)((cell)stub + stub->size());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Iterator> void each_callback(Iterator &iter)
|
template <typename Iterator> void each_callback(Iterator& iter) {
|
||||||
{
|
code_block* scan = (code_block*)seg->start;
|
||||||
code_block *scan = (code_block *)seg->start;
|
code_block* end = (code_block*)here;
|
||||||
code_block *end = (code_block *)here;
|
while (scan < end) {
|
||||||
while(scan < end)
|
|
||||||
{
|
|
||||||
iter(scan);
|
iter(scan);
|
||||||
scan = next(scan);
|
scan = next(scan);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue