]> gitweb.factorcode.org Git - factor.git/blob - vm/contexts.cpp
f5c63f1e7fab2cbace0097c5cdf4f3588e02a0da
[factor.git] / vm / contexts.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6
7 void factorvm::reset_datastack()
8 {
9         ds = ds_bot - sizeof(cell);
10 }
11
12 void factorvm::reset_retainstack()
13 {
14         rs = rs_bot - sizeof(cell);
15 }
16
17 static const cell stack_reserved = (64 * sizeof(cell));
18
19 void factorvm::fix_stacks()
20 {
21         if(ds + sizeof(cell) < ds_bot || ds + stack_reserved >= ds_top) reset_datastack();
22         if(rs + sizeof(cell) < rs_bot || rs + stack_reserved >= rs_top) reset_retainstack();
23 }
24
25 /* called before entry into foreign C code. Note that ds and rs might
26 be stored in registers, so callbacks must save and restore the correct values */
27 void factorvm::save_stacks()
28 {
29         if(stack_chain)
30         {
31                 stack_chain->datastack = ds;
32                 stack_chain->retainstack = rs;
33         }
34 }
35
36 context *factorvm::alloc_context()
37 {
38         context *new_context;
39
40         if(unused_contexts)
41         {
42                 new_context = unused_contexts;
43                 unused_contexts = unused_contexts->next;
44         }
45         else
46         {
47                 new_context = (context *)safe_malloc(sizeof(context));
48                 new_context->datastack_region = alloc_segment(ds_size);
49                 new_context->retainstack_region = alloc_segment(rs_size);
50         }
51
52         return new_context;
53 }
54
55 void factorvm::dealloc_context(context *old_context)
56 {
57         old_context->next = unused_contexts;
58         unused_contexts = old_context;
59 }
60
61 /* called on entry into a compiled callback */
62 void factorvm::nest_stacks()
63 {
64         context *new_context = alloc_context();
65
66         new_context->callstack_bottom = (stack_frame *)-1;
67         new_context->callstack_top = (stack_frame *)-1;
68
69         /* note that these register values are not necessarily valid stack
70         pointers. they are merely saved non-volatile registers, and are
71         restored in unnest_stacks(). consider this scenario:
72         - factor code calls C function
73         - C function saves ds/cs registers (since they're non-volatile)
74         - C function clobbers them
75         - C function calls Factor callback
76         - Factor callback returns
77         - C function restores registers
78         - C function returns to Factor code */
79         new_context->datastack_save = ds;
80         new_context->retainstack_save = rs;
81
82         /* save per-callback userenv */
83         new_context->current_callback_save = userenv[CURRENT_CALLBACK_ENV];
84         new_context->catchstack_save = userenv[CATCHSTACK_ENV];
85
86         new_context->next = stack_chain;
87         stack_chain = new_context;
88
89         reset_datastack();
90         reset_retainstack();
91 }
92
93 void nest_stacks()
94 {
95         return vm->nest_stacks();
96 }
97
98 /* called when leaving a compiled callback */
99 void factorvm::unnest_stacks()
100 {
101         ds = stack_chain->datastack_save;
102         rs = stack_chain->retainstack_save;
103
104         /* restore per-callback userenv */
105         userenv[CURRENT_CALLBACK_ENV] = stack_chain->current_callback_save;
106         userenv[CATCHSTACK_ENV] = stack_chain->catchstack_save;
107
108         context *old_stacks = stack_chain;
109         stack_chain = old_stacks->next;
110         dealloc_context(old_stacks);
111 }
112
113 void unnest_stacks()
114 {
115         return vm->unnest_stacks();
116 }
117
118 /* called on startup */
119 void factorvm::init_stacks(cell ds_size_, cell rs_size_)
120 {
121         ds_size = ds_size_;
122         rs_size = rs_size_;
123         stack_chain = NULL;
124         unused_contexts = NULL;
125 }
126
127 bool factorvm::stack_to_array(cell bottom, cell top)
128 {
129         fixnum depth = (fixnum)(top - bottom + sizeof(cell));
130
131         if(depth < 0)
132                 return false;
133         else
134         {
135                 array *a = allot_array_internal<array>(depth / sizeof(cell));
136                 memcpy(a + 1,(void*)bottom,depth);
137                 dpush(tag<array>(a));
138                 return true;
139         }
140 }
141
142 inline void factorvm::vmprim_datastack()
143 {
144         if(!stack_to_array(ds_bot,ds))
145                 general_error(ERROR_DS_UNDERFLOW,F,F,NULL);
146 }
147
148 PRIMITIVE(datastack)
149 {
150         PRIMITIVE_GETVM()->vmprim_datastack();
151 }
152
153 inline void factorvm::vmprim_retainstack()
154 {
155         if(!stack_to_array(rs_bot,rs))
156                 general_error(ERROR_RS_UNDERFLOW,F,F,NULL);
157 }
158
159 PRIMITIVE(retainstack)
160 {
161         PRIMITIVE_GETVM()->vmprim_retainstack();
162 }
163
164 /* returns pointer to top of stack */
165 cell factorvm::array_to_stack(array *array, cell bottom)
166 {
167         cell depth = array_capacity(array) * sizeof(cell);
168         memcpy((void*)bottom,array + 1,depth);
169         return bottom + depth - sizeof(cell);
170 }
171
172 inline void factorvm::vmprim_set_datastack()
173 {
174         ds = array_to_stack(untag_check<array>(dpop()),ds_bot);
175 }
176
177 PRIMITIVE(set_datastack)
178 {
179         PRIMITIVE_GETVM()->vmprim_set_datastack();
180 }
181
182 inline void factorvm::vmprim_set_retainstack()
183 {
184         rs = array_to_stack(untag_check<array>(dpop()),rs_bot);
185 }
186
187 PRIMITIVE(set_retainstack)
188 {
189         PRIMITIVE_GETVM()->vmprim_set_retainstack();
190 }
191
192 /* Used to implement call( */
193 inline void factorvm::vmprim_check_datastack()
194 {
195         fixnum out = to_fixnum(dpop());
196         fixnum in = to_fixnum(dpop());
197         fixnum height = out - in;
198         array *saved_datastack = untag_check<array>(dpop());
199         fixnum saved_height = array_capacity(saved_datastack);
200         fixnum current_height = (ds - ds_bot + sizeof(cell)) / sizeof(cell);
201         if(current_height - height != saved_height)
202                 dpush(F);
203         else
204         {
205                 fixnum i;
206                 for(i = 0; i < saved_height - in; i++)
207                 {
208                         if(((cell *)ds_bot)[i] != array_nth(saved_datastack,i))
209                         {
210                                 dpush(F);
211                                 return;
212                         }
213                 }
214                 dpush(T);
215         }
216 }
217
218 PRIMITIVE(check_datastack)
219 {
220         PRIMITIVE_GETVM()->vmprim_check_datastack();
221 }
222
223 }