]> gitweb.factorcode.org Git - factor.git/blob - vm/contexts.cpp
GC maps for more compact inline GC checks
[factor.git] / vm / contexts.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 context::context(cell datastack_size, cell retainstack_size, cell callstack_size) :
7         callstack_top(NULL),
8         callstack_bottom(NULL),
9         datastack(0),
10         retainstack(0),
11         callstack_save(0),
12         datastack_seg(new segment(datastack_size,false)),
13         retainstack_seg(new segment(retainstack_size,false)),
14         callstack_seg(new segment(callstack_size,false))
15 {
16         reset();
17 }
18
19 void context::reset_datastack()
20 {
21         datastack = datastack_seg->start - sizeof(cell);
22 }
23
24 void context::reset_retainstack()
25 {
26         retainstack = retainstack_seg->start - sizeof(cell);
27 }
28
29 void context::reset_callstack()
30 {
31         callstack_top = callstack_bottom = CALLSTACK_BOTTOM(this);
32 }
33
34 void context::reset_context_objects()
35 {
36         memset_cell(context_objects,false_object,context_object_count * sizeof(cell));
37 }
38
39 void context::reset()
40 {
41         reset_datastack();
42         reset_retainstack();
43         reset_callstack();
44         reset_context_objects();
45 }
46
47 void context::fix_stacks()
48 {
49         if(datastack + sizeof(cell) < datastack_seg->start
50                 || datastack + stack_reserved >= datastack_seg->end)
51                 reset_datastack();
52
53         if(retainstack + sizeof(cell) < retainstack_seg->start
54                 || retainstack + stack_reserved >= retainstack_seg->end)
55                 reset_retainstack();
56 }
57
58 void context::scrub_stacks(gc_info *info, cell index)
59 {
60         u8 *bitmap = info->gc_info_bitmap();
61
62         {
63                 cell base = info->scrub_d_base(index);
64
65                 for(cell loc = 0; loc < info->scrub_d_count; loc++)
66                 {
67                         if(bitmap_p(bitmap,base + loc))
68                                 ((cell *)datastack)[-loc] = 0;
69                 }
70         }
71
72         {
73                 cell base = info->scrub_r_base(index);
74
75                 for(cell loc = 0; loc < info->scrub_r_count; loc++)
76                 {
77                         if(bitmap_p(bitmap,base + loc))
78                                 printf("scrub retainstack %ld\n",loc);
79                 }
80         }
81 }
82
83 context::~context()
84 {
85         delete datastack_seg;
86         delete retainstack_seg;
87         delete callstack_seg;
88 }
89
90 /* called on startup */
91 void factor_vm::init_contexts(cell datastack_size_, cell retainstack_size_, cell callstack_size_)
92 {
93         datastack_size = datastack_size_;
94         retainstack_size = retainstack_size_;
95         callstack_size = callstack_size_;
96
97         ctx = NULL;
98         spare_ctx = new_context();
99 }
100
101 void factor_vm::delete_contexts()
102 {
103         assert(!ctx);
104         std::vector<context *>::const_iterator iter = unused_contexts.begin();
105         std::vector<context *>::const_iterator end = unused_contexts.end();
106         while(iter != end)
107         {
108                 delete *iter;
109                 iter++;
110         }
111 }
112
113 context *factor_vm::new_context()
114 {
115         context *new_context;
116
117         if(unused_contexts.empty())
118         {
119                 new_context = new context(datastack_size,
120                         retainstack_size,
121                         callstack_size);
122         }
123         else
124         {
125                 new_context = unused_contexts.back();
126                 unused_contexts.pop_back();
127         }
128
129         new_context->reset();
130
131         active_contexts.insert(new_context);
132
133         return new_context;
134 }
135
136 void factor_vm::init_context(context *ctx)
137 {
138         ctx->context_objects[OBJ_CONTEXT] = allot_alien(ctx);
139 }
140
141 context *new_context(factor_vm *parent)
142 {
143         context *new_context = parent->new_context();
144         parent->init_context(new_context);
145         return new_context;
146 }
147
148 void factor_vm::delete_context(context *old_context)
149 {
150         unused_contexts.push_back(old_context);
151         active_contexts.erase(old_context);
152 }
153
154 VM_C_API void delete_context(factor_vm *parent, context *old_context)
155 {
156         parent->delete_context(old_context);
157 }
158
159 cell factor_vm::begin_callback(cell quot_)
160 {
161         data_root<object> quot(quot_,this);
162
163         ctx->reset();
164         spare_ctx = new_context();
165         callback_ids.push_back(callback_id++);
166
167         init_context(ctx);
168
169         return quot.value();
170 }
171
172 cell begin_callback(factor_vm *parent, cell quot)
173 {
174         return parent->begin_callback(quot);
175 }
176
177 void factor_vm::end_callback()
178 {
179         callback_ids.pop_back();
180         delete_context(ctx);
181 }
182
183 void end_callback(factor_vm *parent)
184 {
185         parent->end_callback();
186 }
187
188 void factor_vm::primitive_current_callback()
189 {
190         ctx->push(tag_fixnum(callback_ids.back()));
191 }
192
193 void factor_vm::primitive_context_object()
194 {
195         fixnum n = untag_fixnum(ctx->peek());
196         ctx->replace(ctx->context_objects[n]);
197 }
198
199 void factor_vm::primitive_set_context_object()
200 {
201         fixnum n = untag_fixnum(ctx->pop());
202         cell value = ctx->pop();
203         ctx->context_objects[n] = value;
204 }
205
206 void factor_vm::primitive_context_object_for()
207 {
208         context *other_ctx = (context *)pinned_alien_offset(ctx->pop());
209         fixnum n = untag_fixnum(ctx->pop());
210         ctx->push(other_ctx->context_objects[n]);
211 }
212
213 cell factor_vm::stack_to_array(cell bottom, cell top)
214 {
215         fixnum depth = (fixnum)(top - bottom + sizeof(cell));
216
217         if(depth < 0)
218                 return false_object;
219         else
220         {
221                 array *a = allot_uninitialized_array<array>(depth / sizeof(cell));
222                 memcpy(a + 1,(void*)bottom,depth);
223                 return tag<array>(a);
224         }
225 }
226
227 cell factor_vm::datastack_to_array(context *ctx)
228 {
229         cell array = stack_to_array(ctx->datastack_seg->start,ctx->datastack);
230         if(array == false_object)
231         {
232                 general_error(ERROR_DATASTACK_UNDERFLOW,false_object,false_object);
233                 return false_object;
234         }
235         else
236                 return array;
237 }
238
239 void factor_vm::primitive_datastack()
240 {
241         ctx->push(datastack_to_array(ctx));
242 }
243
244 void factor_vm::primitive_datastack_for()
245 {
246         context *other_ctx = (context *)pinned_alien_offset(ctx->pop());
247         ctx->push(datastack_to_array(other_ctx));
248 }
249
250 cell factor_vm::retainstack_to_array(context *ctx)
251 {
252         cell array = stack_to_array(ctx->retainstack_seg->start,ctx->retainstack);
253         if(array == false_object)
254         {
255                 general_error(ERROR_RETAINSTACK_UNDERFLOW,false_object,false_object);
256                 return false_object;
257         }
258         else
259                 return array;
260 }
261
262 void factor_vm::primitive_retainstack()
263 {
264         ctx->push(retainstack_to_array(ctx));
265 }
266
267 void factor_vm::primitive_retainstack_for()
268 {
269         context *other_ctx = (context *)pinned_alien_offset(ctx->pop());
270         ctx->push(retainstack_to_array(other_ctx));
271 }
272
273 /* returns pointer to top of stack */
274 cell factor_vm::array_to_stack(array *array, cell bottom)
275 {
276         cell depth = array_capacity(array) * sizeof(cell);
277         memcpy((void*)bottom,array + 1,depth);
278         return bottom + depth - sizeof(cell);
279 }
280
281 void factor_vm::set_datastack(context *ctx, array *array)
282 {
283         ctx->datastack = array_to_stack(array,ctx->datastack_seg->start);
284 }
285
286 void factor_vm::primitive_set_datastack()
287 {
288         set_datastack(ctx,untag_check<array>(ctx->pop()));
289 }
290
291 void factor_vm::set_retainstack(context *ctx, array *array)
292 {
293         ctx->retainstack = array_to_stack(array,ctx->retainstack_seg->start);
294 }
295
296 void factor_vm::primitive_set_retainstack()
297 {
298         set_retainstack(ctx,untag_check<array>(ctx->pop()));
299 }
300
301 /* Used to implement call( */
302 void factor_vm::primitive_check_datastack()
303 {
304         fixnum out = to_fixnum(ctx->pop());
305         fixnum in = to_fixnum(ctx->pop());
306         fixnum height = out - in;
307         array *saved_datastack = untag_check<array>(ctx->pop());
308         fixnum saved_height = array_capacity(saved_datastack);
309         fixnum current_height = (ctx->datastack - ctx->datastack_seg->start + sizeof(cell)) / sizeof(cell);
310         if(current_height - height != saved_height)
311                 ctx->push(false_object);
312         else
313         {
314                 cell *ds_bot = (cell *)ctx->datastack_seg->start;
315                 for(fixnum i = 0; i < saved_height - in; i++)
316                 {
317                         if(ds_bot[i] != array_nth(saved_datastack,i))
318                         {
319                                 ctx->push(false_object);
320                                 return;
321                         }
322                 }
323                 ctx->push(true_object);
324         }
325 }
326
327 void factor_vm::primitive_load_locals()
328 {
329         fixnum count = untag_fixnum(ctx->pop());
330         memcpy((cell *)(ctx->retainstack + sizeof(cell)),
331                 (cell *)(ctx->datastack - sizeof(cell) * (count - 1)),
332                 sizeof(cell) * count);
333         ctx->datastack -= sizeof(cell) * count;
334         ctx->retainstack += sizeof(cell) * count;
335 }
336
337 }