]> gitweb.factorcode.org Git - factor.git/blob - vm/callstack.cpp
Merge branch 'master' of factorcode.org:/git/factor
[factor.git] / vm / callstack.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 void factor_vm::check_frame(stack_frame *frame)
7 {
8 #ifdef FACTOR_DEBUG
9         check_code_pointer((cell)frame->entry_point);
10         assert(frame->size != 0);
11 #endif
12 }
13
14 callstack *factor_vm::allot_callstack(cell size)
15 {
16         callstack *stack = allot<callstack>(callstack_object_size(size));
17         stack->length = tag_fixnum(size);
18         return stack;
19 }
20
21 /* If 'stack' points into the middle of the frame, find the nearest valid stack
22 pointer where we can resume execution and hope to capture the call trace without
23 crashing. Also, make sure we have at least 'stack_reserved' bytes available so
24 that we don't run out of callstack space while handling the error. */
25 stack_frame *factor_vm::fix_callstack_top(stack_frame *stack)
26 {
27         stack_frame *frame = ctx->callstack_bottom - 1;
28
29         while(frame >= stack
30                 && frame >= ctx->callstack_top
31                 && (cell)frame >= ctx->callstack_seg->start + stack_reserved)
32                 frame = frame_successor(frame);
33
34         return frame + 1;
35 }
36
37 /* We ignore the two topmost frames, the 'callstack' primitive
38 frame itself, and the frame calling the 'callstack' primitive,
39 so that set-callstack doesn't get stuck in an infinite loop.
40
41 This means that if 'callstack' is called in tail position, we
42 will have popped a necessary frame... however this word is only
43 called by continuation implementation, and user code shouldn't
44 be calling it at all, so we leave it as it is for now. */
45 stack_frame *factor_vm::second_from_top_stack_frame(context *ctx)
46 {
47         stack_frame *frame = ctx->callstack_bottom - 1;
48         while(frame >= ctx->callstack_top
49                 && frame_successor(frame) >= ctx->callstack_top
50                 && frame_successor(frame_successor(frame)) >= ctx->callstack_top)
51         {
52                 frame = frame_successor(frame);
53         }
54         return frame + 1;
55 }
56
57 cell factor_vm::capture_callstack(context *ctx)
58 {
59         stack_frame *top = second_from_top_stack_frame(ctx);
60         stack_frame *bottom = ctx->callstack_bottom;
61
62         fixnum size = std::max((fixnum)0,(fixnum)bottom - (fixnum)top);
63
64         callstack *stack = allot_callstack(size);
65         memcpy(stack->top(),top,size);
66         return tag<callstack>(stack);
67 }
68
69 void factor_vm::primitive_callstack()
70 {
71         ctx->push(capture_callstack(ctx));
72 }
73
74 void factor_vm::primitive_callstack_for()
75 {
76         context *other_ctx = (context *)pinned_alien_offset(ctx->pop());
77         ctx->push(capture_callstack(other_ctx));
78 }
79
80 code_block *factor_vm::frame_code(stack_frame *frame)
81 {
82         check_frame(frame);
83         return (code_block *)frame->entry_point - 1;
84 }
85
86 code_block_type factor_vm::frame_type(stack_frame *frame)
87 {
88         return frame_code(frame)->type();
89 }
90
91 cell factor_vm::frame_executing(stack_frame *frame)
92 {
93         return frame_code(frame)->owner;
94 }
95
96 cell factor_vm::frame_executing_quot(stack_frame *frame)
97 {
98         tagged<object> executing(frame_executing(frame));
99         code_block *compiled = frame_code(frame);
100         if(!compiled->optimized_p() && executing->type() == WORD_TYPE)
101                 executing = executing.as<word>()->def;
102         return executing.value();
103 }
104
105 stack_frame *factor_vm::frame_successor(stack_frame *frame)
106 {
107         check_frame(frame);
108         return (stack_frame *)((cell)frame - frame->size);
109 }
110
111 cell factor_vm::frame_offset(stack_frame *frame)
112 {
113         char *entry_point = (char *)frame_code(frame)->entry_point();
114         char *return_address = (char *)FRAME_RETURN_ADDRESS(frame,this);
115         if(return_address)
116                 return return_address - entry_point;
117         else
118                 return (cell)-1;
119 }
120
121 void factor_vm::set_frame_offset(stack_frame *frame, cell offset)
122 {
123         char *entry_point = (char *)frame_code(frame)->entry_point();
124         if(offset == (cell)-1)
125                 FRAME_RETURN_ADDRESS(frame,this) = NULL;
126         else
127                 FRAME_RETURN_ADDRESS(frame,this) = entry_point + offset;
128 }
129
130 void factor_vm::scrub_return_address()
131 {
132         stack_frame *top = ctx->callstack_top;
133         stack_frame *bottom = ctx->callstack_bottom;
134         stack_frame *frame = bottom - 1;
135
136         while(frame >= top && frame_successor(frame) >= top)
137                 frame = frame_successor(frame);
138
139         set_frame_offset(frame,0);
140
141 #ifdef FACTOR_DEBUG
142         /* Doing a GC here triggers all kinds of funny errors */
143         primitive_compact_gc();
144 #endif
145 }
146
147 cell factor_vm::frame_scan(stack_frame *frame)
148 {
149         switch(frame_type(frame))
150         {
151         case code_block_unoptimized:
152                 {
153                         tagged<object> obj(frame_executing(frame));
154                         if(obj.type_p(WORD_TYPE))
155                                 obj = obj.as<word>()->def;
156
157                         if(obj.type_p(QUOTATION_TYPE))
158                                 return tag_fixnum(quot_code_offset_to_scan(obj.value(),frame_offset(frame)));
159                         else
160                                 return false_object;
161                 }
162         case code_block_optimized:
163                 return false_object;
164         default:
165                 critical_error("Bad frame type",frame_type(frame));
166                 return false_object;
167         }
168 }
169
170 struct stack_frame_accumulator {
171         factor_vm *parent;
172         growable_array frames;
173
174         explicit stack_frame_accumulator(factor_vm *parent_) : parent(parent_), frames(parent_) {} 
175
176         void operator()(stack_frame *frame)
177         {
178                 data_root<object> executing_quot(parent->frame_executing_quot(frame),parent);
179                 data_root<object> executing(parent->frame_executing(frame),parent);
180                 data_root<object> scan(parent->frame_scan(frame),parent);
181
182                 frames.add(executing.value());
183                 frames.add(executing_quot.value());
184                 frames.add(scan.value());
185         }
186 };
187
188 void factor_vm::primitive_callstack_to_array()
189 {
190         data_root<callstack> callstack(ctx->pop(),this);
191
192         stack_frame_accumulator accum(this);
193         iterate_callstack_object(callstack.untagged(),accum);
194         accum.frames.trim();
195
196         ctx->push(accum.frames.elements.value());
197 }
198
199 stack_frame *factor_vm::innermost_stack_frame(callstack *stack)
200 {
201         stack_frame *top = stack->top();
202         stack_frame *bottom = stack->bottom();
203         stack_frame *frame = bottom - 1;
204
205         while(frame >= top && frame_successor(frame) >= top)
206                 frame = frame_successor(frame);
207
208         return frame;
209 }
210
211 /* Some primitives implementing a limited form of callstack mutation.
212 Used by the single stepper. */
213 void factor_vm::primitive_innermost_stack_frame_executing()
214 {
215         stack_frame *frame = innermost_stack_frame(untag_check<callstack>(ctx->pop()));
216         ctx->push(frame_executing_quot(frame));
217 }
218
219 void factor_vm::primitive_innermost_stack_frame_scan()
220 {
221         stack_frame *frame = innermost_stack_frame(untag_check<callstack>(ctx->pop()));
222         ctx->push(frame_scan(frame));
223 }
224
225 void factor_vm::primitive_set_innermost_stack_frame_quot()
226 {
227         data_root<callstack> callstack(ctx->pop(),this);
228         data_root<quotation> quot(ctx->pop(),this);
229
230         callstack.untag_check(this);
231         quot.untag_check(this);
232
233         jit_compile_quot(quot.value(),true);
234
235         stack_frame *inner = innermost_stack_frame(callstack.untagged());
236         cell offset = frame_offset(inner);
237         inner->entry_point = quot->entry_point;
238         set_frame_offset(inner,offset);
239 }
240
241 void factor_vm::primitive_callstack_bounds()
242 {
243         ctx->push(allot_alien((void*)ctx->callstack_seg->start));
244         ctx->push(allot_alien((void*)ctx->callstack_seg->end));
245 }
246
247 }