]> gitweb.factorcode.org Git - factor.git/blob - vm/contexts.cpp
vm: Add more comments about functions that allocate.
[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->callsite_scrub_d(index);
64
65                 for(cell loc = 0; loc < info->scrub_d_count; loc++)
66                 {
67                         if(bitmap_p(bitmap,base + loc))
68                         {
69 #ifdef DEBUG_GC_MAPS
70                                 std::cout << "scrubbing datastack location " << loc << std::endl;
71 #endif
72                                 *((cell *)datastack - loc) = 0;
73                         }
74                 }
75         }
76
77         {
78                 cell base = info->callsite_scrub_r(index);
79
80                 for(cell loc = 0; loc < info->scrub_r_count; loc++)
81                 {
82                         if(bitmap_p(bitmap,base + loc))
83                         {
84 #ifdef DEBUG_GC_MAPS
85                                 std::cout << "scrubbing retainstack location " << loc << std::endl;
86 #endif
87                                 *((cell *)retainstack - loc) = 0;
88                         }
89                 }
90         }
91 }
92
93 context::~context()
94 {
95         delete datastack_seg;
96         delete retainstack_seg;
97         delete callstack_seg;
98 }
99
100 /* called on startup */
101 void factor_vm::init_contexts(cell datastack_size_, cell retainstack_size_, cell callstack_size_)
102 {
103         datastack_size = datastack_size_;
104         retainstack_size = retainstack_size_;
105         callstack_size = callstack_size_;
106
107         ctx = NULL;
108         spare_ctx = new_context();
109 }
110
111 void factor_vm::delete_contexts()
112 {
113         FACTOR_ASSERT(!ctx);
114         std::list<context *>::const_iterator iter = unused_contexts.begin();
115         std::list<context *>::const_iterator end = unused_contexts.end();
116         while(iter != end)
117         {
118                 delete *iter;
119                 iter++;
120         }
121 }
122
123 context *factor_vm::new_context()
124 {
125         context *new_context;
126
127         if(unused_contexts.empty())
128         {
129                 new_context = new context(datastack_size,
130                         retainstack_size,
131                         callstack_size);
132         }
133         else
134         {
135                 new_context = unused_contexts.back();
136                 unused_contexts.pop_back();
137         }
138
139         new_context->reset();
140
141         active_contexts.insert(new_context);
142
143         return new_context;
144 }
145
146 /* Allocates memory */
147 void factor_vm::init_context(context *ctx)
148 {
149         ctx->context_objects[OBJ_CONTEXT] = allot_alien(ctx);
150 }
151
152 /* Allocates memory */
153 context *new_context(factor_vm *parent)
154 {
155         context *new_context = parent->new_context();
156         parent->init_context(new_context);
157         return new_context;
158 }
159
160 void factor_vm::delete_context(context *old_context)
161 {
162         unused_contexts.push_back(old_context);
163         active_contexts.erase(old_context);
164
165         while(unused_contexts.size() > 10)
166         {
167                 context *stale_context = unused_contexts.front();
168                 unused_contexts.pop_front();
169                 delete stale_context;
170         }
171 }
172
173 VM_C_API void delete_context(factor_vm *parent, context *old_context)
174 {
175         parent->delete_context(old_context);
176 }
177
178 /* Allocates memory */
179 VM_C_API void reset_context(factor_vm *parent, context *ctx)
180 {
181         ctx->reset();
182         parent->init_context(ctx);
183 }
184
185 /* Allocates memory */
186 cell factor_vm::begin_callback(cell quot_)
187 {
188         data_root<object> quot(quot_,this);
189
190         ctx->reset();
191         spare_ctx = new_context();
192         callback_ids.push_back(callback_id++);
193
194         init_context(ctx);
195
196         return quot.value();
197 }
198
199 cell begin_callback(factor_vm *parent, cell quot)
200 {
201         return parent->begin_callback(quot);
202 }
203
204 void factor_vm::end_callback()
205 {
206         callback_ids.pop_back();
207         delete_context(ctx);
208 }
209
210 void end_callback(factor_vm *parent)
211 {
212         parent->end_callback();
213 }
214
215 void factor_vm::primitive_current_callback()
216 {
217         ctx->push(tag_fixnum(callback_ids.back()));
218 }
219
220 void factor_vm::primitive_context_object()
221 {
222         fixnum n = untag_fixnum(ctx->peek());
223         ctx->replace(ctx->context_objects[n]);
224 }
225
226 void factor_vm::primitive_set_context_object()
227 {
228         fixnum n = untag_fixnum(ctx->pop());
229         cell value = ctx->pop();
230         ctx->context_objects[n] = value;
231 }
232
233 void factor_vm::primitive_context_object_for()
234 {
235         context *other_ctx = (context *)pinned_alien_offset(ctx->pop());
236         fixnum n = untag_fixnum(ctx->pop());
237         ctx->push(other_ctx->context_objects[n]);
238 }
239
240 /* Allocates memory */
241 cell factor_vm::stack_to_array(cell bottom, cell top)
242 {
243         fixnum depth = (fixnum)(top - bottom + sizeof(cell));
244
245         if(depth < 0)
246                 return false_object;
247         else
248         {
249                 array *a = allot_uninitialized_array<array>(depth / sizeof(cell));
250                 memcpy(a + 1,(void*)bottom,depth);
251                 return tag<array>(a);
252         }
253 }
254
255 cell factor_vm::datastack_to_array(context *ctx)
256 {
257         cell array = stack_to_array(ctx->datastack_seg->start,ctx->datastack);
258         if(array == false_object)
259         {
260                 general_error(ERROR_DATASTACK_UNDERFLOW,false_object,false_object);
261                 return false_object;
262         }
263         else
264                 return array;
265 }
266
267 void factor_vm::primitive_datastack()
268 {
269         ctx->push(datastack_to_array(ctx));
270 }
271
272 void factor_vm::primitive_datastack_for()
273 {
274         context *other_ctx = (context *)pinned_alien_offset(ctx->pop());
275         ctx->push(datastack_to_array(other_ctx));
276 }
277
278 cell factor_vm::retainstack_to_array(context *ctx)
279 {
280         cell array = stack_to_array(ctx->retainstack_seg->start,ctx->retainstack);
281         if(array == false_object)
282         {
283                 general_error(ERROR_RETAINSTACK_UNDERFLOW,false_object,false_object);
284                 return false_object;
285         }
286         else
287                 return array;
288 }
289
290 void factor_vm::primitive_retainstack()
291 {
292         ctx->push(retainstack_to_array(ctx));
293 }
294
295 void factor_vm::primitive_retainstack_for()
296 {
297         context *other_ctx = (context *)pinned_alien_offset(ctx->pop());
298         ctx->push(retainstack_to_array(other_ctx));
299 }
300
301 /* returns pointer to top of stack */
302 cell factor_vm::array_to_stack(array *array, cell bottom)
303 {
304         cell depth = array_capacity(array) * sizeof(cell);
305         memcpy((void*)bottom,array + 1,depth);
306         return bottom + depth - sizeof(cell);
307 }
308
309 void factor_vm::set_datastack(context *ctx, array *array)
310 {
311         ctx->datastack = array_to_stack(array,ctx->datastack_seg->start);
312 }
313
314 void factor_vm::primitive_set_datastack()
315 {
316         set_datastack(ctx,untag_check<array>(ctx->pop()));
317 }
318
319 void factor_vm::set_retainstack(context *ctx, array *array)
320 {
321         ctx->retainstack = array_to_stack(array,ctx->retainstack_seg->start);
322 }
323
324 void factor_vm::primitive_set_retainstack()
325 {
326         set_retainstack(ctx,untag_check<array>(ctx->pop()));
327 }
328
329 /* Used to implement call( */
330 void factor_vm::primitive_check_datastack()
331 {
332         fixnum out = to_fixnum(ctx->pop());
333         fixnum in = to_fixnum(ctx->pop());
334         fixnum height = out - in;
335         array *saved_datastack = untag_check<array>(ctx->pop());
336         fixnum saved_height = array_capacity(saved_datastack);
337         fixnum current_height = (ctx->datastack - ctx->datastack_seg->start + sizeof(cell)) / sizeof(cell);
338         if(current_height - height != saved_height)
339                 ctx->push(false_object);
340         else
341         {
342                 cell *ds_bot = (cell *)ctx->datastack_seg->start;
343                 for(fixnum i = 0; i < saved_height - in; i++)
344                 {
345                         if(ds_bot[i] != array_nth(saved_datastack,i))
346                         {
347                                 ctx->push(false_object);
348                                 return;
349                         }
350                 }
351                 ctx->push(true_object);
352         }
353 }
354
355 void factor_vm::primitive_load_locals()
356 {
357         fixnum count = untag_fixnum(ctx->pop());
358         memcpy((cell *)(ctx->retainstack + sizeof(cell)),
359                 (cell *)(ctx->datastack - sizeof(cell) * (count - 1)),
360                 sizeof(cell) * count);
361         ctx->datastack -= sizeof(cell) * count;
362         ctx->retainstack += sizeof(cell) * count;
363 }
364
365 }