/* Allocates memory */
cell frame_scan(stack_frame *frame)
{
- if(frame_type(frame) == QUOTATION_TYPE)
+ switch(frame_type(frame))
{
+ case QUOTATION_TYPE:
cell quot = frame_executing(frame);
if(quot == F)
return F;
return tag_fixnum(quot_code_offset_to_scan(
quot,(cell)(return_addr - quot_xt)));
}
- }
- else
+ case WORD_TYPE:
+ return F;
+ default:
+ critical_error("Bad frame type",frame_type(frame));
return F;
+ }
}
namespace
{
-struct stack_frame_counter {
- cell count;
- stack_frame_counter() : count(0) {}
- void operator()(stack_frame *frame) { count += 2; }
-};
-
struct stack_frame_accumulator {
- cell index;
- gc_root<array> frames;
- stack_frame_accumulator(cell count) : index(0), frames(allot_array(count,F)) {}
+ growable_array frames;
+
void operator()(stack_frame *frame)
{
- set_array_nth(frames.untagged(),index++,frame_executing(frame));
- set_array_nth(frames.untagged(),index++,frame_scan(frame));
+ gc_root<object> executing(frame_executing(frame));
+ gc_root<object> scan(frame_scan(frame));
+
+ frames.add(executing.value());
+ frames.add(scan.value());
}
};
{
gc_root<callstack> callstack(dpop());
- stack_frame_counter counter;
- iterate_callstack_object(callstack.untagged(),counter);
-
- stack_frame_accumulator accum(counter.count);
+ stack_frame_accumulator accum;
iterate_callstack_object(callstack.untagged(),accum);
+ accum.frames.trim();
- dpush(accum.frames.value());
+ dpush(accum.frames.elements.value());
}
stack_frame *innermost_stack_frame(callstack *stack)
}
}
-template<typename T> void iterate_callstack_object(callstack *stack, T &iterator)
+/* This is a little tricky. The iterator may allocate memory, so we
+keep the callstack in a GC root and use relative offsets */
+template<typename T> void iterate_callstack_object(callstack *stack_, T &iterator)
{
- iterate_callstack((cell)stack->top(),(cell)stack->bottom(),iterator);
+ gc_root<callstack> stack(stack_);
+ fixnum frame_offset = untag_fixnum(stack->length) - sizeof(stack_frame);
+
+ while(frame_offset >= 0)
+ {
+ stack_frame *frame = stack->frame_at(frame_offset);
+ frame_offset -= frame->size;
+ iterator(frame);
+ }
}
}