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