vm: reversed callstack iteration
parent
e2fafaed9c
commit
e116bc497b
|
@ -108,25 +108,7 @@ void factor_vm::set_frame_offset(stack_frame *frame, cell offset)
|
||||||
|
|
||||||
cell factor_vm::frame_scan(stack_frame *frame)
|
cell factor_vm::frame_scan(stack_frame *frame)
|
||||||
{
|
{
|
||||||
switch(frame_type(frame))
|
return frame_code(frame)->scan(this, FRAME_RETURN_ADDRESS(frame,this));
|
||||||
{
|
|
||||||
case code_block_unoptimized:
|
|
||||||
{
|
|
||||||
tagged<object> obj(frame_executing(frame));
|
|
||||||
if(obj.type_p(WORD_TYPE))
|
|
||||||
obj = obj.as<word>()->def;
|
|
||||||
|
|
||||||
if(obj.type_p(QUOTATION_TYPE))
|
|
||||||
return tag_fixnum(quot_code_offset_to_scan(obj.value(),frame_offset(frame)));
|
|
||||||
else
|
|
||||||
return false_object;
|
|
||||||
}
|
|
||||||
case code_block_optimized:
|
|
||||||
return false_object;
|
|
||||||
default:
|
|
||||||
critical_error("Bad frame type",frame_type(frame));
|
|
||||||
return false_object;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct stack_frame_accumulator {
|
struct stack_frame_accumulator {
|
||||||
|
|
|
@ -8,6 +8,34 @@ inline static cell callstack_object_size(cell size)
|
||||||
|
|
||||||
/* This is a little tricky. The iterator may allocate memory, so we
|
/* This is a little tricky. The iterator may allocate memory, so we
|
||||||
keep the callstack in a GC root and use relative offsets */
|
keep the callstack in a GC root and use relative offsets */
|
||||||
|
template<typename Iterator>
|
||||||
|
void factor_vm::iterate_callstack_object_reversed(callstack *stack_, Iterator &iterator)
|
||||||
|
{
|
||||||
|
data_root<callstack> stack(stack_,this);
|
||||||
|
fixnum frame_length = factor::untag_fixnum(stack->length);
|
||||||
|
fixnum frame_offset = 0;
|
||||||
|
|
||||||
|
while(frame_offset < frame_length)
|
||||||
|
{
|
||||||
|
void *frame_top = stack->frame_top_at(frame_offset);
|
||||||
|
void *addr = frame_return_address(frame_top);
|
||||||
|
|
||||||
|
code_block *owner = code->code_block_for_address(addr);
|
||||||
|
cell frame_size = owner->stack_frame_size_for_address(addr);
|
||||||
|
|
||||||
|
#ifdef FACTOR_DEBUG
|
||||||
|
// check our derived owner and frame size against the ones stored in the frame
|
||||||
|
// by the function prolog
|
||||||
|
stack_frame *frame = (stack_frame*)((char*)frame_top + frame_size) - 1;
|
||||||
|
FACTOR_ASSERT(owner->entry_point() == frame->entry_point);
|
||||||
|
FACTOR_ASSERT(frame_size == frame->size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
iterator(owner, addr);
|
||||||
|
frame_offset += frame_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Iterator> void factor_vm::iterate_callstack_object(callstack *stack_, Iterator &iterator)
|
template<typename Iterator> void factor_vm::iterate_callstack_object(callstack *stack_, Iterator &iterator)
|
||||||
{
|
{
|
||||||
data_root<callstack> stack(stack_,this);
|
data_root<callstack> stack(stack_,this);
|
||||||
|
@ -21,56 +49,37 @@ template<typename Iterator> void factor_vm::iterate_callstack_object(callstack *
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void factor_vm::verify_callstack(context *ctx, cell pc)
|
template<typename Iterator>
|
||||||
|
void factor_vm::iterate_callstack_reversed(context *ctx, Iterator &iterator)
|
||||||
{
|
{
|
||||||
if (pc == 0)
|
if (ctx->callstack_top == ctx->callstack_bottom)
|
||||||
{
|
|
||||||
std::cout << "null return address" << std::endl;
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
unsigned char *frame_top = (unsigned char*)ctx->callstack_top;
|
char *frame_top = (char*)ctx->callstack_top;
|
||||||
cell addr = pc;
|
|
||||||
|
|
||||||
while(frame_top < (unsigned char*)ctx->callstack_bottom)
|
while (frame_top < (char*)ctx->callstack_bottom)
|
||||||
{
|
{
|
||||||
std::cout << std::endl;
|
void *addr = frame_return_address((void*)frame_top);
|
||||||
std::cout << "address " << (void*)addr << std::endl;
|
FACTOR_ASSERT(addr != 0);
|
||||||
code_block *owner = code->code_block_for_address(addr);
|
|
||||||
std::cout << "owner " << (void*)owner->entry_point() << " ";
|
code_block *owner = code->code_block_for_address((cell)addr);
|
||||||
print_obj(owner->owner);
|
cell frame_size = owner->stack_frame_size_for_address((cell)addr);
|
||||||
std::cout << std::endl;
|
|
||||||
cell frame_size = owner->stack_frame_size_for_address(addr);
|
#ifdef FACTOR_DEBUG
|
||||||
std::cout << "frame size " << (void*)frame_size << std::endl;
|
// check our derived owner and frame size against the ones stored in the frame
|
||||||
|
// by the function prolog
|
||||||
|
stack_frame *frame = (stack_frame*)(frame_top + frame_size) - 1;
|
||||||
|
FACTOR_ASSERT(owner->entry_point() == frame->entry_point);
|
||||||
|
FACTOR_ASSERT(frame_size == frame->size);
|
||||||
|
#endif
|
||||||
|
|
||||||
frame_top += frame_size;
|
frame_top += frame_size;
|
||||||
stack_frame *frame = (stack_frame*)frame_top - 1;
|
iterator(owner, addr);
|
||||||
if (owner->entry_point() != frame->entry_point)
|
|
||||||
{
|
|
||||||
std::cout << "unexpected frame owner " << (void*)frame->entry_point << " ";
|
|
||||||
print_obj(((code_block*)frame->entry_point - 1)->owner);
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
if (frame_size != frame->size)
|
|
||||||
std::cout << "unexpected frame size " << frame->size << std::endl;
|
|
||||||
// XXX x86
|
|
||||||
addr = *(cell*)frame_top;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void factor_vm::verify_callstack(context *ctx)
|
template<typename Iterator>
|
||||||
{
|
void factor_vm::iterate_callstack(context *ctx, Iterator &iterator)
|
||||||
/*
|
|
||||||
std::cout << std::endl << std::endl
|
|
||||||
<< "callstack " << (void*)ctx->callstack_top
|
|
||||||
<< " to " << (void*)ctx->callstack_bottom << std::endl;
|
|
||||||
|
|
||||||
// XXX x86-centric
|
|
||||||
cell return_address = *((cell*)ctx->callstack_top);
|
|
||||||
verify_callstack(ctx, return_address);
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Iterator> void factor_vm::iterate_callstack(context *ctx, Iterator &iterator)
|
|
||||||
{
|
{
|
||||||
stack_frame *frame = ctx->callstack_bottom - 1;
|
stack_frame *frame = ctx->callstack_bottom - 1;
|
||||||
|
|
||||||
|
|
|
@ -3,6 +3,29 @@
|
||||||
namespace factor
|
namespace factor
|
||||||
{
|
{
|
||||||
|
|
||||||
|
cell code_block::scan(factor_vm *vm, void *addr) const
|
||||||
|
{
|
||||||
|
switch(type())
|
||||||
|
{
|
||||||
|
case code_block_unoptimized:
|
||||||
|
{
|
||||||
|
tagged<object> obj(owner);
|
||||||
|
if(obj.type_p(WORD_TYPE))
|
||||||
|
obj = obj.as<word>()->def;
|
||||||
|
|
||||||
|
if(obj.type_p(QUOTATION_TYPE))
|
||||||
|
return tag_fixnum(vm->quot_code_offset_to_scan(obj.value(),offset(addr)));
|
||||||
|
else
|
||||||
|
return false_object;
|
||||||
|
}
|
||||||
|
case code_block_optimized:
|
||||||
|
return false_object;
|
||||||
|
default:
|
||||||
|
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())
|
||||||
|
|
|
@ -121,6 +121,13 @@ struct code_block
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cell offset(void *addr) const
|
||||||
|
{
|
||||||
|
return (char*)addr - (char*)entry_point();
|
||||||
|
}
|
||||||
|
|
||||||
|
cell scan(factor_vm *vm, void *addr) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
VM_C_API void undefined_symbol(void);
|
VM_C_API void undefined_symbol(void);
|
||||||
|
|
|
@ -3,6 +3,16 @@ namespace factor
|
||||||
|
|
||||||
#define FRAME_RETURN_ADDRESS(frame,vm) *(void **)(vm->frame_successor(frame) + 1)
|
#define FRAME_RETURN_ADDRESS(frame,vm) *(void **)(vm->frame_successor(frame) + 1)
|
||||||
|
|
||||||
|
inline static void* frame_return_address(void *frame_top)
|
||||||
|
{
|
||||||
|
return *(void**)frame_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void set_frame_return_address(void *frame_top, cell return_address)
|
||||||
|
{
|
||||||
|
*(cell*)frame_top = return_address;
|
||||||
|
}
|
||||||
|
|
||||||
#define CALLSTACK_BOTTOM(ctx) (stack_frame *)(ctx->callstack_seg->end - sizeof(cell) * 5)
|
#define CALLSTACK_BOTTOM(ctx) (stack_frame *)(ctx->callstack_seg->end - sizeof(cell) * 5)
|
||||||
|
|
||||||
inline static void flush_icache(cell start, cell len) {}
|
inline static void flush_icache(cell start, cell len) {}
|
||||||
|
|
17
vm/debug.cpp
17
vm/debug.cpp
|
@ -220,23 +220,23 @@ struct stack_frame_printer {
|
||||||
factor_vm *parent;
|
factor_vm *parent;
|
||||||
|
|
||||||
explicit stack_frame_printer(factor_vm *parent_) : parent(parent_) {}
|
explicit stack_frame_printer(factor_vm *parent_) : parent(parent_) {}
|
||||||
void operator()(stack_frame *frame)
|
void operator()(code_block *owner, void *addr)
|
||||||
{
|
{
|
||||||
std::cout << "frame: " << std::hex << (cell)frame << std::dec << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << "executing: ";
|
std::cout << "executing: ";
|
||||||
parent->print_obj(parent->frame_executing(frame));
|
parent->print_obj(owner->owner);
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << "scan: ";
|
std::cout << "scan: ";
|
||||||
parent->print_obj(parent->frame_scan(frame));
|
parent->print_obj(owner->scan(parent, addr));
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << "word/quot addr: ";
|
std::cout << "word/quot addr: ";
|
||||||
std::cout << std::hex << (cell)parent->frame_executing(frame) << std::dec;
|
std::cout << std::hex << (cell)owner->owner << std::dec;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << "word/quot xt: ";
|
std::cout << "word/quot xt: ";
|
||||||
std::cout << std::hex << (cell)frame->entry_point << std::dec;
|
std::cout << std::hex << (cell)owner->entry_point() << std::dec;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << "return address: ";
|
std::cout << "return address: ";
|
||||||
std::cout << std::hex << (cell)FRAME_RETURN_ADDRESS(frame,parent) << std::dec;
|
std::cout << std::hex << (cell)addr << std::dec;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -247,8 +247,7 @@ void factor_vm::print_callstack()
|
||||||
if (ctx)
|
if (ctx)
|
||||||
{
|
{
|
||||||
stack_frame_printer printer(this);
|
stack_frame_printer printer(this);
|
||||||
verify_callstack(ctx);
|
iterate_callstack_reversed(ctx,printer);
|
||||||
iterate_callstack(ctx,printer);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
std::cout << "*** Context not initialized" << std::endl;
|
std::cout << "*** Context not initialized" << std::endl;
|
||||||
|
|
|
@ -257,7 +257,6 @@ void factor_vm::scrub_context(context *ctx)
|
||||||
{
|
{
|
||||||
call_frame_scrubber scrubber(this,ctx);
|
call_frame_scrubber scrubber(this,ctx);
|
||||||
iterate_callstack(ctx,scrubber);
|
iterate_callstack(ctx,scrubber);
|
||||||
verify_callstack(ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::scrub_contexts()
|
void factor_vm::scrub_contexts()
|
||||||
|
|
|
@ -366,6 +366,11 @@ struct callstack : public object {
|
||||||
return (stack_frame *)((char *)(this + 1) + offset);
|
return (stack_frame *)((char *)(this + 1) + offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *frame_top_at(cell offset) const
|
||||||
|
{
|
||||||
|
return (void *)((char *)(this + 1) + offset);
|
||||||
|
}
|
||||||
|
|
||||||
stack_frame *top() const { return (stack_frame *)(this + 1); }
|
stack_frame *top() const { return (stack_frame *)(this + 1); }
|
||||||
stack_frame *bottom() const { return (stack_frame *)((cell)(this + 1) + untag_fixnum(length)); }
|
stack_frame *bottom() const { return (stack_frame *)((cell)(this + 1) + untag_fixnum(length)); }
|
||||||
};
|
};
|
||||||
|
|
|
@ -378,7 +378,6 @@ template<typename Fixup>
|
||||||
void slot_visitor<Fixup>::visit_callstack(context *ctx)
|
void slot_visitor<Fixup>::visit_callstack(context *ctx)
|
||||||
{
|
{
|
||||||
call_frame_slot_visitor<Fixup> call_frame_visitor(parent,this);
|
call_frame_slot_visitor<Fixup> call_frame_visitor(parent,this);
|
||||||
parent->verify_callstack(ctx);
|
|
||||||
parent->iterate_callstack(ctx,call_frame_visitor);
|
parent->iterate_callstack(ctx,call_frame_visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -184,7 +184,6 @@ struct factor_vm
|
||||||
std::set<context *>::const_iterator end = active_contexts.end();
|
std::set<context *>::const_iterator end = active_contexts.end();
|
||||||
while(begin != end)
|
while(begin != end)
|
||||||
{
|
{
|
||||||
verify_callstack(*begin);
|
|
||||||
iterate_callstack(*begin++,iter);
|
iterate_callstack(*begin++,iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -623,6 +622,7 @@ struct factor_vm
|
||||||
|
|
||||||
// callstack
|
// callstack
|
||||||
template<typename Iterator> void iterate_callstack_object(callstack *stack_, Iterator &iterator);
|
template<typename Iterator> void iterate_callstack_object(callstack *stack_, Iterator &iterator);
|
||||||
|
template<typename Iterator> void iterate_callstack_object_reversed(callstack *stack_, Iterator &iterator);
|
||||||
void check_frame(stack_frame *frame);
|
void check_frame(stack_frame *frame);
|
||||||
callstack *allot_callstack(cell size);
|
callstack *allot_callstack(cell size);
|
||||||
stack_frame *second_from_top_stack_frame(context *ctx);
|
stack_frame *second_from_top_stack_frame(context *ctx);
|
||||||
|
@ -643,8 +643,7 @@ struct factor_vm
|
||||||
void primitive_innermost_stack_frame_scan();
|
void primitive_innermost_stack_frame_scan();
|
||||||
void primitive_set_innermost_stack_frame_quot();
|
void primitive_set_innermost_stack_frame_quot();
|
||||||
void primitive_callstack_bounds();
|
void primitive_callstack_bounds();
|
||||||
void verify_callstack(context *ctx);
|
template<typename Iterator> void iterate_callstack_reversed(context *ctx, Iterator &iterator);
|
||||||
void verify_callstack(context *ctx, cell pc);
|
|
||||||
template<typename Iterator> void iterate_callstack(context *ctx, Iterator &iterator);
|
template<typename Iterator> void iterate_callstack(context *ctx, Iterator &iterator);
|
||||||
|
|
||||||
// cpu-*
|
// cpu-*
|
||||||
|
|
Loading…
Reference in New Issue