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