]> gitweb.factorcode.org Git - factor.git/blob - vm/contexts.cpp
vm: actually use context callstacks when running code
[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 context::~context()
48 {
49         delete datastack_seg;
50         delete retainstack_seg;
51         delete callstack_seg;
52 }
53
54 /* called on startup */
55 void factor_vm::init_contexts(cell datastack_size_, cell retainstack_size_, cell callstack_size_)
56 {
57         datastack_size = datastack_size_;
58         retainstack_size = retainstack_size_;
59         callstack_size = callstack_size_;
60
61         ctx = NULL;
62         spare_ctx = new_context();
63 }
64
65 void factor_vm::delete_contexts()
66 {
67         assert(!ctx);
68         std::vector<context *>::const_iterator iter = unused_contexts.begin();
69         std::vector<context *>::const_iterator end = unused_contexts.end();
70         while(iter != end)
71         {
72                 delete *iter;
73                 iter++;
74         }
75 }
76
77 context *factor_vm::new_context()
78 {
79         context *new_context;
80
81         if(unused_contexts.empty())
82         {
83                 new_context = new context(datastack_size,
84                         retainstack_size,
85                         callstack_size);
86         }
87         else
88         {
89                 new_context = unused_contexts.back();
90                 unused_contexts.pop_back();
91         }
92
93         new_context->reset();
94
95         active_contexts.insert(new_context);
96
97         return new_context;
98 }
99
100 void factor_vm::delete_context(context *old_context)
101 {
102         unused_contexts.push_back(old_context);
103         active_contexts.erase(old_context);
104 }
105
106 void factor_vm::begin_callback()
107 {
108         ctx->reset();
109         spare_ctx = new_context();
110         callback_ids.push_back(callback_id++);
111 }
112
113 void begin_callback(factor_vm *parent)
114 {
115         parent->begin_callback();
116 }
117
118 void factor_vm::end_callback()
119 {
120         callback_ids.pop_back();
121         delete_context(ctx);
122 }
123
124 void end_callback(factor_vm *parent)
125 {
126         parent->end_callback();
127 }
128
129 void factor_vm::primitive_current_callback()
130 {
131         ctx->push(tag_fixnum(callback_ids.back()));
132 }
133
134 void factor_vm::primitive_context_object()
135 {
136         fixnum n = untag_fixnum(ctx->peek());
137         ctx->replace(ctx->context_objects[n]);
138 }
139
140 void factor_vm::primitive_set_context_object()
141 {
142         fixnum n = untag_fixnum(ctx->pop());
143         cell value = ctx->pop();
144         ctx->context_objects[n] = value;
145 }
146
147 bool factor_vm::stack_to_array(cell bottom, cell top)
148 {
149         fixnum depth = (fixnum)(top - bottom + sizeof(cell));
150
151         if(depth < 0)
152                 return false;
153         else
154         {
155                 array *a = allot_uninitialized_array<array>(depth / sizeof(cell));
156                 memcpy(a + 1,(void*)bottom,depth);
157                 ctx->push(tag<array>(a));
158                 return true;
159         }
160 }
161
162 void factor_vm::primitive_datastack()
163 {
164         if(!stack_to_array(ctx->datastack_seg->start,ctx->datastack))
165                 general_error(ERROR_DS_UNDERFLOW,false_object,false_object,NULL);
166 }
167
168 void factor_vm::primitive_retainstack()
169 {
170         if(!stack_to_array(ctx->retainstack_seg->start,ctx->retainstack))
171                 general_error(ERROR_RS_UNDERFLOW,false_object,false_object,NULL);
172 }
173
174 /* returns pointer to top of stack */
175 cell factor_vm::array_to_stack(array *array, cell bottom)
176 {
177         cell depth = array_capacity(array) * sizeof(cell);
178         memcpy((void*)bottom,array + 1,depth);
179         return bottom + depth - sizeof(cell);
180 }
181
182 void factor_vm::primitive_set_datastack()
183 {
184         ctx->datastack = array_to_stack(untag_check<array>(ctx->pop()),ctx->datastack_seg->start);
185 }
186
187 void factor_vm::primitive_set_retainstack()
188 {
189         ctx->retainstack = array_to_stack(untag_check<array>(ctx->pop()),ctx->retainstack_seg->start);
190 }
191
192 /* Used to implement call( */
193 void factor_vm::primitive_check_datastack()
194 {
195         fixnum out = to_fixnum(ctx->pop());
196         fixnum in = to_fixnum(ctx->pop());
197         fixnum height = out - in;
198         array *saved_datastack = untag_check<array>(ctx->pop());
199         fixnum saved_height = array_capacity(saved_datastack);
200         fixnum current_height = (ctx->datastack - ctx->datastack_seg->start + sizeof(cell)) / sizeof(cell);
201         if(current_height - height != saved_height)
202                 ctx->push(false_object);
203         else
204         {
205                 cell *ds_bot = (cell *)ctx->datastack_seg->start;
206                 for(fixnum i = 0; i < saved_height - in; i++)
207                 {
208                         if(ds_bot[i] != array_nth(saved_datastack,i))
209                         {
210                                 ctx->push(false_object);
211                                 return;
212                         }
213                 }
214                 ctx->push(true_object);
215         }
216 }
217
218 void factor_vm::primitive_load_locals()
219 {
220         fixnum count = untag_fixnum(ctx->pop());
221         memcpy((cell *)(ctx->retainstack + sizeof(cell)),
222                 (cell *)(ctx->datastack - sizeof(cell) * (count - 1)),
223                 sizeof(cell) * count);
224         ctx->datastack -= sizeof(cell) * count;
225         ctx->retainstack += sizeof(cell) * count;
226 }
227
228 void factor_vm::primitive_current_context()
229 {
230         ctx->push(allot_alien(ctx));
231 }
232
233 void factor_vm::primitive_start_context()
234 {
235         cell quot = ctx->pop();
236         ctx = new_context();
237         unwind_native_frames(quot,ctx->callstack_bottom);
238 }
239
240 void factor_vm::primitive_delete_context()
241 {
242         context *old_context = (context *)pinned_alien_offset(ctx->pop());
243         delete_context(old_context);
244 }
245
246 }