/vm/contexts.cpp

http://github.com/abeaumont/factor · C++ · 365 lines · 301 code · 56 blank · 8 comment · 22 complexity · dcba44a66b7b7ee4a7a19abb1f9a4b72 MD5 · raw file

  1. #include "master.hpp"
  2. namespace factor
  3. {
  4. context::context(cell datastack_size, cell retainstack_size, cell callstack_size) :
  5. callstack_top(NULL),
  6. callstack_bottom(NULL),
  7. datastack(0),
  8. retainstack(0),
  9. callstack_save(0),
  10. datastack_seg(new segment(datastack_size,false)),
  11. retainstack_seg(new segment(retainstack_size,false)),
  12. callstack_seg(new segment(callstack_size,false))
  13. {
  14. reset();
  15. }
  16. void context::reset_datastack()
  17. {
  18. datastack = datastack_seg->start - sizeof(cell);
  19. }
  20. void context::reset_retainstack()
  21. {
  22. retainstack = retainstack_seg->start - sizeof(cell);
  23. }
  24. void context::reset_callstack()
  25. {
  26. callstack_top = callstack_bottom = CALLSTACK_BOTTOM(this);
  27. }
  28. void context::reset_context_objects()
  29. {
  30. memset_cell(context_objects,false_object,context_object_count * sizeof(cell));
  31. }
  32. void context::reset()
  33. {
  34. reset_datastack();
  35. reset_retainstack();
  36. reset_callstack();
  37. reset_context_objects();
  38. }
  39. void context::fix_stacks()
  40. {
  41. if(datastack + sizeof(cell) < datastack_seg->start
  42. || datastack + stack_reserved >= datastack_seg->end)
  43. reset_datastack();
  44. if(retainstack + sizeof(cell) < retainstack_seg->start
  45. || retainstack + stack_reserved >= retainstack_seg->end)
  46. reset_retainstack();
  47. }
  48. void context::scrub_stacks(gc_info *info, cell index)
  49. {
  50. u8 *bitmap = info->gc_info_bitmap();
  51. {
  52. cell base = info->callsite_scrub_d(index);
  53. for(cell loc = 0; loc < info->scrub_d_count; loc++)
  54. {
  55. if(bitmap_p(bitmap,base + loc))
  56. {
  57. #ifdef DEBUG_GC_MAPS
  58. std::cout << "scrubbing datastack location " << loc << std::endl;
  59. #endif
  60. *((cell *)datastack - loc) = 0;
  61. }
  62. }
  63. }
  64. {
  65. cell base = info->callsite_scrub_r(index);
  66. for(cell loc = 0; loc < info->scrub_r_count; loc++)
  67. {
  68. if(bitmap_p(bitmap,base + loc))
  69. {
  70. #ifdef DEBUG_GC_MAPS
  71. std::cout << "scrubbing retainstack location " << loc << std::endl;
  72. #endif
  73. *((cell *)retainstack - loc) = 0;
  74. }
  75. }
  76. }
  77. }
  78. context::~context()
  79. {
  80. delete datastack_seg;
  81. delete retainstack_seg;
  82. delete callstack_seg;
  83. }
  84. /* called on startup */
  85. void factor_vm::init_contexts(cell datastack_size_, cell retainstack_size_, cell callstack_size_)
  86. {
  87. datastack_size = datastack_size_;
  88. retainstack_size = retainstack_size_;
  89. callstack_size = callstack_size_;
  90. ctx = NULL;
  91. spare_ctx = new_context();
  92. }
  93. void factor_vm::delete_contexts()
  94. {
  95. FACTOR_ASSERT(!ctx);
  96. std::list<context *>::const_iterator iter = unused_contexts.begin();
  97. std::list<context *>::const_iterator end = unused_contexts.end();
  98. while(iter != end)
  99. {
  100. delete *iter;
  101. iter++;
  102. }
  103. }
  104. context *factor_vm::new_context()
  105. {
  106. context *new_context;
  107. if(unused_contexts.empty())
  108. {
  109. new_context = new context(datastack_size,
  110. retainstack_size,
  111. callstack_size);
  112. }
  113. else
  114. {
  115. new_context = unused_contexts.back();
  116. unused_contexts.pop_back();
  117. }
  118. new_context->reset();
  119. active_contexts.insert(new_context);
  120. return new_context;
  121. }
  122. /* Allocates memory */
  123. void factor_vm::init_context(context *ctx)
  124. {
  125. ctx->context_objects[OBJ_CONTEXT] = allot_alien(ctx);
  126. }
  127. /* Allocates memory */
  128. context *new_context(factor_vm *parent)
  129. {
  130. context *new_context = parent->new_context();
  131. parent->init_context(new_context);
  132. return new_context;
  133. }
  134. void factor_vm::delete_context(context *old_context)
  135. {
  136. unused_contexts.push_back(old_context);
  137. active_contexts.erase(old_context);
  138. while(unused_contexts.size() > 10)
  139. {
  140. context *stale_context = unused_contexts.front();
  141. unused_contexts.pop_front();
  142. delete stale_context;
  143. }
  144. }
  145. VM_C_API void delete_context(factor_vm *parent, context *old_context)
  146. {
  147. parent->delete_context(old_context);
  148. }
  149. /* Allocates memory */
  150. VM_C_API void reset_context(factor_vm *parent, context *ctx)
  151. {
  152. ctx->reset();
  153. parent->init_context(ctx);
  154. }
  155. /* Allocates memory */
  156. cell factor_vm::begin_callback(cell quot_)
  157. {
  158. data_root<object> quot(quot_,this);
  159. ctx->reset();
  160. spare_ctx = new_context();
  161. callback_ids.push_back(callback_id++);
  162. init_context(ctx);
  163. return quot.value();
  164. }
  165. cell begin_callback(factor_vm *parent, cell quot)
  166. {
  167. return parent->begin_callback(quot);
  168. }
  169. void factor_vm::end_callback()
  170. {
  171. callback_ids.pop_back();
  172. delete_context(ctx);
  173. }
  174. void end_callback(factor_vm *parent)
  175. {
  176. parent->end_callback();
  177. }
  178. void factor_vm::primitive_current_callback()
  179. {
  180. ctx->push(tag_fixnum(callback_ids.back()));
  181. }
  182. void factor_vm::primitive_context_object()
  183. {
  184. fixnum n = untag_fixnum(ctx->peek());
  185. ctx->replace(ctx->context_objects[n]);
  186. }
  187. void factor_vm::primitive_set_context_object()
  188. {
  189. fixnum n = untag_fixnum(ctx->pop());
  190. cell value = ctx->pop();
  191. ctx->context_objects[n] = value;
  192. }
  193. void factor_vm::primitive_context_object_for()
  194. {
  195. context *other_ctx = (context *)pinned_alien_offset(ctx->pop());
  196. fixnum n = untag_fixnum(ctx->pop());
  197. ctx->push(other_ctx->context_objects[n]);
  198. }
  199. /* Allocates memory */
  200. cell factor_vm::stack_to_array(cell bottom, cell top)
  201. {
  202. fixnum depth = (fixnum)(top - bottom + sizeof(cell));
  203. if(depth < 0)
  204. return false_object;
  205. else
  206. {
  207. array *a = allot_uninitialized_array<array>(depth / sizeof(cell));
  208. memcpy(a + 1,(void*)bottom,depth);
  209. return tag<array>(a);
  210. }
  211. }
  212. cell factor_vm::datastack_to_array(context *ctx)
  213. {
  214. cell array = stack_to_array(ctx->datastack_seg->start,ctx->datastack);
  215. if(array == false_object)
  216. {
  217. general_error(ERROR_DATASTACK_UNDERFLOW,false_object,false_object);
  218. return false_object;
  219. }
  220. else
  221. return array;
  222. }
  223. void factor_vm::primitive_datastack()
  224. {
  225. ctx->push(datastack_to_array(ctx));
  226. }
  227. void factor_vm::primitive_datastack_for()
  228. {
  229. context *other_ctx = (context *)pinned_alien_offset(ctx->pop());
  230. ctx->push(datastack_to_array(other_ctx));
  231. }
  232. cell factor_vm::retainstack_to_array(context *ctx)
  233. {
  234. cell array = stack_to_array(ctx->retainstack_seg->start,ctx->retainstack);
  235. if(array == false_object)
  236. {
  237. general_error(ERROR_RETAINSTACK_UNDERFLOW,false_object,false_object);
  238. return false_object;
  239. }
  240. else
  241. return array;
  242. }
  243. void factor_vm::primitive_retainstack()
  244. {
  245. ctx->push(retainstack_to_array(ctx));
  246. }
  247. void factor_vm::primitive_retainstack_for()
  248. {
  249. context *other_ctx = (context *)pinned_alien_offset(ctx->pop());
  250. ctx->push(retainstack_to_array(other_ctx));
  251. }
  252. /* returns pointer to top of stack */
  253. cell factor_vm::array_to_stack(array *array, cell bottom)
  254. {
  255. cell depth = array_capacity(array) * sizeof(cell);
  256. memcpy((void*)bottom,array + 1,depth);
  257. return bottom + depth - sizeof(cell);
  258. }
  259. void factor_vm::set_datastack(context *ctx, array *array)
  260. {
  261. ctx->datastack = array_to_stack(array,ctx->datastack_seg->start);
  262. }
  263. void factor_vm::primitive_set_datastack()
  264. {
  265. set_datastack(ctx,untag_check<array>(ctx->pop()));
  266. }
  267. void factor_vm::set_retainstack(context *ctx, array *array)
  268. {
  269. ctx->retainstack = array_to_stack(array,ctx->retainstack_seg->start);
  270. }
  271. void factor_vm::primitive_set_retainstack()
  272. {
  273. set_retainstack(ctx,untag_check<array>(ctx->pop()));
  274. }
  275. /* Used to implement call( */
  276. void factor_vm::primitive_check_datastack()
  277. {
  278. fixnum out = to_fixnum(ctx->pop());
  279. fixnum in = to_fixnum(ctx->pop());
  280. fixnum height = out - in;
  281. array *saved_datastack = untag_check<array>(ctx->pop());
  282. fixnum saved_height = array_capacity(saved_datastack);
  283. fixnum current_height = (ctx->datastack - ctx->datastack_seg->start + sizeof(cell)) / sizeof(cell);
  284. if(current_height - height != saved_height)
  285. ctx->push(false_object);
  286. else
  287. {
  288. cell *ds_bot = (cell *)ctx->datastack_seg->start;
  289. for(fixnum i = 0; i < saved_height - in; i++)
  290. {
  291. if(ds_bot[i] != array_nth(saved_datastack,i))
  292. {
  293. ctx->push(false_object);
  294. return;
  295. }
  296. }
  297. ctx->push(true_object);
  298. }
  299. }
  300. void factor_vm::primitive_load_locals()
  301. {
  302. fixnum count = untag_fixnum(ctx->pop());
  303. memcpy((cell *)(ctx->retainstack + sizeof(cell)),
  304. (cell *)(ctx->datastack - sizeof(cell) * (count - 1)),
  305. sizeof(cell) * count);
  306. ctx->datastack -= sizeof(cell) * count;
  307. ctx->retainstack += sizeof(cell) * count;
  308. }
  309. }