factor/vm/callstack.cpp

246 lines
6.5 KiB
C++
Raw Normal View History

2009-05-02 05:04:19 -04:00
#include "master.hpp"
2009-05-04 02:46:13 -04:00
namespace factor
{
2009-09-23 14:05:46 -04:00
void factor_vm::check_frame(stack_frame *frame)
2009-05-02 21:01:54 -04:00
{
#ifdef FACTOR_DEBUG
check_code_pointer((cell)frame->entry_point);
2009-05-02 21:01:54 -04:00
assert(frame->size != 0);
#endif
}
2009-09-23 14:05:46 -04:00
callstack *factor_vm::allot_callstack(cell size)
2009-05-02 05:04:19 -04:00
{
callstack *stack = allot<callstack>(callstack_object_size(size));
2009-05-04 05:50:24 -04:00
stack->length = tag_fixnum(size);
return stack;
2009-05-02 05:04:19 -04:00
}
void factor_vm::dispatch_signal_handler(cell *sp, cell *pc, cell newpc)
{
/* True stack frames are always 16-byte aligned. Leaf procedures
that don't create a stack frame will be out of alignment by sizeof(cell)
bytes. */
cell offset = *sp % 16;
if (offset == 0) {
signal_from_leaf = false;
cell newsp = *sp - sizeof(cell);
*sp = newsp;
*(cell*)newsp = *pc;
*pc = newpc;
ctx->callstack_top = (stack_frame*)newsp;
} else if (offset == 16 - sizeof(cell)) {
dispatch_signal_handler_from_leaf(sp, pc, newpc);
} else {
fatal_error("Invalid stack frame during signal handler", *sp);
}
}
void factor_vm::dispatch_signal_handler_from_leaf(cell *sp, cell *pc, cell newpc)
{
/* We should try to conjure a stack frame here, but we may need to deal
with callstack overflows or the GC moving code around.
For now leave the stack untouched so the signal handler returns into
the parent procedure. This will cause things to blow up if the stack
is left unbalanced. */
signal_from_leaf = true;
*pc = newpc;
}
/* We ignore the two topmost frames, the 'callstack' primitive
frame itself, and the frame calling the 'callstack' primitive,
2009-05-02 05:04:19 -04:00
so that set-callstack doesn't get stuck in an infinite loop.
This means that if 'callstack' is called in tail position, we
will have popped a necessary frame... however this word is only
called by continuation implementation, and user code shouldn't
be calling it at all, so we leave it as it is for now. */
stack_frame *factor_vm::second_from_top_stack_frame(context *ctx)
2009-05-02 05:04:19 -04:00
{
stack_frame *frame = ctx->callstack_bottom - 1;
while(frame >= ctx->callstack_top
&& frame_successor(frame) >= ctx->callstack_top
&& frame_successor(frame_successor(frame)) >= ctx->callstack_top)
{
2009-05-02 05:04:19 -04:00
frame = frame_successor(frame);
}
2009-05-02 05:04:19 -04:00
return frame + 1;
}
cell factor_vm::capture_callstack(context *ctx)
2009-05-02 05:04:19 -04:00
{
stack_frame *top = second_from_top_stack_frame(ctx);
stack_frame *bottom = ctx->callstack_bottom;
2009-05-02 05:04:19 -04:00
fixnum size = std::max((fixnum)0,(fixnum)bottom - (fixnum)top);
2009-05-02 05:04:19 -04:00
2009-05-04 05:50:24 -04:00
callstack *stack = allot_callstack(size);
memcpy(stack->top(),top,size);
return tag<callstack>(stack);
}
void factor_vm::primitive_callstack()
{
ctx->push(capture_callstack(ctx));
}
void factor_vm::primitive_callstack_for()
{
context *other_ctx = (context *)pinned_alien_offset(ctx->pop());
ctx->push(capture_callstack(other_ctx));
2009-05-02 05:04:19 -04:00
}
2009-09-23 14:05:46 -04:00
code_block *factor_vm::frame_code(stack_frame *frame)
2009-05-02 05:04:19 -04:00
{
2009-05-02 21:01:54 -04:00
check_frame(frame);
return (code_block *)frame->entry_point - 1;
2009-05-02 05:04:19 -04:00
}
code_block_type factor_vm::frame_type(stack_frame *frame)
2009-05-02 05:04:19 -04:00
{
return frame_code(frame)->type();
2009-05-02 05:04:19 -04:00
}
2009-09-23 14:05:46 -04:00
cell factor_vm::frame_executing(stack_frame *frame)
2009-05-02 05:04:19 -04:00
{
return frame_code(frame)->owner;
2009-05-02 05:04:19 -04:00
}
2009-12-02 17:57:39 -05:00
cell factor_vm::frame_executing_quot(stack_frame *frame)
{
tagged<object> executing(frame_executing(frame));
code_block *compiled = frame_code(frame);
if(!compiled->optimized_p() && executing->type() == WORD_TYPE)
executing = executing.as<word>()->def;
return executing.value();
}
2009-09-23 14:05:46 -04:00
stack_frame *factor_vm::frame_successor(stack_frame *frame)
2009-05-02 05:04:19 -04:00
{
2009-05-02 21:01:54 -04:00
check_frame(frame);
2009-05-04 05:50:24 -04:00
return (stack_frame *)((cell)frame - frame->size);
2009-05-02 05:04:19 -04:00
}
cell factor_vm::frame_offset(stack_frame *frame)
{
char *entry_point = (char *)frame_code(frame)->entry_point();
char *return_address = (char *)FRAME_RETURN_ADDRESS(frame,this);
if(return_address)
return return_address - entry_point;
else
return (cell)-1;
}
void factor_vm::set_frame_offset(stack_frame *frame, cell offset)
{
char *entry_point = (char *)frame_code(frame)->entry_point();
if(offset == (cell)-1)
FRAME_RETURN_ADDRESS(frame,this) = NULL;
else
FRAME_RETURN_ADDRESS(frame,this) = entry_point + offset;
}
2009-09-23 14:05:46 -04:00
cell factor_vm::frame_scan(stack_frame *frame)
2009-05-02 05:04:19 -04:00
{
switch(frame_type(frame))
2009-05-02 05:04:19 -04:00
{
case code_block_unoptimized:
2009-05-02 05:04:19 -04:00
{
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;
2009-05-02 05:04:19 -04:00
}
case code_block_optimized:
return false_object;
default:
critical_error("Bad frame type",frame_type(frame));
return false_object;
}
2009-05-02 05:04:19 -04:00
}
struct stack_frame_accumulator {
factor_vm *parent;
growable_array frames;
explicit stack_frame_accumulator(factor_vm *parent_) : parent(parent_), frames(parent_) {}
void operator()(stack_frame *frame)
{
data_root<object> executing_quot(parent->frame_executing_quot(frame),parent);
data_root<object> executing(parent->frame_executing(frame),parent);
data_root<object> scan(parent->frame_scan(frame),parent);
frames.add(executing.value());
frames.add(executing_quot.value());
frames.add(scan.value());
}
};
2009-05-02 05:04:19 -04:00
void factor_vm::primitive_callstack_to_array()
2009-05-02 05:04:19 -04:00
{
data_root<callstack> callstack(ctx->pop(),this);
2009-05-02 05:04:19 -04:00
stack_frame_accumulator accum(this);
iterate_callstack_object(callstack.untagged(),accum);
accum.frames.trim();
2009-05-02 05:04:19 -04:00
ctx->push(accum.frames.elements.value());
2009-05-02 05:04:19 -04:00
}
stack_frame *factor_vm::innermost_stack_frame(stack_frame *bottom, stack_frame *top)
2009-05-02 05:04:19 -04:00
{
stack_frame *frame = bottom - 1;
2009-05-02 05:04:19 -04:00
while(frame >= top && frame_successor(frame) >= top)
frame = frame_successor(frame);
return frame;
}
/* Some primitives implementing a limited form of callstack mutation.
Used by the single stepper. */
void factor_vm::primitive_innermost_stack_frame_executing()
2009-05-02 05:04:19 -04:00
{
callstack *stack = untag_check<callstack>(ctx->pop());
stack_frame *frame = innermost_stack_frame(stack->bottom(), stack->top());
ctx->push(frame_executing_quot(frame));
2009-05-02 05:04:19 -04:00
}
void factor_vm::primitive_innermost_stack_frame_scan()
2009-05-02 05:04:19 -04:00
{
callstack *stack = untag_check<callstack>(ctx->pop());
stack_frame *frame = innermost_stack_frame(stack->bottom(), stack->top());
ctx->push(frame_scan(frame));
2009-05-02 05:04:19 -04:00
}
void factor_vm::primitive_set_innermost_stack_frame_quot()
2009-05-02 05:04:19 -04:00
{
data_root<callstack> stack(ctx->pop(),this);
data_root<quotation> quot(ctx->pop(),this);
2009-05-02 05:04:19 -04:00
stack.untag_check(this);
2009-08-17 16:37:15 -04:00
quot.untag_check(this);
2009-05-02 05:04:19 -04:00
jit_compile_quot(quot.value(),true);
2009-05-02 05:04:19 -04:00
stack_frame *inner = innermost_stack_frame(stack->bottom(), stack->top());
cell offset = frame_offset(inner);
inner->entry_point = quot->entry_point;
set_frame_offset(inner,offset);
2009-05-02 05:04:19 -04:00
}
void factor_vm::primitive_callstack_bounds()
{
ctx->push(allot_alien((void*)ctx->callstack_seg->start));
ctx->push(allot_alien((void*)ctx->callstack_seg->end));
}
2009-05-04 02:46:13 -04:00
}