memory.cpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463
  1. /* Definitions for the memory interface.
  2. This file is part of khipu.
  3. khipu is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Lesser General Public License as published by
  5. the Free Software Foundation; either version 3 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <https://www.gnu.org/licenses/>. */
  13. #include <cstdio>
  14. #include <cstdlib>
  15. #include <csignal>
  16. #include <climits>
  17. #include "khipu.hpp"
  18. #ifdef KP_PLATFORM_UNIX
  19. #include <sys/mman.h>
  20. #include <unistd.h>
  21. #elif defined (KP_PLATFORM_WINDOWS)
  22. #include <windows.h>
  23. #endif
  24. KP_DECLS_BEGIN
  25. [[noreturn]] void raise_oom (interpreter *interp)
  26. {
  27. if (!interp && !(interp = interpreter::self ()))
  28. {
  29. fputs ("memory exhausted\n", stderr);
  30. exit (1);
  31. }
  32. (void)interp->raise ("memory-error", "failed to allocate memory");
  33. exit (1);
  34. }
  35. void* xmalloc (size_t size)
  36. {
  37. void *ret = malloc (size);
  38. if (!ret || (((uintptr_t)ret) & 7) != 0)
  39. raise_oom ();
  40. return (ret);
  41. }
  42. void* xrealloc (void *ptr, size_t size)
  43. {
  44. void *ret = realloc (ptr, size);
  45. if ((!ret && size) || (ret && (((uintptr_t)ret) & 7) != 0))
  46. raise_oom ();
  47. return (ret);
  48. }
  49. void xfree (void *ptr)
  50. {
  51. free (ptr);
  52. }
  53. #ifdef KP_ARCH_WIDE
  54. void* ensure_mask_impl (void *ptr, int mask)
  55. {
  56. if ((uintptr_t)ptr & ~((UINT64_C (1) << mask) - 1))
  57. raise_oom ();
  58. return (ptr);
  59. }
  60. #endif
  61. void* alloch (size_t size, int type, int mask)
  62. {
  63. varobj *ret = (varobj *)ensure_mask_impl (xmalloc (size), mask);
  64. ret->vo_full = 0;
  65. ret->vo_type = type;
  66. return (ret);
  67. }
  68. // GC implementation.
  69. static const int BM_BITS = sizeof (uintptr_t) * 8;
  70. struct conspage
  71. {
  72. conspage *next;
  73. cons* at (unsigned int idx) const
  74. {
  75. cons *retp = (cons *)((char *)this + sizeof (int64_t));
  76. return (retp + idx);
  77. }
  78. inline uintptr_t* bitmap () const;
  79. // Given a pointer to a cons, return the page it belongs to.
  80. static conspage* from_cons (const cons *ptr);
  81. };
  82. #ifdef KP_PLATFORM_UNIX
  83. static inline void*
  84. alloc_npages (unsigned int n, unsigned int ps)
  85. {
  86. void *ret = mmap (nullptr, ps * n, PROT_READ |
  87. PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  88. if (ret == MAP_FAILED)
  89. raise_oom ();
  90. return (ensure_mask_impl (ret));
  91. }
  92. #elif defined (KP_PLATFORM_WINDOWS)
  93. static inline void*
  94. alloc_npages (unsigned int n, unsigned int ps)
  95. {
  96. void *ret = VirtualAlloc (nullptr, ps * n,
  97. MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
  98. if (!ret)
  99. raise_oom ();
  100. return (ensure_mask_impl (ret));
  101. }
  102. #endif
  103. static void
  104. fini_varobj (varobj *ptr)
  105. {
  106. if (ptr->flagged_p (FLAGS_FINALIZABLE))
  107. {
  108. finobj *fp = (finobj *)ptr;
  109. if (fp->fini)
  110. {
  111. fp->fini (fp);
  112. fp->fini = nullptr;
  113. }
  114. }
  115. xfree (ptr);
  116. }
  117. struct cons_cache
  118. {
  119. conspage *cache;
  120. int ncached;
  121. };
  122. template <typename Iter>
  123. static object
  124. link_conses (cons *ptr, uint32_t n, Iter& iter)
  125. {
  126. // Link adjacent conses.
  127. for (uint32_t i = 0; i < n - 1; ++i)
  128. {
  129. ptr[i].car = *iter++;
  130. ptr[i].cdr = ptr[i + 1].as_obj ();
  131. }
  132. ptr[n - 1].car = *iter++;
  133. ptr[n - 1].cdr = NIL;
  134. return (ptr->as_obj ());
  135. }
  136. struct varobj_set
  137. {
  138. dlist sets[2];
  139. void reset ()
  140. {
  141. this->sets[0].init_head ();
  142. this->sets[1].init_head ();
  143. }
  144. bool empty () const
  145. {
  146. return (this->sets[0].next == &this->sets[0] &&
  147. this->sets[1].next == &this->sets[1]);
  148. }
  149. void add_set (dlist *inp, int idx)
  150. {
  151. if (inp->next == inp)
  152. return;
  153. dlist *outp = &this->sets[idx];
  154. dlist *l1 = outp->prev, *f2 = inp->next, *l2 = inp->prev;
  155. l1->next = f2;
  156. f2->prev = l1;
  157. l2->next = l1;
  158. l1->prev = l2;
  159. }
  160. void add_obj (varobj *vp)
  161. {
  162. uintptr_t idx = (vp->vo_full & FLAGS_ATEXIT) / FLAGS_ATEXIT;
  163. this->sets[idx].add (&vp->gc_link);
  164. }
  165. void concat (varobj_set *sp)
  166. {
  167. this->add_set (&sp->sets[0], 0);
  168. this->add_set (&sp->sets[1], 1);
  169. sp->reset ();
  170. }
  171. };
  172. static const int FINOBJ_IDX = 1;
  173. // GC-specific information.
  174. struct gcinfo
  175. {
  176. int pagesize;
  177. int pagecache_size;
  178. atomic_t xlock;
  179. size_t acc_bytes;
  180. size_t limit;
  181. sync_event event;
  182. bool full_gc;
  183. bool enabled;
  184. cons_cache ccache;
  185. uint32_t conses_per_page;
  186. varobj_set black;
  187. varobj_set gray;
  188. varobj_set white;
  189. memmgr *free_mgrs;
  190. size_t vo_size_limit;
  191. size_t vo_nelem_limit;
  192. uintptr_t gcbit;
  193. uintptr_t n_suspended;
  194. static const uintptr_t GC_MASK = FLAGS_GCBIT1 | FLAGS_GCBIT2 | FLAGS_GCDIRTY;
  195. static const uint32_t MAX_MARK_DEPTH = 64;
  196. bool init ()
  197. {
  198. #ifdef KP_PLATFORM_WINDOWS
  199. SYSTEM_INFO info;
  200. GetSystemInfo (&info);
  201. this->pagesize = info.dwPageSize;
  202. #elif defined (KP_PLATFORM_UNIX)
  203. this->pagesize = sysconf (_SC_PAGESIZE);
  204. #endif
  205. /* Within a cons page, we need enough room for:
  206. * - A pointer to the next page.
  207. * - The conses themselves (We'll call this 'C').
  208. * - Enough bytes for a bitmap, to know which conses
  209. * belong to the old generation.
  210. *
  211. * Given that, the parameter C can be determined as such:
  212. * PAGESIZE = 2P * C + C / 8 + P; where P is the wordsize.
  213. *
  214. * Solving the above equation gives us:
  215. * C = ((PAGESIZE - P) * 8) / (16P + 1)
  216. * Which we round down in order to play it safe, and to ensure
  217. * that the space for the bitmap is correctly aligned. */
  218. this->conses_per_page =
  219. ((this->pagesize - sizeof (conspage *)) * 8) /
  220. (16 * sizeof (conspage *) + 1) - 1;
  221. #ifndef KP_ARCH_WIDE
  222. /* On 32-bit platforms, we furthermore need to ensure that conses
  223. * are properly aligned, so we use an additional word for that. */
  224. --this->conses_per_page;
  225. #endif
  226. // XXX: Make these tunable.
  227. this->limit = 10 * 1024 * 1024;
  228. this->pagecache_size = 8 * sizeof (void *);
  229. this->vo_nelem_limit = 1024;
  230. this->vo_size_limit = this->limit / 16;
  231. this->ccache.cache = this->alloc_conspage ();
  232. this->free_mgrs = nullptr;
  233. lwlock_init (&this->xlock);
  234. this->black.reset ();
  235. this->gray.reset ();
  236. this->white.reset ();
  237. this->gcbit = FLAGS_GCBIT1;
  238. this->event.init ();
  239. return (true);
  240. }
  241. void lock (interpreter *interp)
  242. {
  243. #ifndef KP_NO_THREADS
  244. lwlock_grab_nointr (interp, &this->xlock);
  245. #endif
  246. }
  247. void unlock ()
  248. {
  249. #ifndef KP_NO_THREADS
  250. lwlock_drop (&this->xlock);
  251. #endif
  252. }
  253. void* alloc_pages (unsigned int n)
  254. {
  255. return (alloc_npages (n, this->pagesize));
  256. }
  257. conspage* alloc_conspage ()
  258. {
  259. if (this->ccache.ncached == 0)
  260. this->ccache.cache = (conspage *)
  261. this->alloc_pages (this->ccache.ncached = this->pagecache_size);
  262. conspage *ret = this->ccache.cache;
  263. this->ccache.cache = (conspage *)
  264. ((char *)this->ccache.cache + this->pagesize);
  265. --this->ccache.ncached;
  266. return (ret);
  267. }
  268. void do_gc (interpreter *interp);
  269. void mark_pkg (package *pkgp, uint32_t depth);
  270. void mark_cons (object obj, uint32_t depth);
  271. void mark (object obj, uint32_t depth = 0);
  272. void update_alloc (interpreter *interp, size_t size)
  273. {
  274. if ((this->acc_bytes += size) >= this->limit)
  275. this->do_gc (interp);
  276. }
  277. void sweep_varobjs (int idx, gcinfo& out)
  278. {
  279. for (auto it = this->white.sets[idx].iterator (&varobj::gc_link);
  280. it.valid (); )
  281. {
  282. auto curr = it++;
  283. varobj *vp = &*curr;
  284. curr.link()->del ();
  285. if (kp_unlikely (vp->flagged_p (out.gcbit)))
  286. { /* This object survived even though it's not in the black set,
  287. * most likely because of a write barrier. */
  288. vp->vo_full = (vp->vo_full & ~GC_MASK) | out.gcbit;
  289. out.black.add_obj (vp);
  290. }
  291. else
  292. {
  293. out.acc_bytes -= vp->vo_size;
  294. fini_varobj (vp);
  295. }
  296. }
  297. }
  298. void sweep_varobjs (gcinfo& out)
  299. {
  300. this->sweep_varobjs (0, out);
  301. this->sweep_varobjs (1, out);
  302. }
  303. bool set_black (varobj *vp)
  304. {
  305. if (vp->flagged_p (this->gcbit))
  306. return (false);
  307. vp->vo_full = (vp->vo_full & ~GC_MASK) | this->gcbit;
  308. if (vp->gc_link.linked_p ())
  309. {
  310. vp->gc_link.del ();
  311. this->black.add_obj (vp);
  312. }
  313. return (true);
  314. }
  315. void mark_gray (int idx)
  316. {
  317. for (auto it = this->gray.sets[idx].iterator (&varobj::gc_link);
  318. it.valid (); )
  319. {
  320. auto curr = it++;
  321. varobj *vp = &*curr;
  322. vp->vo_full &= ~FLAGS_GCWIP;
  323. this->mark (vp->as_obj ());
  324. }
  325. }
  326. void mark_gray ()
  327. {
  328. this->mark_gray (0);
  329. this->mark_gray (1);
  330. }
  331. void suspend_one (interpreter *interp, interpreter *target);
  332. void suspend_all (interpreter *interp);
  333. void resume_all (interpreter *interp);
  334. result<void> exit (interpreter *interp, object val);
  335. };
  336. struct gc_cards
  337. {
  338. object *table;
  339. object st_tab[16];
  340. uint32_t nelem;
  341. uint32_t nsize;
  342. void init ()
  343. {
  344. this->table = this->st_tab;
  345. this->nelem = 0;
  346. this->nsize = (uint32_t)KP_NELEM (this->st_tab);
  347. for (uint32_t i = 0; i < this->nsize; ++i)
  348. this->table[i] = UNBOUND;
  349. }
  350. result<void> resize (interpreter *interp)
  351. {
  352. uint32_t nsz = this->nsize * 2;
  353. object ax = KP_TRY (alloc_array (interp, nsz));
  354. array *np = as_array (ax);
  355. for (uint32_t i = 0, j = 0; j < this->nelem; ++i)
  356. {
  357. object obj = this->table[i];
  358. if (obj == UNBOUND)
  359. continue;
  360. uint32_t idx = (uint32_t)((obj >> 3) & (nsz - 1));
  361. while (true)
  362. {
  363. if (np->data[idx] != UNBOUND)
  364. {
  365. np->data[idx] = obj;
  366. break;
  367. }
  368. idx = (idx + 1) & (nsz - 1);
  369. }
  370. ++j;
  371. }
  372. this->table = np->data;
  373. this->nsize = nsz;
  374. return (0);
  375. }
  376. result<void> add_obj (interpreter *interp, object obj)
  377. {
  378. uint32_t idx = (uint32_t)((obj >> 3) & (this->nsize - 1));
  379. while (true)
  380. {
  381. if (this->table[idx] == obj)
  382. return (0);
  383. else if (this->table[idx] == UNBOUND)
  384. {
  385. this->table[idx] = obj;
  386. if (++this->nelem * 100 > this->nsize * 80)
  387. KP_VTRY (this->resize (interp));
  388. return (0);
  389. }
  390. idx = (idx + 1) & (this->nsize - 1);
  391. }
  392. }
  393. };
  394. struct cycle_alloc_iter
  395. {
  396. object value;
  397. cycle_alloc_iter (object v) : value (v)
  398. {
  399. }
  400. cycle_alloc_iter& operator++ (int)
  401. {
  402. return (*this);
  403. }
  404. object operator* ()
  405. {
  406. return (this->value);
  407. }
  408. };
  409. struct memmgr
  410. {
  411. conspage *pages;
  412. object free_list;
  413. uint32_t nfree;
  414. uint32_t top_used;
  415. varobj_set vobjs;
  416. size_t vo_size;
  417. uint32_t vo_nelem;
  418. gc_cards cards;
  419. memmgr *next;
  420. void init ()
  421. {
  422. this->pages = nullptr;
  423. this->free_list = NIL;
  424. this->nfree = this->vo_nelem = 0;
  425. this->top_used = 0xffff;
  426. this->vo_size = 0;
  427. this->vobjs.reset ();
  428. this->cards.init ();
  429. }
  430. conspage* fetch_conspage (gcinfo& gc)
  431. {
  432. conspage *ret = gc.alloc_conspage ();
  433. ret->next = this->pages;
  434. this->pages = ret;
  435. return (ret);
  436. }
  437. result<conspage*> alloc_conspage (interpreter *interp, gcinfo& gc)
  438. {
  439. conspage *ret;
  440. {
  441. KP_MT_BEGIN (lwlock_grab_nointr (interp, &gc.xlock));
  442. ret = gc.alloc_conspage ();
  443. gc.update_alloc (interp, gc.pagesize);
  444. KP_MT_END (lwlock_drop (&gc.xlock));
  445. }
  446. ret->next = this->pages;
  447. this->pages = ret;
  448. this->top_used = 0;
  449. return (ret);
  450. }
  451. void push_cons (cons *ptr, gcinfo& gc)
  452. {
  453. ptr->car = UNBOUND;
  454. ptr->cdr = this->free_list;
  455. this->free_list = ptr->as_obj ();
  456. ++this->nfree;
  457. gc.acc_bytes -= sizeof (*ptr);
  458. }
  459. cons* pop_cons ()
  460. {
  461. cons *retp = as_cons (this->free_list);
  462. this->free_list = retp->cdr;
  463. return (retp);
  464. }
  465. result<object> alloc_cons1 (interpreter *interp, gcinfo& gc)
  466. {
  467. cons *ret;
  468. if (this->nfree != 0)
  469. { // Use the free list.
  470. ret = this->pop_cons ();
  471. --this->nfree;
  472. }
  473. else
  474. {
  475. if (this->top_used >= gc.conses_per_page)
  476. { // Top page is empty - Allocate a new one.
  477. KP_VTRY (this->alloc_conspage (interp, gc));
  478. }
  479. ret = this->pages->at (this->top_used);
  480. ++this->top_used;
  481. }
  482. interp->alval = ret->as_obj ();
  483. ret->car = ret->cdr = NIL;
  484. return (interp->alval);
  485. }
  486. template <typename Iter>
  487. object alloc_ncons (interpreter *interp, gcinfo& gc, uint32_t n,
  488. Iter it, object **tail)
  489. {
  490. object *outp = &interp->alval;
  491. uint32_t i;
  492. *outp = NIL;
  493. // Consume the free list before using the pages.
  494. for (i = 0; i < min (this->nfree, n); ++i)
  495. {
  496. cons *tmp = this->pop_cons ();
  497. tmp->car = *it++;
  498. *outp = tmp->as_obj (), outp = &tmp->cdr;
  499. }
  500. this->nfree -= i;
  501. if ((n -= i) == 0)
  502. {
  503. *(*tail = outp) = NIL;
  504. return (interp->alval);
  505. }
  506. cons *ptr = this->pages->at (this->top_used);
  507. auto opp = gc.conses_per_page;
  508. int avail = (int)opp - (int)this->top_used;
  509. if (avail >= (int)n)
  510. { // Top page has enough conses to satisfy the request.
  511. *outp = link_conses (ptr, n, it);
  512. this->top_used += n;
  513. }
  514. else
  515. {
  516. uint32_t n_pages = 1;
  517. if (avail > 0)
  518. { // Consume the top page before allocating more.
  519. *outp = link_conses (ptr, avail, it);
  520. outp = &ptr[avail - 1].cdr;
  521. n -= avail;
  522. }
  523. KP_MT_BEGIN (lwlock_grab_nointr (interp, &gc.xlock));
  524. for (; n > opp; n -= opp, ++n_pages)
  525. {
  526. ptr = this->fetch_conspage(gc)->at (0);
  527. *outp = link_conses (ptr, opp, it);
  528. outp = &ptr[opp - 1].cdr;
  529. }
  530. ptr = this->fetch_conspage(gc)->at (0);
  531. this->top_used = n;
  532. *outp = link_conses (ptr, n, it);
  533. gc.update_alloc (interp, n_pages * gc.pagesize);
  534. KP_MT_END (lwlock_drop (&gc.xlock));
  535. }
  536. *tail = &ptr[n - 1].cdr;
  537. return (interp->alval);
  538. }
  539. void reset_varobjs (gcinfo& gc)
  540. {
  541. gc.white.concat (&this->vobjs);
  542. gc.acc_bytes += this->vo_size;
  543. this->vo_size = this->vo_nelem = 0;
  544. }
  545. void flush_varobjs (interpreter *interp, gcinfo& gc)
  546. {
  547. auto saved = this->vo_size;
  548. KP_MT_BEGIN (gc.lock (interp));
  549. gc.white.concat (&this->vobjs);
  550. this->vo_size = 0;
  551. gc.update_alloc (interp, saved);
  552. KP_MT_END (gc.unlock ());
  553. this->vo_nelem = 0;
  554. }
  555. void add_varobj (interpreter *interp, gcinfo& gc,
  556. varobj *ptr, size_t bytes)
  557. {
  558. this->vobjs.add_obj (ptr);
  559. ptr->vo_size = (uint32_t)bytes;
  560. this->vo_size += bytes;
  561. ++this->vo_nelem;
  562. if (this->vo_size > gc.vo_size_limit ||
  563. this->vo_nelem > gc.vo_nelem_limit)
  564. this->flush_varobjs (interp, gc);
  565. }
  566. void clear_bitmaps (uint32_t opp)
  567. {
  568. for (conspage *p = this->pages; p != nullptr; p = p->next)
  569. memset (p->bitmap (), 0, (opp + 7) / 8);
  570. }
  571. void sweep_cons_page (gcinfo& gc, conspage *page, uint32_t n)
  572. {
  573. uintptr_t *bp = page->bitmap ();
  574. for (uint32_t i = 0; i < n; ++i)
  575. {
  576. cons *ptr = page->at (i);
  577. if (ptr->car != UNBOUND &&
  578. (bp[i / BM_BITS] & ((uintptr_t)1 << (i % BM_BITS))) == 0)
  579. this->push_cons (ptr, gc);
  580. }
  581. }
  582. void sweep (gcinfo& gc)
  583. {
  584. if (!this->pages)
  585. return;
  586. auto opp = gc.conses_per_page;
  587. for (conspage *p = this->pages->next; p != nullptr; p = p->next)
  588. this->sweep_cons_page (gc, p, opp);
  589. this->sweep_cons_page (gc, this->pages, this->top_used);
  590. }
  591. void mark_cards (gcinfo& gc)
  592. {
  593. // Mark the GC cards, but not the containing vector itself.
  594. for (uint32_t i = 0; i < this->cards.nsize; ++i)
  595. gc.mark (this->cards.table[i]);
  596. // Done with the vector.
  597. this->cards.init ();
  598. }
  599. };
  600. static gcinfo KP_gc;
  601. memmgr* memmgr_alloc ()
  602. {
  603. while (true)
  604. {
  605. memmgr *mp = KP_gc.free_mgrs;
  606. if (!mp)
  607. break;
  608. else if (atomic_cas_bool ((atomic_t *)&KP_gc.free_mgrs,
  609. (atomic_t)mp, (atomic_t)mp->next))
  610. return (mp);
  611. atomic_spin_nop ();
  612. }
  613. memmgr *ret = (memmgr *)xmalloc (sizeof (*ret));
  614. ret->init ();
  615. return (ret);
  616. }
  617. void memmgr_free (memmgr *mp)
  618. {
  619. while (true)
  620. {
  621. memmgr *tp = KP_gc.free_mgrs;
  622. mp->next = tp;
  623. if (atomic_cas_bool ((atomic_t *)&KP_gc.free_mgrs,
  624. (atomic_t)tp, (atomic_t)mp))
  625. return;
  626. atomic_spin_nop ();
  627. }
  628. }
  629. uintptr_t* conspage::bitmap () const
  630. {
  631. return ((uintptr_t *)this->at (KP_gc.conses_per_page));
  632. }
  633. conspage* conspage::from_cons (const cons *ptr)
  634. {
  635. return ((conspage *)((uintptr_t)ptr & ~(KP_gc.pagesize - 1)));
  636. }
  637. void gc_lock (interpreter *interp)
  638. {
  639. KP_gc.lock (interp);
  640. }
  641. void gc_unlock ()
  642. {
  643. KP_gc.unlock ();
  644. }
  645. void gc_register (interpreter *interp, varobj *ptr, size_t bytes)
  646. {
  647. interp->mmgr->add_varobj (interp, KP_gc, ptr, bytes);
  648. }
  649. result<object> alloc_cons (interpreter *interp)
  650. {
  651. auto eg = KP_TRY (evh_guard::make (interp));
  652. return (interp->mmgr->alloc_cons1 (interp, KP_gc));
  653. }
  654. result<object> alloc_cons (interpreter *interp, uint32_t n,
  655. object fill, object **tail)
  656. {
  657. cycle_alloc_iter cit (fill);
  658. object *dummy;
  659. if (!tail)
  660. tail = &dummy;
  661. auto eg = KP_TRY (evh_guard::make (interp));
  662. return (interp->mmgr->alloc_ncons (interp, KP_gc, n, cit, tail));
  663. }
  664. result<object> alloc_cons (interpreter *interp, uint32_t n,
  665. object *argv, object **tail)
  666. {
  667. object *dummy;
  668. if (!tail)
  669. tail = &dummy;
  670. auto eg = KP_TRY (evh_guard::make (interp));
  671. return (interp->mmgr->alloc_ncons (interp, KP_gc, n, argv, tail));
  672. }
  673. result<object> gcreq_handler (interpreter *interp, object *, int)
  674. {
  675. // Flush memory state and ackowledge request.
  676. evh_safeguard eg { interp };
  677. atomic_mfence ();
  678. interp->sync_ev()->wait (interp);
  679. kp_return (fixint (0));
  680. }
  681. void gcinfo::suspend_one (interpreter *interp, interpreter *target)
  682. {
  683. if (target == interp)
  684. return;
  685. /* Save the state and notify the thread of the suspension request,
  686. * if it's running. Otherwise, the thread will have to wait on the
  687. * GC event once it's done blocking. */
  688. target->lock_remote (interp);
  689. target->saved_state = target->state;
  690. target->state = INTERP_SUSPENDED;
  691. target->sync_ev() = &this->event;
  692. if (target->saved_state == INTERP_RUNNING)
  693. {
  694. target->set_ev (GCREQ_EV);
  695. ++this->n_suspended;
  696. }
  697. target->unlock ();
  698. }
  699. static inline dlist::iter_type<thread> threads_iter ()
  700. {
  701. return (all_threads.iterator (&thread::thr_link));
  702. }
  703. void gcinfo::resume_all (interpreter *interp)
  704. {
  705. for (auto it = threads_iter (); it.valid (); ++it)
  706. {
  707. interpreter *target = it->interp;
  708. if (target == interp)
  709. continue;
  710. // Restore interpreter state.
  711. target->lock_remote (interp);
  712. target->state = target->saved_state;
  713. target->unlock ();
  714. }
  715. lwlock_drop (&all_threads_lock);
  716. // Wake all threads.
  717. this->event.wake_all (interp);
  718. }
  719. // Marking routines.
  720. struct depth_guard
  721. {
  722. uint32_t *ptr;
  723. depth_guard (uint32_t *p) : ptr (p)
  724. {
  725. ++*this->ptr;
  726. }
  727. ~depth_guard ()
  728. {
  729. --*this->ptr;
  730. }
  731. };
  732. static inline bool
  733. ub_tail_p (object obj)
  734. {
  735. for (; cons_p (obj); obj = xcdr (obj)) ;
  736. return (obj == UNBOUND);
  737. }
  738. static inline bool
  739. left_tail_p (object obj, uint32_t cnt)
  740. {
  741. if (cnt-- == 0)
  742. return (false);
  743. for (; cnt != 0; --cnt)
  744. {
  745. obj = xcar (obj);
  746. if (!cons_p (obj) || !cons_p (obj = xcdr (obj)))
  747. return (false);
  748. }
  749. return (xcons_p (obj) && ub_tail_p (xcar (obj)));
  750. }
  751. void gcinfo::mark_cons (object obj, uint32_t depth)
  752. {
  753. if (!as_cons(obj)->gc_mark ())
  754. return;
  755. object curr = obj, pred = UNBOUND;
  756. bool fwd = true;
  757. uint32_t cnt = 0;
  758. while (true)
  759. {
  760. if (fwd)
  761. { // Move on to the CDR.
  762. object tmp = xcdr (curr);
  763. if (cons_p (tmp) && as_cons(tmp)->gc_mark ())
  764. {
  765. xcdr(curr) = pred;
  766. pred = curr, curr = tmp;
  767. }
  768. else
  769. { // Reached the end - Move left.
  770. if (!xcons_p (tmp))
  771. this->mark (tmp, depth);
  772. swap (curr, pred);
  773. fwd = false;
  774. }
  775. }
  776. else
  777. {
  778. object tmp = xcar (pred);
  779. if (!cons_p (tmp))
  780. this->mark (tmp, depth);
  781. else if (as_cons(tmp)->gc_mark ())
  782. { // Found a sub-cons - Descend and move right.
  783. xcar(pred) = curr;
  784. curr = tmp;
  785. fwd = true;
  786. ++cnt;
  787. continue;
  788. }
  789. as_cons(pred)->gc_mark ();
  790. if (curr == UNBOUND)
  791. goto end;
  792. tmp = xcdr (curr);
  793. if ((!cons_p (tmp) && tmp != UNBOUND) ||
  794. left_tail_p (curr, cnt))
  795. { // Reached the end - Ascend and continue left.
  796. tmp = xcar (curr);
  797. xcar(curr) = pred;
  798. pred = curr, curr = tmp;
  799. --cnt;
  800. continue;
  801. }
  802. xcdr(curr) = pred;
  803. pred = curr, curr = tmp;
  804. if (curr == UNBOUND)
  805. {
  806. end:
  807. tmp = xcar (pred);
  808. if (!cons_p (tmp))
  809. {
  810. this->mark (tmp, depth);
  811. break;
  812. }
  813. else if (!as_cons(tmp)->gc_mark ())
  814. break;
  815. else
  816. { // Recurse on innermost cons.
  817. curr = tmp;
  818. pred = UNBOUND;
  819. fwd = true;
  820. }
  821. }
  822. }
  823. }
  824. }
  825. void gcinfo::mark_pkg (package *pkgp, uint32_t depth)
  826. {
  827. this->set_black (as_varobj (pkgp->name));
  828. this->mark (pkgp->path);
  829. /* For a package's symbol table, we don't want to mark temporary
  830. * symbols such as those produced by 'let' and function bindings,
  831. * since they are generally garbage. Therefore, we inline the
  832. * marking routine here. */
  833. array *syms = as_array (pkgp->syms);
  834. if (!this->set_black (syms))
  835. return;
  836. for (uint32_t i = 0; i < syms->len; ++i)
  837. {
  838. object s = syms->data[i];
  839. if (symbol_p (s) && symval (s) != UNBOUND)
  840. this->mark (s, depth);
  841. }
  842. }
  843. static inline bool
  844. composite_type_p (int tp)
  845. {
  846. switch (tp)
  847. {
  848. case typecode::ARRAY:
  849. case typecode::TABLE:
  850. case typecode::TUPLE:
  851. case typecode::CUSTOM:
  852. return (true);
  853. default:
  854. return (false);
  855. }
  856. }
  857. struct gc_visitor : public visitor
  858. {
  859. uint32_t depth;
  860. gcinfo* pgc;
  861. gc_visitor (uint32_t d) : depth (d), pgc (&KP_gc)
  862. {
  863. }
  864. void operator() (interpreter *, object obj)
  865. {
  866. this->pgc->mark (obj, this->depth);
  867. }
  868. };
  869. void gcinfo::mark (object obj, uint32_t depth)
  870. {
  871. // Unmask the extra bit and check for common values.
  872. if (obj == result<object>::ERROR)
  873. return;
  874. obj &= ~EXTRA_BIT;
  875. if (obj == NIL || obj == UNBOUND)
  876. return;
  877. int tp = itype (obj);
  878. if (tp == typecode::INT || tp == typecode::CHAR)
  879. return;
  880. else if (tp == typecode::CONS)
  881. {
  882. this->mark_cons (obj, depth);
  883. return;
  884. }
  885. depth_guard g { &depth };
  886. varobj *vp = as_varobj (obj);
  887. if (depth > MAX_MARK_DEPTH && composite_type_p (tp))
  888. {
  889. if (vp->flagged_p (this->gcbit | FLAGS_GCWIP))
  890. return;
  891. else if (vp->gc_link.linked_p ())
  892. { // Not a local varobject.
  893. vp->vo_full |= FLAGS_GCWIP;
  894. vp->gc_link.del ();
  895. this->gray.add_obj (vp);
  896. return;
  897. }
  898. }
  899. else if (!this->set_black (vp))
  900. return;
  901. switch (tp)
  902. {
  903. case typecode::ARRAY:
  904. {
  905. array *ap = (array *)vp;
  906. for (uint32_t i = 0; i < ap->len; ++i)
  907. this->mark (ap->data[i], depth);
  908. break;
  909. }
  910. case typecode::TABLE:
  911. {
  912. table *tp = (table *)vp;
  913. this->mark (tp->vector, depth);
  914. this->mark (tp->cmpfct, depth);
  915. this->mark (tp->hashfct, depth);
  916. break;
  917. }
  918. case typecode::TUPLE:
  919. {
  920. tuple *tp = (tuple *)vp;
  921. this->mark (tp->head, depth);
  922. this->mark (tp->test, depth);
  923. break;
  924. }
  925. case typecode::STREAM:
  926. {
  927. stream *strmp = (stream *)vp;
  928. this->mark (strmp->bvec);
  929. this->mark (strmp->ilock);
  930. this->mark (strmp->pos.state);
  931. this->mark (strmp->extra, depth);
  932. break;
  933. }
  934. case typecode::SYMBOL:
  935. {
  936. symbol *sp = (symbol *)vp;
  937. this->set_black (as_varobj (sp->name));
  938. this->mark (sp->value, depth);
  939. this->mark (sp->pkg, depth);
  940. break;
  941. }
  942. case typecode::PKG:
  943. this->mark_pkg ((package *)vp, depth);
  944. break;
  945. case typecode::FCT:
  946. {
  947. this->mark (fct_name (obj));
  948. if (vp->flagged_p (function_base::native_flag))
  949. return;
  950. function *fp = (function *)vp;
  951. this->set_black (as_varobj (fp->bcode));
  952. this->mark (fp->vals, depth);
  953. this->mark (fp->env, depth);
  954. break;
  955. }
  956. case typecode::CORO:
  957. {
  958. coroutine *crp = (coroutine *)vp;
  959. this->mark (crp->value, depth);
  960. this->mark (crp->argv, depth);
  961. this->mark (crp->dbinds, depth);
  962. break;
  963. }
  964. case typecode::THREAD:
  965. this->mark (((thread *)vp)->retval, depth);
  966. break;
  967. case typecode::INSTANCE:
  968. {
  969. auto instp = (instance *)vp;
  970. this->mark (instp->ptype, depth);
  971. this->mark (instp->slots, depth);
  972. this->mark (instp->tspec, depth);
  973. this->mark (instp->builtin, depth);
  974. break;
  975. }
  976. case typecode::CUSTOM:
  977. {
  978. gc_visitor v { depth };
  979. ((custom_base *)vp)->visit (nullptr, v);
  980. break;
  981. }
  982. }
  983. }
  984. static uintptr_t*
  985. cons_gc_data (const cons *cnp, uintptr_t& mask)
  986. {
  987. conspage *page = conspage::from_cons (cnp);
  988. uintptr_t *bp = page->bitmap ();
  989. uint32_t idx = (uint32_t)(cnp - page->at (0));
  990. mask = (uintptr_t)1 << (idx % BM_BITS);
  991. return (bp + idx / BM_BITS);
  992. }
  993. bool cons::gc_mark ()
  994. {
  995. uintptr_t mask, *bp = cons_gc_data (this, mask);
  996. if (*bp & mask)
  997. return (false);
  998. *bp |= mask;
  999. return (true);
  1000. }
  1001. bool cons::old_gen_p () const
  1002. {
  1003. uintptr_t mask, *bp = cons_gc_data (this, mask);
  1004. return ((*bp & mask) != 0);
  1005. }
  1006. void gcinfo::suspend_all (interpreter *interp)
  1007. {
  1008. this->n_suspended = 0;
  1009. lwlock_grab_nointr (interp, &all_threads_lock);
  1010. for (auto it = threads_iter (); it.valid (); ++it)
  1011. {
  1012. interpreter *ip2 = it->interp;
  1013. this->suspend_one (interp, ip2);
  1014. if (this->full_gc)
  1015. ip2->mmgr->clear_bitmaps (this->conses_per_page);
  1016. }
  1017. lwlock_drop (&all_threads_lock);
  1018. auto& ev = this->event;
  1019. lwlock_grab_nointr (interp, &ev.lock);
  1020. /* If we got here before the suspended threads acknowledged
  1021. * the request, wait for them now. */
  1022. if (ev.n_waiters != this->n_suspended)
  1023. for (ev.limit = this->n_suspended; ev.limit; )
  1024. ev.cv.wait_nointr (interp, &ev.lock);
  1025. lwlock_drop (&ev.lock);
  1026. }
  1027. void gcinfo::do_gc (interpreter *interp)
  1028. {
  1029. if (!this->enabled)
  1030. return;
  1031. else if (this->full_gc)
  1032. {
  1033. this->white.concat (&this->black);
  1034. this->black.reset ();
  1035. this->gcbit ^= GC_MASK;
  1036. }
  1037. this->event.reset ();
  1038. this->suspend_all (interp);
  1039. for (auto it = threads_iter (); it.valid (); ++it)
  1040. {
  1041. thread& thr = *it;
  1042. interpreter *ip2 = thr.interp;
  1043. auto mmgr = ip2->mmgr;
  1044. mmgr->reset_varobjs (*this);
  1045. mmgr->mark_cards (*this);
  1046. // Mark the interpreter's registers.
  1047. this->mark (ip2->thread);
  1048. this->mark (ip2->last_err);
  1049. this->mark (ip2->last_tb);
  1050. this->mark (ip2->retval);
  1051. this->mark (ip2->alval);
  1052. this->mark (ip2->aux);
  1053. if (ip2->xpkg != root_package)
  1054. this->mark (ip2->xpkg);
  1055. // Mark the interpreter's stack.
  1056. this->set_black (as_varobj (ip2->stkobj));
  1057. for (object *p = ip2->stack; p != ip2->stkend; ++p)
  1058. this->mark (*p);
  1059. // Mark the interpreter's dynamic bindings.
  1060. for (uintptr_t i = 0; i < ip2->n_tlsyms; ++i)
  1061. this->mark (ip2->tl_syms[i]);
  1062. // Mark the interpreter's temporary values.
  1063. for (auto i = ip2->values.iterator (&valref::link); i.valid (); ++i)
  1064. this->mark (i->value);
  1065. }
  1066. /* Also mark the GC cards of any thread that may have exited,
  1067. * and its memory manager was not reaped. */
  1068. for (auto mp = this->free_mgrs; mp; mp = mp->next)
  1069. mp->mark_cards (*this);
  1070. // Mark the builtins.
  1071. for (auto sp = symbol::fast_global_syms; *sp != UNBOUND; ++sp)
  1072. this->mark (*sp);
  1073. // Mark the global symbols.
  1074. this->mark_pkg (as_package (root_package), 0);
  1075. /* For the keyword package, we only mark the package object and
  1076. * the symbol table. The reason being, keywords will always survive,
  1077. * since their symbol value is aliased to themselves. */
  1078. {
  1079. package *kwp = as_package (kword_package);
  1080. this->set_black (as_varobj (kwp->name));
  1081. this->set_black (kwp);
  1082. this->set_black (as_array (kwp->syms));
  1083. }
  1084. while (!this->gray.empty ())
  1085. this->mark_gray ();
  1086. // Now the mark phase is over. Sweep the garbage.
  1087. size_t prev = this->acc_bytes;
  1088. for (auto it = threads_iter (); it.valid (); ++it)
  1089. it->interp->mmgr->sweep (*this);
  1090. this->sweep_varobjs (*this);
  1091. if (this->full_gc)
  1092. this->full_gc = false;
  1093. else if (this->acc_bytes >= prev / 3)
  1094. /* If we didn't manage to reclaim at least 2/3's of the
  1095. * total memory, perform a full collection next time. */
  1096. this->full_gc = true;
  1097. // Reset the allocated bytes accumulator.
  1098. this->acc_bytes = 0;
  1099. // GC done. Resume the world.
  1100. this->resume_all (interp);
  1101. }
  1102. result<void> gcinfo::exit (interpreter *interp, object val)
  1103. {
  1104. auto g = KP_TRY (evh_guard::make (interp));
  1105. if (!singlethr_p ())
  1106. {
  1107. this->lock (interp);
  1108. lwlock_grab_nointr (interp, &all_threads_lock);
  1109. for (auto it = threads_iter (); it.valid (); ++it)
  1110. {
  1111. interpreter *ip2 = it->interp;
  1112. this->suspend_one (interp, ip2);
  1113. ip2->mmgr->reset_varobjs (*this);
  1114. }
  1115. this->unlock ();
  1116. }
  1117. int status;
  1118. if (fixint_p (val))
  1119. status = as_int (val);
  1120. else
  1121. {
  1122. KP_TRY (xwrite (interp, as_stream (out_stream), val));
  1123. status = 1;
  1124. }
  1125. ::exit (status);
  1126. return (0); // NOTREACHED.
  1127. }
  1128. result<void> gc (bool full)
  1129. {
  1130. interpreter *interp = interpreter::self ();
  1131. auto g = KP_TRY (evh_guard::make (interp));
  1132. KP_MT_BEGIN (KP_gc.lock (interp));
  1133. KP_gc.full_gc = KP_gc.full_gc || full;
  1134. KP_gc.do_gc (interp);
  1135. KP_MT_END (KP_gc.unlock ());
  1136. return (0);
  1137. }
  1138. static inline bool
  1139. oldgen_p (object obj, uintptr_t bit)
  1140. {
  1141. return ((varobj_p (obj) && as_varobj(obj)->flagged_p (bit)) ||
  1142. (xcons_p (obj) && as_cons(obj)->old_gen_p ()));
  1143. }
  1144. result<void> gc_wbarrier (interpreter *interp, object parent, object obj)
  1145. {
  1146. auto bit = KP_gc.gcbit;
  1147. if (immediate_p (obj) || obj == NIL || KP_gc.full_gc ||
  1148. oldgen_p (obj, bit) || !oldgen_p (parent, bit))
  1149. return (0);
  1150. else if (!xcons_p (parent))
  1151. {
  1152. varobj *vp = as_varobj (parent);
  1153. if (vp->cas_flag (bit, FLAGS_GCDIRTY))
  1154. { /* This object is in the black set. Unlinking it should be safe,
  1155. * even in the presence of multiple threads. */
  1156. vp->gc_link.del ();
  1157. interp->mmgr->vobjs.add_obj (vp);
  1158. }
  1159. return (0);
  1160. }
  1161. switch (itype (obj))
  1162. {
  1163. case typecode::BVECTOR:
  1164. case typecode::STR:
  1165. case typecode::BIGINT:
  1166. case typecode::FLOAT:
  1167. case typecode::BIGFLOAT:
  1168. /* Avoid potentially expensive memory allocations when a single
  1169. * atomic flag setting can do the job. */
  1170. as_varobj(obj)->set_flag (bit);
  1171. return (0);
  1172. default:
  1173. return (interp->mmgr->cards.add_obj (interp, parent));
  1174. }
  1175. }
  1176. static void
  1177. call_finalizers (dlist *lstp)
  1178. {
  1179. for (auto it = lstp->iterator (&finobj::gc_link); it.valid (); ++it)
  1180. {
  1181. finobj *fp = (finobj *)&*it;
  1182. if (fp->fini)
  1183. fp->fini (fp);
  1184. }
  1185. }
  1186. bool memory_init ()
  1187. {
  1188. return (KP_gc.init ());
  1189. }
  1190. bool& gc_status ()
  1191. {
  1192. return (KP_gc.enabled);
  1193. }
  1194. result<object> exit_fct (interpreter *interp, object *argv, int argc)
  1195. {
  1196. KP_TRY (KP_gc.exit (interp, argc ? *argv : fixint (0)));
  1197. return (fixint (0));
  1198. }
  1199. void memory_exit ()
  1200. {
  1201. interpreter *interp = interpreter::self ();
  1202. evh_safeguard eg { interp };
  1203. deref (as_stream(out_stream)->flush (interp));
  1204. deref (as_stream(err_stream)->flush (interp));
  1205. KP_MT_BEGIN (KP_gc.lock (interp));
  1206. for (auto it = threads_iter (); it.valid (); ++it)
  1207. call_finalizers (&it->interp->mmgr->vobjs.sets[FINOBJ_IDX]);
  1208. call_finalizers (&KP_gc.black.sets[FINOBJ_IDX]);
  1209. call_finalizers (&KP_gc.white.sets[FINOBJ_IDX]);
  1210. }
  1211. KP_DECLS_END