VM: Refactor code_blocks to Factor style
parent
2e20733ade
commit
d2fe86eb7e
|
@ -1,5 +1,4 @@
|
||||||
namespace factor
|
namespace factor {
|
||||||
{
|
|
||||||
|
|
||||||
/* Code block visitors iterate over sets of code blocks, applying a functor to
|
/* Code block visitors iterate over sets of code blocks, applying a functor to
|
||||||
each one. The functor returns a new code_block pointer, which may or may not
|
each one. The functor returns a new code_block pointer, which may or may not
|
||||||
|
@ -12,130 +11,114 @@ Iteration is driven by visit_*() methods. Some of them define GC roots:
|
||||||
- visit_context_code_blocks()
|
- visit_context_code_blocks()
|
||||||
- visit_callback_code_blocks() */
|
- visit_callback_code_blocks() */
|
||||||
|
|
||||||
template<typename Fixup> struct code_block_visitor {
|
template <typename Fixup> struct code_block_visitor {
|
||||||
factor_vm *parent;
|
factor_vm* parent;
|
||||||
Fixup fixup;
|
Fixup fixup;
|
||||||
|
|
||||||
explicit code_block_visitor(factor_vm *parent_, Fixup fixup_) :
|
explicit code_block_visitor(factor_vm* parent_, Fixup fixup_)
|
||||||
parent(parent_), fixup(fixup_) {}
|
: parent(parent_), fixup(fixup_) {}
|
||||||
|
|
||||||
code_block *visit_code_block(code_block *compiled);
|
code_block* visit_code_block(code_block* compiled);
|
||||||
void visit_object_code_block(object *obj);
|
void visit_object_code_block(object* obj);
|
||||||
void visit_embedded_code_pointers(code_block *compiled);
|
void visit_embedded_code_pointers(code_block* compiled);
|
||||||
void visit_context_code_blocks();
|
void visit_context_code_blocks();
|
||||||
void visit_uninitialized_code_blocks();
|
void visit_uninitialized_code_blocks();
|
||||||
|
|
||||||
void visit_code_roots();
|
void visit_code_roots();
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Fixup>
|
template <typename Fixup>
|
||||||
code_block *code_block_visitor<Fixup>::visit_code_block(code_block *compiled)
|
code_block* code_block_visitor<Fixup>::visit_code_block(code_block* compiled) {
|
||||||
{
|
return fixup.fixup_code(compiled);
|
||||||
return fixup.fixup_code(compiled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Fixup>
|
template <typename Fixup> struct call_frame_code_block_visitor {
|
||||||
struct call_frame_code_block_visitor {
|
factor_vm* parent;
|
||||||
factor_vm *parent;
|
Fixup fixup;
|
||||||
Fixup fixup;
|
|
||||||
|
|
||||||
explicit call_frame_code_block_visitor(factor_vm *parent_, Fixup fixup_) :
|
explicit call_frame_code_block_visitor(factor_vm* parent_, Fixup fixup_)
|
||||||
parent(parent_), fixup(fixup_) {}
|
: parent(parent_), fixup(fixup_) {}
|
||||||
|
|
||||||
void operator()(void *frame_top, cell frame_size, code_block *owner, void *addr)
|
void operator()(void* frame_top, cell frame_size, code_block* owner,
|
||||||
{
|
void* addr) {
|
||||||
code_block *compiled = Fixup::translated_code_block_map
|
code_block* compiled =
|
||||||
? owner
|
Fixup::translated_code_block_map ? owner : fixup.fixup_code(owner);
|
||||||
: fixup.fixup_code(owner);
|
void* fixed_addr = compiled->address_for_offset(owner->offset(addr));
|
||||||
void *fixed_addr = compiled->address_for_offset(owner->offset(addr));
|
set_frame_return_address(frame_top, fixed_addr);
|
||||||
set_frame_return_address(frame_top, fixed_addr);
|
}
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Fixup>
|
template <typename Fixup>
|
||||||
void code_block_visitor<Fixup>::visit_object_code_block(object *obj)
|
void code_block_visitor<Fixup>::visit_object_code_block(object* obj) {
|
||||||
{
|
switch (obj->type()) {
|
||||||
switch(obj->type())
|
case WORD_TYPE: {
|
||||||
{
|
word* w = (word*)obj;
|
||||||
case WORD_TYPE:
|
if (w->entry_point)
|
||||||
{
|
w->entry_point = visit_code_block(w->code())->entry_point();
|
||||||
word *w = (word *)obj;
|
break;
|
||||||
if(w->entry_point)
|
}
|
||||||
w->entry_point = visit_code_block(w->code())->entry_point();
|
case QUOTATION_TYPE: {
|
||||||
break;
|
quotation* q = (quotation*)obj;
|
||||||
}
|
if (q->entry_point)
|
||||||
case QUOTATION_TYPE:
|
q->entry_point = visit_code_block(q->code())->entry_point();
|
||||||
{
|
break;
|
||||||
quotation *q = (quotation *)obj;
|
}
|
||||||
if(q->entry_point)
|
case CALLSTACK_TYPE: {
|
||||||
q->entry_point = visit_code_block(q->code())->entry_point();
|
callstack* stack = (callstack*)obj;
|
||||||
break;
|
call_frame_code_block_visitor<Fixup> call_frame_visitor(parent, fixup);
|
||||||
}
|
parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
|
||||||
case CALLSTACK_TYPE:
|
break;
|
||||||
{
|
}
|
||||||
callstack *stack = (callstack *)obj;
|
}
|
||||||
call_frame_code_block_visitor<Fixup> call_frame_visitor(parent,fixup);
|
|
||||||
parent->iterate_callstack_object(stack,call_frame_visitor,fixup);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Fixup>
|
template <typename Fixup> struct embedded_code_pointers_visitor {
|
||||||
struct embedded_code_pointers_visitor {
|
Fixup fixup;
|
||||||
Fixup fixup;
|
|
||||||
|
|
||||||
explicit embedded_code_pointers_visitor(Fixup fixup_) : fixup(fixup_) {}
|
explicit embedded_code_pointers_visitor(Fixup fixup_) : fixup(fixup_) {}
|
||||||
|
|
||||||
void operator()(instruction_operand op)
|
void operator()(instruction_operand op) {
|
||||||
{
|
relocation_type type = op.rel_type();
|
||||||
relocation_type type = op.rel_type();
|
if (type == RT_ENTRY_POINT || type == RT_ENTRY_POINT_PIC ||
|
||||||
if(type == RT_ENTRY_POINT
|
type == RT_ENTRY_POINT_PIC_TAIL)
|
||||||
|| type == RT_ENTRY_POINT_PIC
|
op.store_code_block(fixup.fixup_code(op.load_code_block()));
|
||||||
|| type == RT_ENTRY_POINT_PIC_TAIL)
|
}
|
||||||
op.store_code_block(fixup.fixup_code(op.load_code_block()));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Fixup>
|
template <typename Fixup>
|
||||||
void code_block_visitor<Fixup>::visit_embedded_code_pointers(code_block *compiled)
|
void code_block_visitor<Fixup>::visit_embedded_code_pointers(
|
||||||
{
|
code_block* compiled) {
|
||||||
if(!parent->code->uninitialized_p(compiled))
|
if (!parent->code->uninitialized_p(compiled)) {
|
||||||
{
|
embedded_code_pointers_visitor<Fixup> operand_visitor(fixup);
|
||||||
embedded_code_pointers_visitor<Fixup> operand_visitor(fixup);
|
compiled->each_instruction_operand(operand_visitor);
|
||||||
compiled->each_instruction_operand(operand_visitor);
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Fixup>
|
template <typename Fixup>
|
||||||
void code_block_visitor<Fixup>::visit_context_code_blocks()
|
void code_block_visitor<Fixup>::visit_context_code_blocks() {
|
||||||
{
|
call_frame_code_block_visitor<Fixup> call_frame_visitor(parent, fixup);
|
||||||
call_frame_code_block_visitor<Fixup> call_frame_visitor(parent,fixup);
|
parent->iterate_active_callstacks(call_frame_visitor, fixup);
|
||||||
parent->iterate_active_callstacks(call_frame_visitor,fixup);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Fixup>
|
template <typename Fixup>
|
||||||
void code_block_visitor<Fixup>::visit_uninitialized_code_blocks()
|
void code_block_visitor<Fixup>::visit_uninitialized_code_blocks() {
|
||||||
{
|
std::map<code_block*, cell>* uninitialized_blocks =
|
||||||
std::map<code_block *, cell> *uninitialized_blocks = &parent->code->uninitialized_blocks;
|
&parent->code->uninitialized_blocks;
|
||||||
std::map<code_block *, cell>::const_iterator iter = uninitialized_blocks->begin();
|
std::map<code_block*, cell>::const_iterator iter =
|
||||||
std::map<code_block *, cell>::const_iterator end = uninitialized_blocks->end();
|
uninitialized_blocks->begin();
|
||||||
|
std::map<code_block*, cell>::const_iterator end = uninitialized_blocks->end();
|
||||||
|
|
||||||
std::map<code_block *, cell> new_uninitialized_blocks;
|
std::map<code_block*, cell> new_uninitialized_blocks;
|
||||||
for(; iter != end; iter++)
|
for (; iter != end; iter++) {
|
||||||
{
|
new_uninitialized_blocks.insert(
|
||||||
new_uninitialized_blocks.insert(std::make_pair(
|
std::make_pair(fixup.fixup_code(iter->first), iter->second));
|
||||||
fixup.fixup_code(iter->first),
|
}
|
||||||
iter->second));
|
|
||||||
}
|
|
||||||
|
|
||||||
parent->code->uninitialized_blocks = new_uninitialized_blocks;
|
parent->code->uninitialized_blocks = new_uninitialized_blocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Fixup>
|
template <typename Fixup> void code_block_visitor<Fixup>::visit_code_roots() {
|
||||||
void code_block_visitor<Fixup>::visit_code_roots()
|
visit_uninitialized_code_blocks();
|
||||||
{
|
|
||||||
visit_uninitialized_code_blocks();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,530 +1,495 @@
|
||||||
#include "master.hpp"
|
#include "master.hpp"
|
||||||
|
|
||||||
namespace factor
|
namespace factor {
|
||||||
{
|
|
||||||
|
|
||||||
cell code_block::owner_quot() const
|
cell code_block::owner_quot() const {
|
||||||
{
|
tagged<object> executing(owner);
|
||||||
tagged<object> executing(owner);
|
if (!optimized_p() && executing->type() == WORD_TYPE)
|
||||||
if (!optimized_p() && executing->type() == WORD_TYPE)
|
executing = executing.as<word>()->def;
|
||||||
executing = executing.as<word>()->def;
|
return executing.value();
|
||||||
return executing.value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cell code_block::scan(factor_vm *vm, void *addr) const
|
cell code_block::scan(factor_vm* vm, void* addr) const {
|
||||||
{
|
switch (type()) {
|
||||||
switch(type())
|
case code_block_unoptimized: {
|
||||||
{
|
tagged<object> obj(owner);
|
||||||
case code_block_unoptimized:
|
if (obj.type_p(WORD_TYPE))
|
||||||
{
|
obj = obj.as<word>()->def;
|
||||||
tagged<object> obj(owner);
|
|
||||||
if(obj.type_p(WORD_TYPE))
|
|
||||||
obj = obj.as<word>()->def;
|
|
||||||
|
|
||||||
if(obj.type_p(QUOTATION_TYPE))
|
if (obj.type_p(QUOTATION_TYPE))
|
||||||
return tag_fixnum(vm->quot_code_offset_to_scan(obj.value(),offset(addr)));
|
return tag_fixnum(
|
||||||
else
|
vm->quot_code_offset_to_scan(obj.value(), offset(addr)));
|
||||||
return false_object;
|
else
|
||||||
}
|
return false_object;
|
||||||
case code_block_optimized:
|
}
|
||||||
case code_block_pic:
|
case code_block_optimized:
|
||||||
return false_object;
|
case code_block_pic:
|
||||||
default:
|
return false_object;
|
||||||
critical_error("Bad frame type",type());
|
default:
|
||||||
return false_object;
|
critical_error("Bad frame type", type());
|
||||||
}
|
return false_object;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cell factor_vm::compute_entry_point_address(cell obj)
|
cell factor_vm::compute_entry_point_address(cell obj) {
|
||||||
{
|
switch (tagged<object>(obj).type()) {
|
||||||
switch(tagged<object>(obj).type())
|
case WORD_TYPE:
|
||||||
{
|
return (cell) untag<word>(obj)->entry_point;
|
||||||
case WORD_TYPE:
|
case QUOTATION_TYPE:
|
||||||
return (cell)untag<word>(obj)->entry_point;
|
return (cell) untag<quotation>(obj)->entry_point;
|
||||||
case QUOTATION_TYPE:
|
default:
|
||||||
return (cell)untag<quotation>(obj)->entry_point;
|
critical_error("Expected word or quotation", obj);
|
||||||
default:
|
return 0;
|
||||||
critical_error("Expected word or quotation",obj);
|
}
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cell factor_vm::compute_entry_point_pic_address(word *w, cell tagged_quot)
|
cell factor_vm::compute_entry_point_pic_address(word* w, cell tagged_quot) {
|
||||||
{
|
if (!to_boolean(tagged_quot) || max_pic_size == 0)
|
||||||
if(!to_boolean(tagged_quot) || max_pic_size == 0)
|
return (cell) w->entry_point;
|
||||||
return (cell)w->entry_point;
|
else {
|
||||||
else
|
quotation* quot = untag<quotation>(tagged_quot);
|
||||||
{
|
if (quot_compiled_p(quot))
|
||||||
quotation *quot = untag<quotation>(tagged_quot);
|
return (cell) quot->entry_point;
|
||||||
if(quot_compiled_p(quot))
|
else
|
||||||
return (cell)quot->entry_point;
|
return (cell) w->entry_point;
|
||||||
else
|
}
|
||||||
return (cell)w->entry_point;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cell factor_vm::compute_entry_point_pic_address(cell w_)
|
cell factor_vm::compute_entry_point_pic_address(cell w_) {
|
||||||
{
|
tagged<word> w(w_);
|
||||||
tagged<word> w(w_);
|
return compute_entry_point_pic_address(w.untagged(), w->pic_def);
|
||||||
return compute_entry_point_pic_address(w.untagged(),w->pic_def);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cell factor_vm::compute_entry_point_pic_tail_address(cell w_)
|
cell factor_vm::compute_entry_point_pic_tail_address(cell w_) {
|
||||||
{
|
tagged<word> w(w_);
|
||||||
tagged<word> w(w_);
|
return compute_entry_point_pic_address(w.untagged(), w->pic_tail_def);
|
||||||
return compute_entry_point_pic_address(w.untagged(),w->pic_tail_def);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cell factor_vm::code_block_owner(code_block *compiled)
|
cell factor_vm::code_block_owner(code_block* compiled) {
|
||||||
{
|
tagged<object> owner(compiled->owner);
|
||||||
tagged<object> owner(compiled->owner);
|
|
||||||
|
|
||||||
/* Cold generic word call sites point to quotations that call the
|
/* Cold generic word call sites point to quotations that call the
|
||||||
inline-cache-miss and inline-cache-miss-tail primitives. */
|
inline-cache-miss and inline-cache-miss-tail primitives. */
|
||||||
if(owner.type_p(QUOTATION_TYPE))
|
if (owner.type_p(QUOTATION_TYPE)) {
|
||||||
{
|
tagged<quotation> quot(owner.as<quotation>());
|
||||||
tagged<quotation> quot(owner.as<quotation>());
|
tagged<array> elements(quot->array);
|
||||||
tagged<array> elements(quot->array);
|
|
||||||
#ifdef FACTOR_DEBUG
|
#ifdef FACTOR_DEBUG
|
||||||
FACTOR_ASSERT(array_capacity(elements.untagged()) == 5);
|
FACTOR_ASSERT(array_capacity(elements.untagged()) == 5);
|
||||||
FACTOR_ASSERT(array_nth(elements.untagged(),4) == special_objects[PIC_MISS_WORD]
|
FACTOR_ASSERT(array_nth(elements.untagged(), 4) ==
|
||||||
|| array_nth(elements.untagged(),4) == special_objects[PIC_MISS_TAIL_WORD]);
|
special_objects[PIC_MISS_WORD] ||
|
||||||
|
array_nth(elements.untagged(), 4) ==
|
||||||
|
special_objects[PIC_MISS_TAIL_WORD]);
|
||||||
#endif
|
#endif
|
||||||
tagged<wrapper> word_wrapper(array_nth(elements.untagged(),0));
|
tagged<wrapper> word_wrapper(array_nth(elements.untagged(), 0));
|
||||||
return word_wrapper->object;
|
return word_wrapper->object;
|
||||||
}
|
} else
|
||||||
else
|
return compiled->owner;
|
||||||
return compiled->owner;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct update_word_references_relocation_visitor {
|
struct update_word_references_relocation_visitor {
|
||||||
factor_vm *parent;
|
factor_vm* parent;
|
||||||
bool reset_inline_caches;
|
bool reset_inline_caches;
|
||||||
|
|
||||||
update_word_references_relocation_visitor(
|
update_word_references_relocation_visitor(factor_vm* parent_,
|
||||||
factor_vm *parent_,
|
bool reset_inline_caches_)
|
||||||
bool reset_inline_caches_) :
|
: parent(parent_), reset_inline_caches(reset_inline_caches_) {}
|
||||||
parent(parent_),
|
|
||||||
reset_inline_caches(reset_inline_caches_) {}
|
|
||||||
|
|
||||||
void operator()(instruction_operand op)
|
void operator()(instruction_operand op) {
|
||||||
{
|
switch (op.rel_type()) {
|
||||||
switch(op.rel_type())
|
case RT_ENTRY_POINT: {
|
||||||
{
|
code_block* compiled = op.load_code_block();
|
||||||
case RT_ENTRY_POINT:
|
cell owner = compiled->owner;
|
||||||
{
|
if (to_boolean(owner))
|
||||||
code_block *compiled = op.load_code_block();
|
op.store_value(parent->compute_entry_point_address(owner));
|
||||||
cell owner = compiled->owner;
|
break;
|
||||||
if(to_boolean(owner))
|
}
|
||||||
op.store_value(parent->compute_entry_point_address(owner));
|
case RT_ENTRY_POINT_PIC: {
|
||||||
break;
|
code_block* compiled = op.load_code_block();
|
||||||
}
|
if (reset_inline_caches || !compiled->pic_p()) {
|
||||||
case RT_ENTRY_POINT_PIC:
|
cell owner = parent->code_block_owner(compiled);
|
||||||
{
|
if (to_boolean(owner))
|
||||||
code_block *compiled = op.load_code_block();
|
op.store_value(parent->compute_entry_point_pic_address(owner));
|
||||||
if(reset_inline_caches || !compiled->pic_p())
|
}
|
||||||
{
|
break;
|
||||||
cell owner = parent->code_block_owner(compiled);
|
}
|
||||||
if(to_boolean(owner))
|
case RT_ENTRY_POINT_PIC_TAIL: {
|
||||||
op.store_value(parent->compute_entry_point_pic_address(owner));
|
code_block* compiled = op.load_code_block();
|
||||||
}
|
if (reset_inline_caches || !compiled->pic_p()) {
|
||||||
break;
|
cell owner = parent->code_block_owner(compiled);
|
||||||
}
|
if (to_boolean(owner))
|
||||||
case RT_ENTRY_POINT_PIC_TAIL:
|
op.store_value(parent->compute_entry_point_pic_tail_address(owner));
|
||||||
{
|
}
|
||||||
code_block *compiled = op.load_code_block();
|
break;
|
||||||
if(reset_inline_caches || !compiled->pic_p())
|
}
|
||||||
{
|
default:
|
||||||
cell owner = parent->code_block_owner(compiled);
|
break;
|
||||||
if(to_boolean(owner))
|
}
|
||||||
op.store_value(parent->compute_entry_point_pic_tail_address(owner));
|
}
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Relocate new code blocks completely; updating references to literals,
|
/* Relocate new code blocks completely; updating references to literals,
|
||||||
dlsyms, and words. For all other words in the code heap, we only need
|
dlsyms, and words. For all other words in the code heap, we only need
|
||||||
to update references to other words, without worrying about literals
|
to update references to other words, without worrying about literals
|
||||||
or dlsyms. */
|
or dlsyms. */
|
||||||
void factor_vm::update_word_references(code_block *compiled, bool reset_inline_caches)
|
void factor_vm::update_word_references(code_block* compiled,
|
||||||
{
|
bool reset_inline_caches) {
|
||||||
if(code->uninitialized_p(compiled))
|
if (code->uninitialized_p(compiled))
|
||||||
initialize_code_block(compiled);
|
initialize_code_block(compiled);
|
||||||
/* update_word_references() is always applied to every block in
|
/* update_word_references() is always applied to every block in
|
||||||
the code heap. Since it resets all call sites to point to
|
the code heap. Since it resets all call sites to point to
|
||||||
their canonical entry point (cold entry point for non-tail calls,
|
their canonical entry point (cold entry point for non-tail calls,
|
||||||
standard entry point for tail calls), it means that no PICs
|
standard entry point for tail calls), it means that no PICs
|
||||||
are referenced after this is done. So instead of polluting
|
are referenced after this is done. So instead of polluting
|
||||||
the code heap with dead PICs that will be freed on the next
|
the code heap with dead PICs that will be freed on the next
|
||||||
GC, we add them to the free list immediately. */
|
GC, we add them to the free list immediately. */
|
||||||
else if(reset_inline_caches && compiled->pic_p())
|
else if (reset_inline_caches && compiled->pic_p())
|
||||||
code->free(compiled);
|
code->free(compiled);
|
||||||
else
|
else {
|
||||||
{
|
update_word_references_relocation_visitor visitor(this,
|
||||||
update_word_references_relocation_visitor visitor(this,reset_inline_caches);
|
reset_inline_caches);
|
||||||
compiled->each_instruction_operand(visitor);
|
compiled->each_instruction_operand(visitor);
|
||||||
compiled->flush_icache();
|
compiled->flush_icache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Look up an external library symbol referenced by a compiled code block */
|
/* Look up an external library symbol referenced by a compiled code block */
|
||||||
cell factor_vm::compute_dlsym_address(array *parameters, cell index)
|
cell factor_vm::compute_dlsym_address(array* parameters, cell index) {
|
||||||
{
|
cell symbol = array_nth(parameters, index);
|
||||||
cell symbol = array_nth(parameters,index);
|
cell library = array_nth(parameters, index + 1);
|
||||||
cell library = array_nth(parameters,index + 1);
|
|
||||||
|
|
||||||
dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
|
dll* d = (to_boolean(library) ? untag<dll>(library) : NULL);
|
||||||
|
|
||||||
void* undefined_symbol = (void*)factor::undefined_symbol;
|
void* undefined_symbol = (void*)factor::undefined_symbol;
|
||||||
undefined_symbol = FUNCTION_CODE_POINTER(undefined_symbol);
|
undefined_symbol = FUNCTION_CODE_POINTER(undefined_symbol);
|
||||||
if(d != NULL && !d->handle)
|
if (d != NULL && !d->handle)
|
||||||
return (cell)undefined_symbol;
|
return (cell) undefined_symbol;
|
||||||
|
|
||||||
switch(tagged<object>(symbol).type())
|
switch (tagged<object>(symbol).type()) {
|
||||||
{
|
case BYTE_ARRAY_TYPE: {
|
||||||
case BYTE_ARRAY_TYPE:
|
symbol_char* name = alien_offset(symbol);
|
||||||
{
|
void* sym = ffi_dlsym(d, name);
|
||||||
symbol_char *name = alien_offset(symbol);
|
|
||||||
void *sym = ffi_dlsym(d,name);
|
|
||||||
|
|
||||||
if(sym)
|
if (sym)
|
||||||
return (cell)sym;
|
return (cell) sym;
|
||||||
else
|
else
|
||||||
return (cell)undefined_symbol;
|
return (cell) undefined_symbol;
|
||||||
}
|
}
|
||||||
case ARRAY_TYPE:
|
case ARRAY_TYPE: {
|
||||||
{
|
array* names = untag<array>(symbol);
|
||||||
array *names = untag<array>(symbol);
|
for (cell i = 0; i < array_capacity(names); i++) {
|
||||||
for(cell i = 0; i < array_capacity(names); i++)
|
symbol_char* name = alien_offset(array_nth(names, i));
|
||||||
{
|
void* sym = ffi_dlsym(d, name);
|
||||||
symbol_char *name = alien_offset(array_nth(names,i));
|
|
||||||
void *sym = ffi_dlsym(d,name);
|
|
||||||
|
|
||||||
if(sym)
|
if (sym)
|
||||||
return (cell)sym;
|
return (cell) sym;
|
||||||
}
|
}
|
||||||
return (cell)undefined_symbol;
|
return (cell) undefined_symbol;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
critical_error("Bad symbol specifier",symbol);
|
critical_error("Bad symbol specifier", symbol);
|
||||||
return (cell)undefined_symbol;
|
return (cell) undefined_symbol;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef FACTOR_PPC
|
#ifdef FACTOR_PPC
|
||||||
cell factor_vm::compute_dlsym_toc_address(array *parameters, cell index)
|
cell factor_vm::compute_dlsym_toc_address(array* parameters, cell index) {
|
||||||
{
|
cell symbol = array_nth(parameters, index);
|
||||||
cell symbol = array_nth(parameters,index);
|
cell library = array_nth(parameters, index + 1);
|
||||||
cell library = array_nth(parameters,index + 1);
|
|
||||||
|
|
||||||
dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
|
dll* d = (to_boolean(library) ? untag<dll>(library) : NULL);
|
||||||
|
|
||||||
void* undefined_toc = (void*)factor::undefined_symbol;
|
void* undefined_toc = (void*)factor::undefined_symbol;
|
||||||
undefined_toc = FUNCTION_TOC_POINTER(undefined_toc);
|
undefined_toc = FUNCTION_TOC_POINTER(undefined_toc);
|
||||||
if(d != NULL && !d->handle)
|
if (d != NULL && !d->handle)
|
||||||
return (cell)undefined_toc;
|
return (cell) undefined_toc;
|
||||||
|
|
||||||
switch(tagged<object>(symbol).type())
|
switch (tagged<object>(symbol).type()) {
|
||||||
{
|
case BYTE_ARRAY_TYPE: {
|
||||||
case BYTE_ARRAY_TYPE:
|
symbol_char* name = alien_offset(symbol);
|
||||||
{
|
void* toc = ffi_dlsym_toc(d, name);
|
||||||
symbol_char *name = alien_offset(symbol);
|
if (toc)
|
||||||
void* toc = ffi_dlsym_toc(d,name);
|
return (cell) toc;
|
||||||
if(toc)
|
else
|
||||||
return (cell)toc;
|
return (cell) undefined_toc;
|
||||||
else
|
}
|
||||||
return (cell)undefined_toc;
|
case ARRAY_TYPE: {
|
||||||
}
|
array* names = untag<array>(symbol);
|
||||||
case ARRAY_TYPE:
|
for (cell i = 0; i < array_capacity(names); i++) {
|
||||||
{
|
symbol_char* name = alien_offset(array_nth(names, i));
|
||||||
array *names = untag<array>(symbol);
|
void* toc = ffi_dlsym_toc(d, name);
|
||||||
for(cell i = 0; i < array_capacity(names); i++)
|
|
||||||
{
|
|
||||||
symbol_char *name = alien_offset(array_nth(names,i));
|
|
||||||
void *toc = ffi_dlsym_toc(d,name);
|
|
||||||
|
|
||||||
if(toc)
|
if (toc)
|
||||||
return (cell)toc;
|
return (cell) toc;
|
||||||
}
|
}
|
||||||
return (cell)undefined_toc;
|
return (cell) undefined_toc;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
critical_error("Bad symbol specifier",symbol);
|
critical_error("Bad symbol specifier", symbol);
|
||||||
return (cell)undefined_toc;
|
return (cell) undefined_toc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cell factor_vm::compute_vm_address(cell arg)
|
cell factor_vm::compute_vm_address(cell arg) {
|
||||||
{
|
return (cell) this + untag_fixnum(arg);
|
||||||
return (cell)this + untag_fixnum(arg);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::store_external_address(instruction_operand op)
|
void factor_vm::store_external_address(instruction_operand op) {
|
||||||
{
|
code_block* compiled = op.compiled;
|
||||||
code_block *compiled = op.compiled;
|
array* parameters =
|
||||||
array *parameters = (to_boolean(compiled->parameters) ? untag<array>(compiled->parameters) : NULL);
|
(to_boolean(compiled->parameters) ? untag<array>(compiled->parameters)
|
||||||
cell index = op.index;
|
: NULL);
|
||||||
|
cell index = op.index;
|
||||||
|
|
||||||
switch(op.rel_type())
|
switch (op.rel_type()) {
|
||||||
{
|
case RT_DLSYM:
|
||||||
case RT_DLSYM:
|
op.store_value(compute_dlsym_address(parameters, index));
|
||||||
op.store_value(compute_dlsym_address(parameters,index));
|
break;
|
||||||
break;
|
case RT_THIS:
|
||||||
case RT_THIS:
|
op.store_value((cell) compiled->entry_point());
|
||||||
op.store_value((cell)compiled->entry_point());
|
break;
|
||||||
break;
|
case RT_MEGAMORPHIC_CACHE_HITS:
|
||||||
case RT_MEGAMORPHIC_CACHE_HITS:
|
op.store_value((cell) & dispatch_stats.megamorphic_cache_hits);
|
||||||
op.store_value((cell)&dispatch_stats.megamorphic_cache_hits);
|
break;
|
||||||
break;
|
case RT_VM:
|
||||||
case RT_VM:
|
op.store_value(compute_vm_address(array_nth(parameters, index)));
|
||||||
op.store_value(compute_vm_address(array_nth(parameters,index)));
|
break;
|
||||||
break;
|
case RT_CARDS_OFFSET:
|
||||||
case RT_CARDS_OFFSET:
|
op.store_value(cards_offset);
|
||||||
op.store_value(cards_offset);
|
break;
|
||||||
break;
|
case RT_DECKS_OFFSET:
|
||||||
case RT_DECKS_OFFSET:
|
op.store_value(decks_offset);
|
||||||
op.store_value(decks_offset);
|
break;
|
||||||
break;
|
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
case RT_EXCEPTION_HANDLER:
|
case RT_EXCEPTION_HANDLER:
|
||||||
op.store_value((cell)&factor::exception_handler);
|
op.store_value((cell) & factor::exception_handler);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef FACTOR_PPC
|
#ifdef FACTOR_PPC
|
||||||
case RT_DLSYM_TOC:
|
case RT_DLSYM_TOC:
|
||||||
op.store_value(compute_dlsym_toc_address(parameters,index));
|
op.store_value(compute_dlsym_toc_address(parameters, index));
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
case RT_INLINE_CACHE_MISS:
|
case RT_INLINE_CACHE_MISS:
|
||||||
op.store_value((cell)&factor::inline_cache_miss);
|
op.store_value((cell) & factor::inline_cache_miss);
|
||||||
break;
|
break;
|
||||||
case RT_SAFEPOINT:
|
case RT_SAFEPOINT:
|
||||||
op.store_value((cell)code->safepoint_page);
|
op.store_value((cell) code->safepoint_page);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
critical_error("Bad rel type in store_external_address()",op.rel_type());
|
critical_error("Bad rel type in store_external_address()", op.rel_type());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cell factor_vm::compute_here_address(cell arg, cell offset, code_block *compiled)
|
cell factor_vm::compute_here_address(cell arg, cell offset,
|
||||||
{
|
code_block* compiled) {
|
||||||
fixnum n = untag_fixnum(arg);
|
fixnum n = untag_fixnum(arg);
|
||||||
if(n >= 0)
|
if (n >= 0)
|
||||||
return (cell)compiled->entry_point() + offset + n;
|
return (cell) compiled->entry_point() + offset + n;
|
||||||
else
|
else
|
||||||
return (cell)compiled->entry_point() - n;
|
return (cell) compiled->entry_point() - n;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct initial_code_block_visitor {
|
struct initial_code_block_visitor {
|
||||||
factor_vm *parent;
|
factor_vm* parent;
|
||||||
cell literals;
|
cell literals;
|
||||||
cell literal_index;
|
cell literal_index;
|
||||||
|
|
||||||
explicit initial_code_block_visitor(factor_vm *parent_, cell literals_)
|
explicit initial_code_block_visitor(factor_vm* parent_, cell literals_)
|
||||||
: parent(parent_), literals(literals_), literal_index(0) {}
|
: parent(parent_), literals(literals_), literal_index(0) {}
|
||||||
|
|
||||||
cell next_literal()
|
cell next_literal() {
|
||||||
{
|
return array_nth(untag<array>(literals), literal_index++);
|
||||||
return array_nth(untag<array>(literals),literal_index++);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void operator()(instruction_operand op)
|
void operator()(instruction_operand op) {
|
||||||
{
|
switch (op.rel_type()) {
|
||||||
switch(op.rel_type())
|
case RT_LITERAL:
|
||||||
{
|
op.store_value(next_literal());
|
||||||
case RT_LITERAL:
|
break;
|
||||||
op.store_value(next_literal());
|
case RT_ENTRY_POINT:
|
||||||
break;
|
op.store_value(parent->compute_entry_point_address(next_literal()));
|
||||||
case RT_ENTRY_POINT:
|
break;
|
||||||
op.store_value(parent->compute_entry_point_address(next_literal()));
|
case RT_ENTRY_POINT_PIC:
|
||||||
break;
|
op.store_value(parent->compute_entry_point_pic_address(next_literal()));
|
||||||
case RT_ENTRY_POINT_PIC:
|
break;
|
||||||
op.store_value(parent->compute_entry_point_pic_address(next_literal()));
|
case RT_ENTRY_POINT_PIC_TAIL:
|
||||||
break;
|
op.store_value(
|
||||||
case RT_ENTRY_POINT_PIC_TAIL:
|
parent->compute_entry_point_pic_tail_address(next_literal()));
|
||||||
op.store_value(parent->compute_entry_point_pic_tail_address(next_literal()));
|
break;
|
||||||
break;
|
case RT_HERE:
|
||||||
case RT_HERE:
|
op.store_value(parent->compute_here_address(
|
||||||
op.store_value(parent->compute_here_address(next_literal(),op.rel_offset(),op.compiled));
|
next_literal(), op.rel_offset(), op.compiled));
|
||||||
break;
|
break;
|
||||||
case RT_UNTAGGED:
|
case RT_UNTAGGED:
|
||||||
op.store_value(untag_fixnum(next_literal()));
|
op.store_value(untag_fixnum(next_literal()));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
parent->store_external_address(op);
|
parent->store_external_address(op);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Perform all fixups on a code block */
|
/* Perform all fixups on a code block */
|
||||||
void factor_vm::initialize_code_block(code_block *compiled, cell literals)
|
void factor_vm::initialize_code_block(code_block* compiled, cell literals) {
|
||||||
{
|
initial_code_block_visitor visitor(this, literals);
|
||||||
initial_code_block_visitor visitor(this,literals);
|
compiled->each_instruction_operand(visitor);
|
||||||
compiled->each_instruction_operand(visitor);
|
compiled->flush_icache();
|
||||||
compiled->flush_icache();
|
|
||||||
|
|
||||||
/* next time we do a minor GC, we have to trace this code block, since
|
/* next time we do a minor GC, we have to trace this code block, since
|
||||||
the newly-installed instruction operands might point to literals in
|
the newly-installed instruction operands might point to literals in
|
||||||
nursery or aging */
|
nursery or aging */
|
||||||
code->write_barrier(compiled);
|
code->write_barrier(compiled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::initialize_code_block(code_block *compiled)
|
void factor_vm::initialize_code_block(code_block* compiled) {
|
||||||
{
|
std::map<code_block*, cell>::iterator iter =
|
||||||
std::map<code_block *,cell>::iterator iter = code->uninitialized_blocks.find(compiled);
|
code->uninitialized_blocks.find(compiled);
|
||||||
initialize_code_block(compiled,iter->second);
|
initialize_code_block(compiled, iter->second);
|
||||||
code->uninitialized_blocks.erase(iter);
|
code->uninitialized_blocks.erase(iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fixup labels. This is done at compile time, not image load time */
|
/* Fixup labels. This is done at compile time, not image load time */
|
||||||
void factor_vm::fixup_labels(array *labels, code_block *compiled)
|
void factor_vm::fixup_labels(array* labels, code_block* compiled) {
|
||||||
{
|
cell size = array_capacity(labels);
|
||||||
cell size = array_capacity(labels);
|
|
||||||
|
|
||||||
for(cell i = 0; i < size; i += 3)
|
for (cell i = 0; i < size; i += 3) {
|
||||||
{
|
relocation_class rel_class =
|
||||||
relocation_class rel_class = (relocation_class)untag_fixnum(array_nth(labels,i));
|
(relocation_class) untag_fixnum(array_nth(labels, i));
|
||||||
cell offset = untag_fixnum(array_nth(labels,i + 1));
|
cell offset = untag_fixnum(array_nth(labels, i + 1));
|
||||||
cell target = untag_fixnum(array_nth(labels,i + 2));
|
cell target = untag_fixnum(array_nth(labels, i + 2));
|
||||||
|
|
||||||
relocation_entry new_entry(RT_HERE,rel_class,offset);
|
relocation_entry new_entry(RT_HERE, rel_class, offset);
|
||||||
|
|
||||||
instruction_operand op(new_entry,compiled,0);
|
instruction_operand op(new_entry, compiled, 0);
|
||||||
op.store_value(target + (cell)compiled->entry_point());
|
op.store_value(target + (cell) compiled->entry_point());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Might GC */
|
/* Might GC */
|
||||||
/* Allocates memory */
|
/* Allocates memory */
|
||||||
code_block *factor_vm::allot_code_block(cell size, code_block_type type)
|
code_block* factor_vm::allot_code_block(cell size, code_block_type type) {
|
||||||
{
|
code_block* block = code->allocator->allot(size + sizeof(code_block));
|
||||||
code_block *block = code->allocator->allot(size + sizeof(code_block));
|
|
||||||
|
|
||||||
/* If allocation failed, do a full GC and compact the code heap.
|
/* If allocation failed, do a full GC and compact the code heap.
|
||||||
A full GC that occurs as a result of the data heap filling up does not
|
A full GC that occurs as a result of the data heap filling up does not
|
||||||
trigger a compaction. This setup ensures that most GCs do not compact
|
trigger a compaction. This setup ensures that most GCs do not compact
|
||||||
the code heap, but if the code fills up, it probably means it will be
|
the code heap, but if the code fills up, it probably means it will be
|
||||||
fragmented after GC anyway, so its best to compact. */
|
fragmented after GC anyway, so its best to compact. */
|
||||||
if(block == NULL)
|
if (block == NULL) {
|
||||||
{
|
primitive_compact_gc();
|
||||||
primitive_compact_gc();
|
block = code->allocator->allot(size + sizeof(code_block));
|
||||||
block = code->allocator->allot(size + sizeof(code_block));
|
|
||||||
|
|
||||||
/* Insufficient room even after code GC, give up */
|
/* Insufficient room even after code GC, give up */
|
||||||
if(block == NULL)
|
if (block == NULL) {
|
||||||
{
|
std::cout << "Code heap used: " << code->allocator->occupied_space()
|
||||||
std::cout << "Code heap used: " << code->allocator->occupied_space() << "\n";
|
<< "\n";
|
||||||
std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
|
std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
|
||||||
fatal_error("Out of memory in add-compiled-block",0);
|
fatal_error("Out of memory in add-compiled-block", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
block->set_type(type);
|
block->set_type(type);
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Might GC */
|
/* Might GC */
|
||||||
/* Allocates memory */
|
/* Allocates memory */
|
||||||
code_block *factor_vm::add_code_block(code_block_type type, cell code_, cell labels_,
|
code_block* factor_vm::add_code_block(code_block_type type, cell code_,
|
||||||
cell owner_, cell relocation_, cell parameters_, cell literals_,
|
cell labels_, cell owner_,
|
||||||
cell frame_size_untagged)
|
cell relocation_, cell parameters_,
|
||||||
{
|
cell literals_,
|
||||||
data_root<byte_array> code(code_,this);
|
cell frame_size_untagged) {
|
||||||
data_root<object> labels(labels_,this);
|
data_root<byte_array> code(code_, this);
|
||||||
data_root<object> owner(owner_,this);
|
data_root<object> labels(labels_, this);
|
||||||
data_root<byte_array> relocation(relocation_,this);
|
data_root<object> owner(owner_, this);
|
||||||
data_root<array> parameters(parameters_,this);
|
data_root<byte_array> relocation(relocation_, this);
|
||||||
data_root<array> literals(literals_,this);
|
data_root<array> parameters(parameters_, this);
|
||||||
|
data_root<array> literals(literals_, this);
|
||||||
|
|
||||||
cell code_length = array_capacity(code.untagged());
|
cell code_length = array_capacity(code.untagged());
|
||||||
code_block *compiled = allot_code_block(code_length,type);
|
code_block* compiled = allot_code_block(code_length, type);
|
||||||
|
|
||||||
compiled->owner = owner.value();
|
compiled->owner = owner.value();
|
||||||
|
|
||||||
/* slight space optimization */
|
/* slight space optimization */
|
||||||
if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0)
|
if (relocation.type() == BYTE_ARRAY_TYPE &&
|
||||||
compiled->relocation = false_object;
|
array_capacity(relocation.untagged()) == 0)
|
||||||
else
|
compiled->relocation = false_object;
|
||||||
compiled->relocation = relocation.value();
|
else
|
||||||
|
compiled->relocation = relocation.value();
|
||||||
|
|
||||||
if(parameters.type() == ARRAY_TYPE && array_capacity(parameters.untagged()) == 0)
|
if (parameters.type() == ARRAY_TYPE &&
|
||||||
compiled->parameters = false_object;
|
array_capacity(parameters.untagged()) == 0)
|
||||||
else
|
compiled->parameters = false_object;
|
||||||
compiled->parameters = parameters.value();
|
else
|
||||||
|
compiled->parameters = parameters.value();
|
||||||
|
|
||||||
/* code */
|
/* code */
|
||||||
memcpy(compiled + 1,code.untagged() + 1,code_length);
|
memcpy(compiled + 1, code.untagged() + 1, code_length);
|
||||||
|
|
||||||
/* fixup labels */
|
/* fixup labels */
|
||||||
if(to_boolean(labels.value()))
|
if (to_boolean(labels.value()))
|
||||||
fixup_labels(labels.as<array>().untagged(),compiled);
|
fixup_labels(labels.as<array>().untagged(), compiled);
|
||||||
|
|
||||||
compiled->set_stack_frame_size(frame_size_untagged);
|
compiled->set_stack_frame_size(frame_size_untagged);
|
||||||
|
|
||||||
/* Once we are ready, fill in literal and word references in this code
|
/* Once we are ready, fill in literal and word references in this code
|
||||||
block's instruction operands. In most cases this is done right after this
|
block's instruction operands. In most cases this is done right after this
|
||||||
method returns, except when compiling words with the non-optimizing
|
method returns, except when compiling words with the non-optimizing
|
||||||
compiler at the beginning of bootstrap */
|
compiler at the beginning of bootstrap */
|
||||||
this->code->uninitialized_blocks.insert(std::make_pair(compiled,literals.value()));
|
this->code->uninitialized_blocks
|
||||||
this->code->all_blocks.insert((cell)compiled);
|
.insert(std::make_pair(compiled, literals.value()));
|
||||||
|
this->code->all_blocks.insert((cell) compiled);
|
||||||
|
|
||||||
/* next time we do a minor GC, we have to trace this code block, since
|
/* next time we do a minor GC, we have to trace this code block, since
|
||||||
the fields of the code_block struct might point into nursery or aging */
|
the fields of the code_block struct might point into nursery or aging */
|
||||||
this->code->write_barrier(compiled);
|
this->code->write_barrier(compiled);
|
||||||
|
|
||||||
return compiled;
|
return compiled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find the RT_DLSYM relocation nearest to the given return address. */
|
/* Find the RT_DLSYM relocation nearest to the given return address. */
|
||||||
struct find_symbol_at_address_visitor {
|
struct find_symbol_at_address_visitor {
|
||||||
factor_vm *parent;
|
factor_vm* parent;
|
||||||
cell return_address;
|
cell return_address;
|
||||||
cell symbol;
|
cell symbol;
|
||||||
cell library;
|
cell library;
|
||||||
|
|
||||||
find_symbol_at_address_visitor(factor_vm *parent_, cell return_address_) :
|
find_symbol_at_address_visitor(factor_vm* parent_, cell return_address_)
|
||||||
parent(parent_), return_address(return_address_),
|
: parent(parent_),
|
||||||
symbol(false_object), library(false_object) { }
|
return_address(return_address_),
|
||||||
|
symbol(false_object),
|
||||||
|
library(false_object) {}
|
||||||
|
|
||||||
void operator()(instruction_operand op)
|
void operator()(instruction_operand op) {
|
||||||
{
|
if (op.rel_type() == RT_DLSYM && op.pointer <= return_address) {
|
||||||
if(op.rel_type() == RT_DLSYM && op.pointer <= return_address)
|
code_block* compiled = op.compiled;
|
||||||
{
|
array* parameters = untag<array>(compiled->parameters);
|
||||||
code_block *compiled = op.compiled;
|
cell index = op.index;
|
||||||
array *parameters = untag<array>(compiled->parameters);
|
symbol = array_nth(parameters, index);
|
||||||
cell index = op.index;
|
library = array_nth(parameters, index + 1);
|
||||||
symbol = array_nth(parameters,index);
|
}
|
||||||
library = array_nth(parameters,index + 1);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* References to undefined symbols are patched up to call this function on
|
/* References to undefined symbols are patched up to call this function on
|
||||||
image load. It finds the symbol and library, and throws an error. */
|
image load. It finds the symbol and library, and throws an error. */
|
||||||
void factor_vm::undefined_symbol()
|
void factor_vm::undefined_symbol() {
|
||||||
{
|
void* frame = ctx->callstack_top;
|
||||||
void *frame = ctx->callstack_top;
|
void* return_address = frame_return_address(frame);
|
||||||
void *return_address = frame_return_address(frame);
|
code_block* compiled = code->code_block_for_address((cell) return_address);
|
||||||
code_block *compiled = code->code_block_for_address((cell)return_address);
|
find_symbol_at_address_visitor visitor(this, (cell) return_address);
|
||||||
find_symbol_at_address_visitor visitor(this, (cell)return_address);
|
compiled->each_instruction_operand(visitor);
|
||||||
compiled->each_instruction_operand(visitor);
|
if (!to_boolean(visitor.symbol))
|
||||||
if (!to_boolean(visitor.symbol))
|
critical_error("Can't find RT_DLSYM at return address",
|
||||||
critical_error("Can't find RT_DLSYM at return address", (cell)return_address);
|
(cell) return_address);
|
||||||
else
|
else
|
||||||
general_error(ERROR_UNDEFINED_SYMBOL,visitor.symbol,visitor.library);
|
general_error(ERROR_UNDEFINED_SYMBOL, visitor.symbol, visitor.library);
|
||||||
}
|
}
|
||||||
|
|
||||||
void undefined_symbol()
|
void undefined_symbol() { return current_vm()->undefined_symbol(); }
|
||||||
{
|
|
||||||
return current_vm()->undefined_symbol();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,153 +1,117 @@
|
||||||
namespace factor
|
namespace factor {
|
||||||
{
|
|
||||||
|
|
||||||
/* The compiled code heap is structured into blocks. */
|
/* The compiled code heap is structured into blocks. */
|
||||||
struct code_block
|
struct code_block {
|
||||||
{
|
// header format (bits indexed with least significant as zero):
|
||||||
// header format (bits indexed with least significant as zero):
|
// bit 0 : free?
|
||||||
// bit 0 : free?
|
// bits 1-2: type (as a code_block_type)
|
||||||
// bits 1-2: type (as a code_block_type)
|
// if not free:
|
||||||
// if not free:
|
// bits 3-23: code size / 8
|
||||||
// bits 3-23: code size / 8
|
// bits 24-31: stack frame size / 16
|
||||||
// bits 24-31: stack frame size / 16
|
// if free:
|
||||||
// if free:
|
// bits 3-end: code size / 8
|
||||||
// bits 3-end: code size / 8
|
cell header;
|
||||||
cell header;
|
cell owner; /* tagged pointer to word, quotation or f */
|
||||||
cell owner; /* tagged pointer to word, quotation or f */
|
cell parameters; /* tagged pointer to array or f */
|
||||||
cell parameters; /* tagged pointer to array or f */
|
cell relocation; /* tagged pointer to byte-array or f */
|
||||||
cell relocation; /* tagged pointer to byte-array or f */
|
|
||||||
|
|
||||||
bool free_p() const
|
bool free_p() const { return (header & 1) == 1; }
|
||||||
{
|
|
||||||
return (header & 1) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
code_block_type type() const
|
code_block_type type() const {
|
||||||
{
|
return (code_block_type)((header >> 1) & 0x3);
|
||||||
return (code_block_type)((header >> 1) & 0x3);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void set_type(code_block_type type)
|
void set_type(code_block_type type) {
|
||||||
{
|
header = ((header & ~0x7) | (type << 1));
|
||||||
header = ((header & ~0x7) | (type << 1));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
bool pic_p() const
|
bool pic_p() const { return type() == code_block_pic; }
|
||||||
{
|
|
||||||
return type() == code_block_pic;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool optimized_p() const
|
bool optimized_p() const { return type() == code_block_optimized; }
|
||||||
{
|
|
||||||
return type() == code_block_optimized;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell size() const
|
cell size() const {
|
||||||
{
|
cell size;
|
||||||
cell size;
|
if (free_p())
|
||||||
if (free_p())
|
size = header & ~7;
|
||||||
size = header & ~7;
|
else
|
||||||
else
|
size = header & 0xFFFFF8;
|
||||||
size = header & 0xFFFFF8;
|
FACTOR_ASSERT(size > 0);
|
||||||
FACTOR_ASSERT(size > 0);
|
return size;
|
||||||
return size;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
cell stack_frame_size() const
|
cell stack_frame_size() const {
|
||||||
{
|
if (free_p())
|
||||||
if (free_p())
|
return 0;
|
||||||
return 0;
|
else
|
||||||
else
|
return (header >> 20) & 0xFF0;
|
||||||
return (header >> 20) & 0xFF0;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
cell stack_frame_size_for_address(cell addr) const
|
cell stack_frame_size_for_address(cell addr) const {
|
||||||
{
|
cell natural_frame_size = stack_frame_size();
|
||||||
cell natural_frame_size = stack_frame_size();
|
/* The first instruction in a code block is the prolog safepoint,
|
||||||
/* The first instruction in a code block is the prolog safepoint,
|
and a leaf procedure code block will record a frame size of zero.
|
||||||
and a leaf procedure code block will record a frame size of zero.
|
If we're seeing a stack frame in either of these cases, it's a
|
||||||
If we're seeing a stack frame in either of these cases, it's a
|
fake "leaf frame" set up by the signal handler. */
|
||||||
fake "leaf frame" set up by the signal handler. */
|
if (natural_frame_size == 0 || (void*)addr == entry_point())
|
||||||
if (natural_frame_size == 0 || (void*)addr == entry_point())
|
return LEAF_FRAME_SIZE;
|
||||||
return LEAF_FRAME_SIZE;
|
else
|
||||||
else
|
return natural_frame_size;
|
||||||
return natural_frame_size;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void set_stack_frame_size(cell frame_size)
|
void set_stack_frame_size(cell frame_size) {
|
||||||
{
|
FACTOR_ASSERT(size() < 0xFFFFFF);
|
||||||
FACTOR_ASSERT(size() < 0xFFFFFF);
|
FACTOR_ASSERT(!free_p());
|
||||||
FACTOR_ASSERT(!free_p());
|
FACTOR_ASSERT(frame_size % 16 == 0);
|
||||||
FACTOR_ASSERT(frame_size % 16 == 0);
|
FACTOR_ASSERT(frame_size <= 0xFF0);
|
||||||
FACTOR_ASSERT(frame_size <= 0xFF0);
|
header = (header & 0xFFFFFF) | (frame_size << 20);
|
||||||
header = (header & 0xFFFFFF) | (frame_size << 20);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Fixup> cell size(Fixup fixup) const
|
template <typename Fixup> cell size(Fixup fixup) const { return size(); }
|
||||||
{
|
|
||||||
return size();
|
|
||||||
}
|
|
||||||
|
|
||||||
void *entry_point() const
|
void* entry_point() const { return (void*)(this + 1); }
|
||||||
{
|
|
||||||
return (void *)(this + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* GC info is stored at the end of the block */
|
/* GC info is stored at the end of the block */
|
||||||
gc_info *block_gc_info() const
|
gc_info* block_gc_info() const {
|
||||||
{
|
return (gc_info*)((u8*)this + size() - sizeof(gc_info));
|
||||||
return (gc_info *)((u8 *)this + size() - sizeof(gc_info));
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void flush_icache()
|
void flush_icache() { factor::flush_icache((cell) this, size()); }
|
||||||
{
|
|
||||||
factor::flush_icache((cell)this,size());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Iterator> void each_instruction_operand(Iterator &iter)
|
template <typename Iterator> void each_instruction_operand(Iterator& iter) {
|
||||||
{
|
if (to_boolean(relocation)) {
|
||||||
if(to_boolean(relocation))
|
byte_array* rels = (byte_array*)UNTAG(relocation);
|
||||||
{
|
|
||||||
byte_array *rels = (byte_array *)UNTAG(relocation);
|
|
||||||
|
|
||||||
cell index = 0;
|
cell index = 0;
|
||||||
cell length = (rels->capacity >> TAG_BITS) / sizeof(relocation_entry);
|
cell length = (rels->capacity >> TAG_BITS) / sizeof(relocation_entry);
|
||||||
|
|
||||||
for(cell i = 0; i < length; i++)
|
for (cell i = 0; i < length; i++) {
|
||||||
{
|
relocation_entry rel = rels->data<relocation_entry>()[i];
|
||||||
relocation_entry rel = rels->data<relocation_entry>()[i];
|
iter(instruction_operand(rel, this, index));
|
||||||
iter(instruction_operand(rel,this,index));
|
index += rel.number_of_parameters();
|
||||||
index += rel.number_of_parameters();
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
cell offset(void *addr) const
|
cell offset(void* addr) const { return (char*)addr - (char*)entry_point(); }
|
||||||
{
|
|
||||||
return (char*)addr - (char*)entry_point();
|
|
||||||
}
|
|
||||||
|
|
||||||
void *address_for_offset(cell offset) const
|
void* address_for_offset(cell offset) const {
|
||||||
{
|
return (void*)((char*)entry_point() + offset);
|
||||||
return (void*)((char*)entry_point() + offset);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
cell scan(factor_vm *vm, void *addr) const;
|
cell scan(factor_vm* vm, void* addr) const;
|
||||||
cell owner_quot() const;
|
cell owner_quot() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
VM_C_API void undefined_symbol(void);
|
VM_C_API void undefined_symbol(void);
|
||||||
|
|
||||||
inline code_block *word::code() const {
|
inline code_block* word::code() const {
|
||||||
FACTOR_ASSERT(entry_point != NULL);
|
FACTOR_ASSERT(entry_point != NULL);
|
||||||
return (code_block*)entry_point - 1;
|
return (code_block*)entry_point - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline code_block *quotation::code() const {
|
inline code_block* quotation::code() const {
|
||||||
FACTOR_ASSERT(entry_point != NULL);
|
FACTOR_ASSERT(entry_point != NULL);
|
||||||
return (code_block*)entry_point - 1;
|
return (code_block*)entry_point - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue