2013-05-11 22:28:42 -04:00
|
|
|
namespace factor {
|
2009-10-24 04:54:53 -04:00
|
|
|
|
2010-06-11 20:06:00 -04:00
|
|
|
/* Size of the object pointed to by an untagged pointer */
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> cell object::size(Fixup fixup) const {
|
|
|
|
if (free_p())
|
|
|
|
return ((free_heap_block*)this)->size();
|
|
|
|
|
|
|
|
switch (type()) {
|
|
|
|
case ARRAY_TYPE:
|
|
|
|
return align(array_size((array*)this), data_alignment);
|
|
|
|
case BIGNUM_TYPE:
|
|
|
|
return align(array_size((bignum*)this), data_alignment);
|
|
|
|
case BYTE_ARRAY_TYPE:
|
|
|
|
return align(array_size((byte_array*)this), data_alignment);
|
|
|
|
case STRING_TYPE:
|
|
|
|
return align(string_size(string_capacity((string*)this)), data_alignment);
|
|
|
|
case TUPLE_TYPE: {
|
|
|
|
tuple_layout* layout = (tuple_layout*)fixup.translate_data(
|
|
|
|
untag<object>(((tuple*)this)->layout));
|
|
|
|
return align(tuple_size(layout), data_alignment);
|
|
|
|
}
|
|
|
|
case QUOTATION_TYPE:
|
|
|
|
return align(sizeof(quotation), data_alignment);
|
|
|
|
case WORD_TYPE:
|
|
|
|
return align(sizeof(word), data_alignment);
|
|
|
|
case FLOAT_TYPE:
|
|
|
|
return align(sizeof(boxed_float), data_alignment);
|
|
|
|
case DLL_TYPE:
|
|
|
|
return align(sizeof(dll), data_alignment);
|
|
|
|
case ALIEN_TYPE:
|
|
|
|
return align(sizeof(alien), data_alignment);
|
|
|
|
case WRAPPER_TYPE:
|
|
|
|
return align(sizeof(wrapper), data_alignment);
|
|
|
|
case CALLSTACK_TYPE:
|
|
|
|
return align(
|
|
|
|
callstack_object_size(untag_fixnum(((callstack*)this)->length)),
|
|
|
|
data_alignment);
|
|
|
|
default:
|
2013-05-13 00:53:47 -04:00
|
|
|
critical_error("Invalid header in size", (cell)this);
|
2013-05-11 22:28:42 -04:00
|
|
|
return 0; /* can't happen */
|
|
|
|
}
|
2010-06-11 20:06:00 -04:00
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
inline cell object::size() const { return size(no_fixup()); }
|
2010-06-11 20:06:00 -04:00
|
|
|
|
|
|
|
/* The number of cells from the start of the object which should be scanned by
|
|
|
|
the GC. Some types have a binary payload at the end (string, word, DLL) which
|
|
|
|
we ignore. */
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> cell object::binary_payload_start(Fixup fixup) const {
|
|
|
|
if (free_p())
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch (type()) {
|
|
|
|
/* these objects do not refer to other objects at all */
|
|
|
|
case FLOAT_TYPE:
|
|
|
|
case BYTE_ARRAY_TYPE:
|
|
|
|
case BIGNUM_TYPE:
|
|
|
|
case CALLSTACK_TYPE:
|
|
|
|
return 0;
|
|
|
|
/* these objects have some binary data at the end */
|
|
|
|
case WORD_TYPE:
|
|
|
|
return sizeof(word) - sizeof(cell);
|
|
|
|
case ALIEN_TYPE:
|
|
|
|
return sizeof(cell) * 3;
|
|
|
|
case DLL_TYPE:
|
|
|
|
return sizeof(cell) * 2;
|
|
|
|
case QUOTATION_TYPE:
|
|
|
|
return sizeof(quotation) - sizeof(cell);
|
|
|
|
case STRING_TYPE:
|
|
|
|
return sizeof(string);
|
|
|
|
/* everything else consists entirely of pointers */
|
|
|
|
case ARRAY_TYPE:
|
|
|
|
return array_size<array>(array_capacity((array*)this));
|
|
|
|
case TUPLE_TYPE: {
|
|
|
|
tuple_layout* layout = (tuple_layout*)fixup.translate_data(
|
|
|
|
untag<object>(((tuple*)this)->layout));
|
|
|
|
return tuple_size(layout);
|
|
|
|
}
|
|
|
|
case WRAPPER_TYPE:
|
|
|
|
return sizeof(wrapper);
|
|
|
|
default:
|
2013-05-13 00:53:47 -04:00
|
|
|
critical_error("Invalid header in binary_payload_start", (cell)this);
|
2013-05-11 22:28:42 -04:00
|
|
|
return 0; /* can't happen */
|
|
|
|
}
|
2010-06-11 20:06:00 -04:00
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
inline cell object::binary_payload_start() const {
|
|
|
|
return binary_payload_start(no_fixup());
|
2010-06-11 20:06:00 -04:00
|
|
|
}
|
|
|
|
|
2009-12-02 01:48:41 -05:00
|
|
|
/* Slot visitors iterate over the slots of an object, applying a functor to
|
|
|
|
each one that is a non-immediate slot. The pointer is untagged first. The
|
2013-05-11 22:28:42 -04:00
|
|
|
functor returns a new untagged object pointer. The return value may or may not
|
|
|
|
equal the old one,
|
2009-12-02 01:48:41 -05:00
|
|
|
however the new pointer receives the same tag before being stored back to the
|
|
|
|
original location.
|
|
|
|
|
|
|
|
Slots storing immediate values are left unchanged and the visitor does inspect
|
|
|
|
them.
|
|
|
|
|
|
|
|
This is used by GC's copying, sweep and compact phases, and the implementation
|
|
|
|
of the become primitive.
|
|
|
|
|
|
|
|
Iteration is driven by visit_*() methods. Some of them define GC roots:
|
|
|
|
- visit_roots()
|
2015-01-11 23:58:55 -05:00
|
|
|
- visit_contexts()
|
|
|
|
|
|
|
|
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
|
|
|
|
equal the old one. This is stored back to the original location.
|
|
|
|
|
|
|
|
This is used by GC's sweep and compact phases, and the implementation of the
|
|
|
|
modify-code-heap primitive.
|
|
|
|
|
|
|
|
Iteration is driven by visit_*() methods. Some of them define GC roots:
|
|
|
|
- visit_context_code_blocks()
|
|
|
|
- visit_callback_code_blocks() */
|
2009-12-02 01:48:41 -05:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> struct slot_visitor {
|
|
|
|
factor_vm* parent;
|
|
|
|
Fixup fixup;
|
|
|
|
|
2013-05-12 23:20:43 -04:00
|
|
|
slot_visitor<Fixup>(factor_vm* parent, Fixup fixup)
|
|
|
|
: parent(parent), fixup(fixup) {}
|
2013-05-11 22:28:42 -04:00
|
|
|
|
|
|
|
cell visit_pointer(cell pointer);
|
|
|
|
void visit_handle(cell* handle);
|
|
|
|
void visit_object_array(cell* start, cell* end);
|
|
|
|
void visit_slots(object* ptr, cell payload_start);
|
|
|
|
void visit_slots(object* ptr);
|
|
|
|
void visit_stack_elements(segment* region, cell* top);
|
|
|
|
void visit_data_roots();
|
|
|
|
void visit_callback_roots();
|
|
|
|
void visit_literal_table_roots();
|
|
|
|
void visit_roots();
|
|
|
|
void visit_callstack_object(callstack* stack);
|
|
|
|
void visit_callstack(context* ctx);
|
2014-08-28 11:32:36 -04:00
|
|
|
void visit_context(context *ctx);
|
2013-05-11 22:28:42 -04:00
|
|
|
void visit_contexts();
|
|
|
|
void visit_code_block_objects(code_block* compiled);
|
|
|
|
void visit_embedded_literals(code_block* compiled);
|
|
|
|
void visit_sample_callstacks();
|
|
|
|
void visit_sample_threads();
|
2015-01-11 23:58:55 -05:00
|
|
|
void visit_object_code_block(object* obj);
|
|
|
|
void visit_context_code_blocks();
|
|
|
|
void visit_uninitialized_code_blocks();
|
|
|
|
void visit_embedded_code_pointers(code_block* compiled);
|
2009-11-22 14:37:39 -05:00
|
|
|
};
|
2009-11-06 02:22:53 -05:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup>
|
|
|
|
cell slot_visitor<Fixup>::visit_pointer(cell pointer) {
|
|
|
|
if (immediate_p(pointer))
|
|
|
|
return pointer;
|
2009-11-07 17:16:09 -05:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
object* untagged = fixup.fixup_data(untag<object>(pointer));
|
|
|
|
return RETAG(untagged, TAG(pointer));
|
2009-11-22 14:37:39 -05:00
|
|
|
}
|
2009-10-24 04:54:53 -04:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> void slot_visitor<Fixup>::visit_handle(cell* handle) {
|
|
|
|
*handle = visit_pointer(*handle);
|
2009-11-22 14:37:39 -05:00
|
|
|
}
|
2009-10-24 04:54:53 -04:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup>
|
|
|
|
void slot_visitor<Fixup>::visit_object_array(cell* start, cell* end) {
|
|
|
|
while (start < end)
|
|
|
|
visit_handle(start++);
|
2010-03-18 05:06:00 -04:00
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup>
|
|
|
|
void slot_visitor<Fixup>::visit_slots(object* ptr, cell payload_start) {
|
|
|
|
cell* slot = (cell*)ptr;
|
2013-05-13 00:53:47 -04:00
|
|
|
cell* end = (cell*)((cell)ptr + payload_start);
|
2013-05-11 22:28:42 -04:00
|
|
|
|
|
|
|
if (slot != end) {
|
|
|
|
slot++;
|
|
|
|
visit_object_array(slot, end);
|
|
|
|
}
|
2009-11-22 14:37:39 -05:00
|
|
|
}
|
2009-10-25 00:51:14 -04:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> void slot_visitor<Fixup>::visit_slots(object* obj) {
|
|
|
|
if (obj->type() == CALLSTACK_TYPE)
|
|
|
|
visit_callstack_object((callstack*)obj);
|
|
|
|
else
|
|
|
|
visit_slots(obj, obj->binary_payload_start(fixup));
|
2009-11-22 14:37:39 -05:00
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup>
|
|
|
|
void slot_visitor<Fixup>::visit_stack_elements(segment* region, cell* top) {
|
|
|
|
visit_object_array((cell*)region->start, top + 1);
|
2009-11-22 14:37:39 -05:00
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> void slot_visitor<Fixup>::visit_data_roots() {
|
2014-06-11 14:33:33 -04:00
|
|
|
std::vector<cell*>::const_iterator iter =
|
2013-05-11 22:28:42 -04:00
|
|
|
parent->data_roots.begin();
|
2014-06-11 14:33:33 -04:00
|
|
|
std::vector<cell*>::const_iterator end =
|
|
|
|
parent->data_roots.end();
|
2009-11-22 14:37:39 -05:00
|
|
|
|
2014-06-11 14:33:33 -04:00
|
|
|
for (; iter < end; iter++) {
|
|
|
|
visit_handle(*iter);
|
|
|
|
}
|
2009-11-22 14:37:39 -05:00
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> struct callback_slot_visitor {
|
|
|
|
slot_visitor<Fixup>* visitor;
|
2009-12-02 01:48:41 -05:00
|
|
|
|
2014-09-09 11:56:56 -04:00
|
|
|
callback_slot_visitor(slot_visitor<Fixup>* visitor) : visitor(visitor) {}
|
2009-12-02 01:48:41 -05:00
|
|
|
|
2014-09-09 11:56:56 -04:00
|
|
|
void operator()(code_block* stub, cell size) {
|
|
|
|
visitor->visit_handle(&stub->owner);
|
2014-09-09 08:45:01 -04:00
|
|
|
}
|
2009-12-02 01:48:41 -05:00
|
|
|
};
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> void slot_visitor<Fixup>::visit_callback_roots() {
|
2014-09-09 11:56:56 -04:00
|
|
|
callback_slot_visitor<Fixup> callback_visitor(this);
|
|
|
|
parent->callbacks->allocator->iterate(callback_visitor);
|
2009-12-02 01:48:41 -05:00
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup>
|
|
|
|
void slot_visitor<Fixup>::visit_literal_table_roots() {
|
|
|
|
std::map<code_block*, cell>* uninitialized_blocks =
|
|
|
|
&parent->code->uninitialized_blocks;
|
2014-12-04 12:04:49 -05:00
|
|
|
std::map<code_block*, cell>::iterator iter =
|
2013-05-11 22:28:42 -04:00
|
|
|
uninitialized_blocks->begin();
|
2014-12-04 12:04:49 -05:00
|
|
|
std::map<code_block*, cell>::iterator end = uninitialized_blocks->end();
|
2013-05-11 22:28:42 -04:00
|
|
|
|
|
|
|
for (; iter != end; iter++) {
|
2014-12-04 12:04:49 -05:00
|
|
|
iter->second = visit_pointer(iter->second);
|
2013-05-11 22:28:42 -04:00
|
|
|
}
|
2009-12-02 05:28:15 -05:00
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> void slot_visitor<Fixup>::visit_sample_callstacks() {
|
|
|
|
for (std::vector<cell>::iterator iter = parent->sample_callstacks.begin();
|
|
|
|
iter != parent->sample_callstacks.end(); ++iter) {
|
|
|
|
visit_handle(&*iter);
|
|
|
|
}
|
2011-11-01 21:53:37 -04:00
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> void slot_visitor<Fixup>::visit_sample_threads() {
|
|
|
|
for (std::vector<profiling_sample>::iterator iter = parent->samples.begin();
|
|
|
|
iter != parent->samples.end(); ++iter) {
|
|
|
|
visit_handle(&iter->thread);
|
|
|
|
}
|
2011-11-01 22:39:54 -04:00
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> void slot_visitor<Fixup>::visit_roots() {
|
|
|
|
visit_handle(&parent->true_object);
|
|
|
|
visit_handle(&parent->bignum_zero);
|
|
|
|
visit_handle(&parent->bignum_pos_one);
|
|
|
|
visit_handle(&parent->bignum_neg_one);
|
|
|
|
|
|
|
|
visit_data_roots();
|
|
|
|
visit_callback_roots();
|
|
|
|
visit_literal_table_roots();
|
|
|
|
visit_sample_callstacks();
|
|
|
|
visit_sample_threads();
|
|
|
|
|
|
|
|
visit_object_array(parent->special_objects,
|
|
|
|
parent->special_objects + special_object_count);
|
2009-11-22 14:37:39 -05:00
|
|
|
}
|
|
|
|
|
2014-08-28 11:32:36 -04:00
|
|
|
/* primitive_minor_gc() is invoked by inline GC checks, and it needs to fill in
|
|
|
|
uninitialized stack locations before actually calling the GC. See the
|
|
|
|
documentation in compiler.cfg.stacks.vacant for details.
|
|
|
|
|
|
|
|
So for each call frame:
|
|
|
|
|
|
|
|
- scrub some uninitialized locations
|
|
|
|
- trace some overinitialized locations
|
|
|
|
- trace roots in spill slots
|
|
|
|
*/
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> struct call_frame_slot_visitor {
|
|
|
|
factor_vm* parent;
|
|
|
|
slot_visitor<Fixup>* visitor;
|
2014-09-01 10:59:47 -04:00
|
|
|
/* NULL in case we're a visitor for a callstack object. */
|
2014-08-26 22:22:20 -04:00
|
|
|
context* ctx;
|
2010-06-11 20:06:00 -04:00
|
|
|
|
2014-09-01 10:59:47 -04:00
|
|
|
void check_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
|
|
|
|
for (uint32_t loc = 0; loc < count; loc++) {
|
|
|
|
if (bitmap_p(bitmap, base + loc)) {
|
|
|
|
#ifdef DEBUG_GC_MAPS
|
|
|
|
std::cout << "checking stack location " << loc << std::endl;
|
|
|
|
#endif
|
|
|
|
cell* value_ptr = ((cell*)stack + loc + 1);
|
|
|
|
visitor->visit_handle(value_ptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void scrub_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
|
|
|
|
for (cell loc = 0; loc < count; loc++) {
|
|
|
|
if (bitmap_p(bitmap, base + loc)) {
|
|
|
|
#ifdef DEBUG_GC_MAPS
|
|
|
|
std::cout << "scrubbing stack location " << loc << std::endl;
|
|
|
|
#endif
|
|
|
|
*((cell*)stack - loc) = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-12 23:20:43 -04:00
|
|
|
call_frame_slot_visitor(factor_vm* parent,
|
2014-08-26 22:22:20 -04:00
|
|
|
slot_visitor<Fixup>* visitor,
|
|
|
|
context* ctx)
|
|
|
|
: parent(parent), visitor(visitor), ctx(ctx) {}
|
2010-06-11 20:06:00 -04:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
/*
|
2011-12-05 15:53:34 -05:00
|
|
|
frame top -> [return address]
|
|
|
|
[spill area]
|
|
|
|
...
|
|
|
|
[entry_point]
|
|
|
|
[size]
|
2010-06-11 20:06:00 -04:00
|
|
|
*/
|
2015-01-05 08:04:12 -05:00
|
|
|
void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
|
2015-01-06 11:35:44 -05:00
|
|
|
cell return_address = owner->offset(addr);
|
2010-06-13 17:57:16 -04:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
code_block* compiled =
|
|
|
|
Fixup::translated_code_block_map ? owner
|
|
|
|
: visitor->fixup.translate_code(owner);
|
|
|
|
gc_info* info = compiled->block_gc_info();
|
2010-06-13 17:57:16 -04:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
FACTOR_ASSERT(return_address < compiled->size());
|
|
|
|
cell callsite = info->return_address_index(return_address);
|
2013-05-13 00:53:47 -04:00
|
|
|
if (callsite == (cell)-1)
|
2013-05-11 22:28:42 -04:00
|
|
|
return;
|
2010-06-13 17:57:16 -04:00
|
|
|
|
2010-06-13 17:36:08 -04:00
|
|
|
#ifdef DEBUG_GC_MAPS
|
2013-05-11 22:28:42 -04:00
|
|
|
std::cout << "call frame code block " << compiled << " with offset "
|
|
|
|
<< return_address << std::endl;
|
2010-06-13 17:36:08 -04:00
|
|
|
#endif
|
2013-05-11 22:28:42 -04:00
|
|
|
cell* stack_pointer = (cell*)frame_top;
|
2013-05-13 00:28:25 -04:00
|
|
|
uint8_t* bitmap = info->gc_info_bitmap();
|
2013-05-11 22:28:42 -04:00
|
|
|
|
2014-09-01 10:59:47 -04:00
|
|
|
if (ctx) {
|
|
|
|
/* Scrub vacant stack locations. */
|
|
|
|
scrub_stack(ctx->datastack,
|
|
|
|
bitmap,
|
|
|
|
info->callsite_scrub_d(callsite),
|
|
|
|
info->scrub_d_count);
|
|
|
|
scrub_stack(ctx->retainstack,
|
|
|
|
bitmap,
|
|
|
|
info->callsite_scrub_r(callsite),
|
|
|
|
info->scrub_r_count);
|
|
|
|
|
|
|
|
/* Trace overinitialized stack locations. */
|
|
|
|
check_stack(ctx->datastack,
|
|
|
|
bitmap,
|
|
|
|
info->callsite_check_d(callsite),
|
|
|
|
info->check_d_count);
|
|
|
|
check_stack(ctx->retainstack,
|
|
|
|
bitmap,
|
|
|
|
info->callsite_check_r(callsite),
|
|
|
|
info->check_r_count);
|
2014-08-26 22:22:20 -04:00
|
|
|
}
|
|
|
|
|
2014-08-28 11:32:36 -04:00
|
|
|
/* Subtract old value of base pointer from every derived pointer. */
|
|
|
|
for (cell spill_slot = 0; spill_slot < info->derived_root_count;
|
|
|
|
spill_slot++) {
|
|
|
|
uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
|
|
|
|
if (base_pointer != (uint32_t)-1) {
|
|
|
|
#ifdef DEBUG_GC_MAPS
|
|
|
|
std::cout << "visiting derived root " << spill_slot
|
|
|
|
<< " with base pointer " << base_pointer << std::endl;
|
|
|
|
#endif
|
|
|
|
stack_pointer[spill_slot] -= stack_pointer[base_pointer];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
/* Update all GC roots, including base pointers. */
|
|
|
|
cell callsite_gc_roots = info->callsite_gc_roots(callsite);
|
2010-09-27 01:20:50 -04:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
for (cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) {
|
|
|
|
if (bitmap_p(bitmap, callsite_gc_roots + spill_slot)) {
|
2010-09-27 01:20:50 -04:00
|
|
|
#ifdef DEBUG_GC_MAPS
|
2013-05-11 22:28:42 -04:00
|
|
|
std::cout << "visiting GC root " << spill_slot << std::endl;
|
2010-06-13 17:36:08 -04:00
|
|
|
#endif
|
2013-05-11 22:28:42 -04:00
|
|
|
visitor->visit_handle(stack_pointer + spill_slot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Add the base pointers to obtain new derived pointer values. */
|
|
|
|
for (cell spill_slot = 0; spill_slot < info->derived_root_count;
|
|
|
|
spill_slot++) {
|
2013-05-13 00:28:25 -04:00
|
|
|
uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
|
|
|
|
if (base_pointer != (uint32_t)-1)
|
2013-05-11 22:28:42 -04:00
|
|
|
stack_pointer[spill_slot] += stack_pointer[base_pointer];
|
|
|
|
}
|
|
|
|
}
|
2010-06-11 20:06:00 -04:00
|
|
|
};
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup>
|
|
|
|
void slot_visitor<Fixup>::visit_callstack_object(callstack* stack) {
|
2014-09-01 10:59:47 -04:00
|
|
|
call_frame_slot_visitor<Fixup> call_frame_visitor(parent, this, NULL);
|
2013-05-11 22:28:42 -04:00
|
|
|
parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
|
2010-06-11 20:06:00 -04:00
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup>
|
|
|
|
void slot_visitor<Fixup>::visit_callstack(context* ctx) {
|
2014-08-26 22:22:20 -04:00
|
|
|
call_frame_slot_visitor<Fixup> call_frame_visitor(parent, this, ctx);
|
2013-05-11 22:28:42 -04:00
|
|
|
parent->iterate_callstack(ctx, call_frame_visitor, fixup);
|
2010-06-11 20:06:00 -04:00
|
|
|
}
|
|
|
|
|
2014-08-28 11:32:36 -04:00
|
|
|
template <typename Fixup>
|
|
|
|
void slot_visitor<Fixup>::visit_context(context* ctx) {
|
|
|
|
/* Callstack is visited first because it scrubs the data and retain
|
|
|
|
stacks. */
|
|
|
|
visit_callstack(ctx);
|
|
|
|
|
|
|
|
visit_stack_elements(ctx->datastack_seg, (cell*)ctx->datastack);
|
|
|
|
visit_stack_elements(ctx->retainstack_seg, (cell*)ctx->retainstack);
|
|
|
|
visit_object_array(ctx->context_objects,
|
|
|
|
ctx->context_objects + context_object_count);
|
|
|
|
}
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> void slot_visitor<Fixup>::visit_contexts() {
|
|
|
|
std::set<context*>::const_iterator begin = parent->active_contexts.begin();
|
|
|
|
std::set<context*>::const_iterator end = parent->active_contexts.end();
|
|
|
|
while (begin != end) {
|
2014-08-28 11:32:36 -04:00
|
|
|
visit_context(*begin);
|
2013-05-11 22:28:42 -04:00
|
|
|
begin++;
|
|
|
|
}
|
2009-11-22 14:37:39 -05:00
|
|
|
}
|
2009-10-24 04:54:53 -04:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup> struct literal_references_visitor {
|
|
|
|
slot_visitor<Fixup>* visitor;
|
2009-10-24 04:54:53 -04:00
|
|
|
|
2013-05-12 23:20:43 -04:00
|
|
|
explicit literal_references_visitor(slot_visitor<Fixup>* visitor)
|
|
|
|
: visitor(visitor) {}
|
2009-10-24 04:54:53 -04:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
void operator()(instruction_operand op) {
|
|
|
|
if (op.rel_type() == RT_LITERAL)
|
|
|
|
op.store_value(visitor->visit_pointer(op.load_value()));
|
|
|
|
}
|
2009-10-24 04:54:53 -04:00
|
|
|
};
|
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup>
|
|
|
|
void slot_visitor<Fixup>::visit_code_block_objects(code_block* compiled) {
|
|
|
|
visit_handle(&compiled->owner);
|
|
|
|
visit_handle(&compiled->parameters);
|
|
|
|
visit_handle(&compiled->relocation);
|
2009-11-24 20:29:59 -05:00
|
|
|
}
|
2009-11-22 14:37:39 -05:00
|
|
|
|
2013-05-11 22:28:42 -04:00
|
|
|
template <typename Fixup>
|
|
|
|
void slot_visitor<Fixup>::visit_embedded_literals(code_block* compiled) {
|
|
|
|
if (!parent->code->uninitialized_p(compiled)) {
|
|
|
|
literal_references_visitor<Fixup> visitor(this);
|
|
|
|
compiled->each_instruction_operand(visitor);
|
|
|
|
}
|
2009-11-22 14:37:39 -05:00
|
|
|
}
|
|
|
|
|
2015-01-11 23:58:55 -05:00
|
|
|
template <typename Fixup> struct call_frame_code_block_visitor {
|
|
|
|
factor_vm* parent;
|
|
|
|
Fixup fixup;
|
|
|
|
|
|
|
|
call_frame_code_block_visitor(factor_vm* parent, Fixup fixup)
|
|
|
|
: parent(parent), fixup(fixup) {}
|
|
|
|
|
|
|
|
void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
|
|
|
|
code_block* compiled =
|
|
|
|
Fixup::translated_code_block_map ? owner : fixup.fixup_code(owner);
|
|
|
|
cell fixed_addr = compiled->address_for_offset(owner->offset(addr));
|
|
|
|
|
|
|
|
*(cell*)frame_top = fixed_addr;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename Fixup>
|
|
|
|
void slot_visitor<Fixup>::visit_object_code_block(object* obj) {
|
|
|
|
switch (obj->type()) {
|
|
|
|
case WORD_TYPE: {
|
|
|
|
word* w = (word*)obj;
|
|
|
|
if (w->entry_point)
|
|
|
|
w->entry_point = fixup.fixup_code(w->code())->entry_point();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case QUOTATION_TYPE: {
|
|
|
|
quotation* q = (quotation*)obj;
|
|
|
|
if (q->entry_point)
|
|
|
|
q->entry_point = fixup.fixup_code(q->code())->entry_point();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CALLSTACK_TYPE: {
|
|
|
|
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>
|
|
|
|
void slot_visitor<Fixup>::visit_context_code_blocks() {
|
|
|
|
call_frame_code_block_visitor<Fixup> call_frame_visitor(parent, fixup);
|
|
|
|
std::set<context*>::const_iterator begin = parent->active_contexts.begin();
|
|
|
|
std::set<context*>::const_iterator end = parent->active_contexts.end();
|
|
|
|
while (begin != end) {
|
|
|
|
parent->iterate_callstack(*begin++, call_frame_visitor, fixup);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Fixup>
|
|
|
|
void slot_visitor<Fixup>::visit_uninitialized_code_blocks() {
|
|
|
|
std::map<code_block*, cell>* uninitialized_blocks =
|
|
|
|
&parent->code->uninitialized_blocks;
|
|
|
|
std::map<code_block*, cell>::const_iterator iter =
|
|
|
|
uninitialized_blocks->begin();
|
|
|
|
std::map<code_block*, cell>::const_iterator end = uninitialized_blocks->end();
|
|
|
|
|
|
|
|
std::map<code_block*, cell> new_uninitialized_blocks;
|
|
|
|
for (; iter != end; iter++) {
|
|
|
|
new_uninitialized_blocks.insert(
|
|
|
|
std::make_pair(fixup.fixup_code(iter->first), iter->second));
|
|
|
|
}
|
|
|
|
|
|
|
|
parent->code->uninitialized_blocks = new_uninitialized_blocks;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename Fixup> struct embedded_code_pointers_visitor {
|
|
|
|
Fixup fixup;
|
|
|
|
|
|
|
|
explicit embedded_code_pointers_visitor(Fixup fixup) : fixup(fixup) {}
|
|
|
|
|
|
|
|
void operator()(instruction_operand op) {
|
|
|
|
relocation_type type = op.rel_type();
|
|
|
|
if (type == RT_ENTRY_POINT || type == RT_ENTRY_POINT_PIC ||
|
|
|
|
type == RT_ENTRY_POINT_PIC_TAIL)
|
|
|
|
op.store_code_block(fixup.fixup_code(op.load_code_block()));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename Fixup>
|
|
|
|
void slot_visitor<Fixup>::visit_embedded_code_pointers(code_block* compiled) {
|
|
|
|
if (!parent->code->uninitialized_p(compiled)) {
|
|
|
|
embedded_code_pointers_visitor<Fixup> operand_visitor(fixup);
|
|
|
|
compiled->each_instruction_operand(operand_visitor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-24 04:54:53 -04:00
|
|
|
}
|