PageRenderTime 46ms CodeModel.GetById 11ms app.highlight 31ms RepoModel.GetById 1ms app.codeStats 0ms

/vm/contexts.cpp

http://github.com/abeaumont/factor
C++ | 365 lines | 301 code | 56 blank | 8 comment | 20 complexity | dcba44a66b7b7ee4a7a19abb1f9a4b72 MD5 | raw file
  1#include "master.hpp"
  2
  3namespace factor
  4{
  5
  6context::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
 19void context::reset_datastack()
 20{
 21	datastack = datastack_seg->start - sizeof(cell);
 22}
 23
 24void context::reset_retainstack()
 25{
 26	retainstack = retainstack_seg->start - sizeof(cell);
 27}
 28
 29void context::reset_callstack()
 30{
 31	callstack_top = callstack_bottom = CALLSTACK_BOTTOM(this);
 32}
 33
 34void context::reset_context_objects()
 35{
 36	memset_cell(context_objects,false_object,context_object_count * sizeof(cell));
 37}
 38
 39void context::reset()
 40{
 41	reset_datastack();
 42	reset_retainstack();
 43	reset_callstack();
 44	reset_context_objects();
 45}
 46
 47void 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
 58void 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
 93context::~context()
 94{
 95	delete datastack_seg;
 96	delete retainstack_seg;
 97	delete callstack_seg;
 98}
 99
100/* called on startup */
101void 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
111void 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
123context *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 */
147void factor_vm::init_context(context *ctx)
148{
149	ctx->context_objects[OBJ_CONTEXT] = allot_alien(ctx);
150}
151
152/* Allocates memory */
153context *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
160void 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
173VM_C_API void delete_context(factor_vm *parent, context *old_context)
174{
175	parent->delete_context(old_context);
176}
177
178/* Allocates memory */
179VM_C_API void reset_context(factor_vm *parent, context *ctx)
180{
181	ctx->reset();
182	parent->init_context(ctx);
183}
184
185/* Allocates memory */
186cell 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
199cell begin_callback(factor_vm *parent, cell quot)
200{
201	return parent->begin_callback(quot);
202}
203
204void factor_vm::end_callback()
205{
206	callback_ids.pop_back();
207	delete_context(ctx);
208}
209
210void end_callback(factor_vm *parent)
211{
212	parent->end_callback();
213}
214
215void factor_vm::primitive_current_callback()
216{
217	ctx->push(tag_fixnum(callback_ids.back()));
218}
219
220void factor_vm::primitive_context_object()
221{
222	fixnum n = untag_fixnum(ctx->peek());
223	ctx->replace(ctx->context_objects[n]);
224}
225
226void 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
233void 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 */
241cell 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
255cell 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
267void factor_vm::primitive_datastack()
268{
269	ctx->push(datastack_to_array(ctx));
270}
271
272void 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
278cell 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
290void factor_vm::primitive_retainstack()
291{
292	ctx->push(retainstack_to_array(ctx));
293}
294
295void 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 */
302cell 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
309void factor_vm::set_datastack(context *ctx, array *array)
310{
311	ctx->datastack = array_to_stack(array,ctx->datastack_seg->start);
312}
313
314void factor_vm::primitive_set_datastack()
315{
316	set_datastack(ctx,untag_check<array>(ctx->pop()));
317}
318
319void factor_vm::set_retainstack(context *ctx, array *array)
320{
321	ctx->retainstack = array_to_stack(array,ctx->retainstack_seg->start);
322}
323
324void factor_vm::primitive_set_retainstack()
325{
326	set_retainstack(ctx,untag_check<array>(ctx->pop()));
327}
328
329/* Used to implement call( */
330void 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
355void 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}