]> gitweb.factorcode.org Git - factor.git/blob - vm/callstack.cpp
VM: the frame_return_address and set_frame_return_address functions aren't needed...
[factor.git] / vm / callstack.cpp
1 #include "master.hpp"
2
3 namespace factor {
4
5 /* Allocates memory (allot) */
6 callstack* factor_vm::allot_callstack(cell size) {
7   callstack* stack = allot<callstack>(callstack_object_size(size));
8   stack->length = tag_fixnum(size);
9   return stack;
10 }
11
12 /* We ignore the two topmost frames, the 'callstack' primitive
13 frame itself, and the frame calling the 'callstack' primitive,
14 so that set-callstack doesn't get stuck in an infinite loop.
15
16 This means that if 'callstack' is called in tail position, we
17 will have popped a necessary frame... however this word is only
18 called by continuation implementation, and user code shouldn't
19 be calling it at all, so we leave it as it is for now. */
20 void* factor_vm::second_from_top_stack_frame(context* ctx) {
21   void* frame_top = ctx->callstack_top;
22   for (cell i = 0; i < 2; ++i) {
23     void* pred = frame_predecessor(frame_top);
24     if (pred >= ctx->callstack_bottom)
25       return frame_top;
26     frame_top = pred;
27   }
28   return frame_top;
29 }
30
31 /* Allocates memory (allot_callstack) */
32 cell factor_vm::capture_callstack(context* ctx) {
33   void* top = second_from_top_stack_frame(ctx);
34   void* bottom = ctx->callstack_bottom;
35
36   fixnum size = std::max((fixnum)0, (fixnum)bottom - (fixnum)top);
37
38   callstack* stack = allot_callstack(size);
39   memcpy(stack->top(), top, size);
40   return tag<callstack>(stack);
41 }
42
43 /* Allocates memory (capture_callstack) */
44 void factor_vm::primitive_callstack() { ctx->push(capture_callstack(ctx)); }
45
46 /* Allocates memory (capture_callstack) */
47 void factor_vm::primitive_callstack_for() {
48   context* other_ctx = (context*)pinned_alien_offset(ctx->peek());
49   ctx->replace(capture_callstack(other_ctx));
50 }
51
52 void* factor_vm::frame_predecessor(void* frame_top) {
53   void* addr = *(void**)frame_top;
54   FACTOR_ASSERT(addr != 0);
55   code_block* owner = code->code_block_for_address((cell)addr);
56   cell frame_size = owner->stack_frame_size_for_address((cell)addr);
57   return (void*)((char*)frame_top + frame_size);
58 }
59
60 struct stack_frame_accumulator {
61   factor_vm* parent;
62   growable_array frames;
63
64   /* Allocates memory (frames is a growable_array, constructor allocates) */
65   explicit stack_frame_accumulator(factor_vm* parent)
66       : parent(parent), frames(parent) {}
67
68
69   /* Allocates memory (frames.add()) */
70   void operator()(void* frame_top, cell frame_size, code_block* owner,
71                   void* addr) {
72     data_root<object> executing_quot(owner->owner_quot(), parent);
73     data_root<object> executing(owner->owner, parent);
74     data_root<object> scan(owner->scan(parent, addr), parent);
75
76     frames.add(executing.value());
77     frames.add(executing_quot.value());
78     frames.add(scan.value());
79   }
80 };
81
82 struct stack_frame_in_array {
83   cell cells[3];
84 };
85
86 /* Allocates memory (frames.trim()), iterate_callstack_object() */
87 void factor_vm::primitive_callstack_to_array() {
88   data_root<callstack> callstack(ctx->peek(), this);
89
90   stack_frame_accumulator accum(this);
91   iterate_callstack_object(callstack.untagged(), accum);
92
93   /* The callstack iterator visits frames in reverse order (top to bottom) */
94   std::reverse((stack_frame_in_array*)accum.frames.elements->data(),
95                (stack_frame_in_array*)(accum.frames.elements->data() +
96                                        accum.frames.count));
97
98   accum.frames.trim();
99
100   ctx->replace(accum.frames.elements.value());
101
102 }
103
104 /* Some primitives implementing a limited form of callstack mutation.
105 Used by the single stepper. */
106 void factor_vm::primitive_innermost_stack_frame_executing() {
107   callstack* stack = untag_check<callstack>(ctx->peek());
108   void* frame = stack->top();
109   void* addr = *(void**)frame;
110   ctx->replace(code->code_block_for_address((cell)addr)->owner_quot());
111 }
112
113 void factor_vm::primitive_innermost_stack_frame_scan() {
114   callstack* stack = untag_check<callstack>(ctx->peek());
115   void* frame = stack->top();
116   void* addr = *(void**)frame;
117   ctx->replace(code->code_block_for_address((cell)addr)->scan(this, addr));
118 }
119
120 /* Allocates memory (jit_compile_quot) */
121 void factor_vm::primitive_set_innermost_stack_frame_quot() {
122   data_root<callstack> stack(ctx->pop(), this);
123   data_root<quotation> quot(ctx->pop(), this);
124
125   stack.untag_check(this);
126   quot.untag_check(this);
127
128   jit_compile_quot(quot.value(), true);
129
130   void* inner = stack->top();
131   void* addr = *(void**)inner;
132   code_block* block = code->code_block_for_address((cell)addr);
133   cell offset = block->offset(addr);
134   *(void**)inner = (char*)quot->entry_point + offset;
135 }
136
137 /* Allocates memory (allot_alien) */
138 void factor_vm::primitive_callstack_bounds() {
139   ctx->push(allot_alien((void*)ctx->callstack_seg->start));
140   ctx->push(allot_alien((void*)ctx->callstack_seg->end));
141 }
142
143 }