PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/c/gbc-new.d

https://gitlab.com/jlarocco/ecl
D | 986 lines | 755 code | 129 blank | 102 comment | 156 complexity | d18693c3359ff5adf9c72f86e22314d8 MD5 | raw file
Possible License(s): LGPL-2.0, JSON
  1. /* -*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*- */
  2. /* vim: set filetype=c tabstop=8 shiftwidth=4 expandtab: */
  3. /*
  4. gbc.c -- Garbage collector.
  5. */
  6. /*
  7. Copyright (c) 1984, Taiichi Yuasa and Masami Hagiya.
  8. Copyright (c) 1990, Giuseppe Attardi and William F. Schelter.
  9. Copyright (c) 2001, Juan Jose Garcia Ripoll.
  10. ECL is free software; you can redistribute it and/or
  11. modify it under the terms of the GNU Library General Public
  12. License as published by the Free Software Foundation; either
  13. version 2 of the License, or (at your option) any later version.
  14. See file '../Copyright' for full details.
  15. */
  16. #include "ecl.h"
  17. #include "page.h"
  18. /******************************* EXPORTS ******************************/
  19. bool GC_enable;
  20. int gc_time; /* Beppe */
  21. /******************************* ------- ******************************/
  22. /*
  23. mark_table[m]:i represents word w = 128*m + 4*i, where m = addr-DATA_START.
  24. Therefore m = w >> 7, i = (w / 4) % 32 = (w >> 2) & 0x1f.
  25. */
  26. static int *mark_table;
  27. static void inline
  28. set_mark_bit(void *x) {
  29. int w = (int)x;
  30. int m = (w - DATA_START) >> 7;
  31. int i = (w >> 2) & 0x1f;
  32. mark_table[m] |= (1 << i);
  33. }
  34. static int inline
  35. get_mark_bit(void *x) {
  36. int w = (int)x;
  37. int m = (w - DATA_START) >> 7;
  38. int i = (w >> 2) & 0x1f;
  39. return (mark_table[m] >> i) & 1;
  40. }
  41. #define inheap(pp) ((unsigned long)(pp) < (unsigned long)heap_end)
  42. #define VALID_DATA_ADDRESS(pp) \
  43. !ECL_IMMEDIATE(pp) && (cl_index)DATA_START <= (cl_index)(pp) && (cl_index)(pp) < (cl_index)heap_end
  44. cl_object siVgc_verbose;
  45. cl_object siVgc_message;
  46. static bool debug = FALSE;
  47. static int maxpage;
  48. #define GC_ROOT_MAX 200
  49. static cl_object *gc_root[GC_ROOT_MAX];
  50. static int gc_roots;
  51. static bool collect_blocks;
  52. /*
  53. We must register location, since value may be reassigned (e.g. malloc_list)
  54. */
  55. static void _mark_object (cl_object x);
  56. static void _mark_contblock (void *p, size_t s);
  57. extern void sigint (void);
  58. void
  59. register_root(cl_object *p)
  60. {
  61. if (gc_roots >= GC_ROOT_MAX)
  62. error("too many roots");
  63. gc_root[gc_roots++] = p;
  64. }
  65. @(defun gc (area)
  66. @
  67. if (!GC_enabled())
  68. error("GC is not enabled");
  69. if (Null(area))
  70. gc(t_cons);
  71. else
  72. gc(t_contiguous);
  73. @(return)
  74. @)
  75. /*----------------------------------------------------------------------
  76. * Mark phase
  77. *----------------------------------------------------------------------
  78. */
  79. /* Whenever two arrays are linked together by displacement,
  80. if one is live, the other will be made live */
  81. #define mark_displaced(ar) mark_object(ar)
  82. #define mark_contblock(x,s) {if (collect_blocks) _mark_contblock(x,s); }
  83. #if 1
  84. #define mark_object(x) if ((x != OBJNULL) && !ECL_IMMEDIATE(x)) _mark_object(x)
  85. #define mark_next(a) if ((a != OBJNULL) && !ECL_IMMEDIATE(a)) { x=(a); goto BEGIN; }
  86. #else
  87. #define mark_object(x) _mark_object(x)
  88. #define mark_next(a) x=(a); goto BEGIN
  89. #endif
  90. /* We make bitvectors multiple of sizeof(int) in size allocated
  91. Assume 8 = number of bits in char */
  92. #define W_SIZE (8*sizeof(int))
  93. static void
  94. _mark_object(cl_object x)
  95. {
  96. size_t i, j;
  97. cl_object *p, y;
  98. char *cp;
  99. cs_check(x);
  100. BEGIN:
  101. #if 0
  102. /* We cannot get here because mark_object() and mark_next() already check this */
  103. if (ECL_IMMEDIATE(x)) return; /* fixnum, character or locative */
  104. if (x == OBJNULL)
  105. return;
  106. #endif
  107. if (get_mark_bit(x))
  108. return;
  109. set_mark_bit(x);
  110. switch (ecl_t_of(x)) {
  111. case t_bignum:
  112. #ifdef WITH_GMP
  113. if (collect_blocks) {
  114. /* GMP may set num.alloc before actually allocating anything.
  115. With these checks we make sure we do not move anything
  116. we don't have to. Besides, we use big_dim as the size
  117. of the object, because big_size might even be smaller.
  118. */
  119. char *limbs = (char *)x->big.big_limbs;
  120. size_t size = x->big.big_dim * sizeof(mp_limb_t);
  121. if (size) mark_contblock(limbs, size);
  122. }
  123. #endif /* WITH_GMP */
  124. break;
  125. case t_ratio:
  126. mark_object(x->ratio.num);
  127. mark_next(x->ratio.den);
  128. break;
  129. #ifdef ECL_SSE2
  130. case t_sse_pack:
  131. #endif
  132. case t_singlefloat:
  133. case t_doublefloat:
  134. break;
  135. case t_complex:
  136. mark_object(x->complex.imag);
  137. mark_next(x->complex.real);
  138. break;
  139. case t_character:
  140. break;
  141. case t_symbol:
  142. mark_object(x->symbol.name);
  143. mark_object(x->symbol.plist);
  144. mark_object(ECL_SYM_FUN(x));
  145. mark_next(SYM_VAL(x));
  146. break;
  147. case t_package:
  148. mark_object(x->pack.name);
  149. mark_object(x->pack.nicknames);
  150. mark_object(x->pack.shadowings);
  151. mark_object(x->pack.uses);
  152. mark_object(x->pack.usedby);
  153. mark_object(x->pack.internal);
  154. mark_next(x->pack.external);
  155. break;
  156. case t_cons:
  157. mark_object(CAR(x));
  158. mark_next(CDR(x));
  159. break;
  160. case t_hashtable:
  161. mark_object(x->hash.rehash_size);
  162. mark_object(x->hash.threshold);
  163. if (x->hash.data == NULL)
  164. break;
  165. for (i = 0, j = x->hash.size; i < j; i++) {
  166. mark_object(x->hash.data[i].key);
  167. mark_object(x->hash.data[i].value);
  168. }
  169. mark_contblock(x->hash.data, j * sizeof(struct hashtable_entry));
  170. break;
  171. case t_array:
  172. mark_contblock(x->array.dims, sizeof(x->array.dims[0])*x->array.rank);
  173. #ifdef ECL_UNICODE
  174. case t_string:
  175. #endif
  176. case t_vector:
  177. if ((y = x->array.displaced) != ECL_NIL)
  178. mark_displaced(y);
  179. cp = (char *)x->array.self.t;
  180. if (cp == NULL)
  181. break;
  182. switch ((enum aelttype)x->array.elttype) {
  183. #ifdef ECL_UNICODE
  184. case ecl_aet_ch:
  185. #endif
  186. case ecl_aet_object:
  187. if (x->array.displaced == ECL_NIL || CAR(x->array.displaced) == ECL_NIL) {
  188. cl_object *p = x->array.self.t;
  189. cl_index i;
  190. if (x->array.t == t_vector && x->vector.hasfillp)
  191. i = x->vector.fillp;
  192. else
  193. i = x->vector.dim;
  194. while (i-- > 0)
  195. mark_object(p[i]);
  196. }
  197. j = sizeof(cl_object)*x->array.dim;
  198. break;
  199. case ecl_aet_bc:
  200. j = x->array.dim;
  201. break;
  202. case ecl_aet_bit:
  203. j = sizeof(int) * ((x->vector.offset + x->vector.dim + W_SIZE -1)/W_SIZE);
  204. break;
  205. case ecl_aet_fix:
  206. j = x->array.dim * sizeof(cl_fixnum);
  207. break;
  208. case ecl_aet_sf:
  209. j = x->array.dim * sizeof(float);
  210. break;
  211. case ecl_aet_df:
  212. j = x->array.dim * sizeof(double);
  213. break;
  214. default:
  215. error("Allocation botch: unknown array element type");
  216. }
  217. goto COPY_ARRAY;
  218. case t_base_string:
  219. if ((y = x->base_string.displaced) != ECL_NIL)
  220. mark_displaced(y);
  221. cp = x->base_string.self;
  222. if (cp == NULL)
  223. break;
  224. j = x->base_string.dim;
  225. COPY_ARRAY:
  226. mark_contblock(cp, j);
  227. break;
  228. case t_bitvector:
  229. if ((y = x->vector.displaced) != ECL_NIL)
  230. mark_displaced(y);
  231. cp = x->vector.self.bit;
  232. if (cp == NULL)
  233. break;
  234. j= sizeof(int) * ((x->vector.offset + x->vector.dim + W_SIZE -1)/W_SIZE);
  235. goto COPY_ARRAY;
  236. case t_stream:
  237. switch ((enum smmode)x->stream.mode) {
  238. case ecl_smm_closed:
  239. /* Rest of fields are NULL */
  240. mark_next(x->stream.object1);
  241. break;
  242. case ecl_smm_input:
  243. case ecl_smm_output:
  244. case ecl_smm_io:
  245. case ecl_smm_probe:
  246. mark_object(x->stream.object0);
  247. mark_object(x->stream.object1);
  248. mark_contblock(x->stream.buffer, BUFSIZ);
  249. break;
  250. case ecl_smm_synonym:
  251. mark_next(x->stream.object0);
  252. break;
  253. case ecl_smm_broadcast:
  254. case ecl_smm_concatenated:
  255. mark_next(x->stream.object0);
  256. break;
  257. case ecl_smm_two_way:
  258. case ecl_smm_echo:
  259. mark_object(x->stream.object0);
  260. mark_next(x->stream.object1);
  261. break;
  262. case ecl_smm_string_input:
  263. case ecl_smm_string_output:
  264. mark_next(x->stream.object0);
  265. break;
  266. default:
  267. error("mark stream botch");
  268. }
  269. break;
  270. case t_random:
  271. break;
  272. case t_readtable:
  273. if (x->readtable.table == NULL)
  274. break;
  275. mark_contblock((char *)(x->readtable.table), RTABSIZE*sizeof(struct readtable_entry));
  276. for (i = 0; i < RTABSIZE; i++) {
  277. cl_object *p = x->readtable.table[i].dispatch_table;
  278. mark_object(x->readtable.table[i].macro);
  279. if (p != NULL) {
  280. mark_contblock(p, RTABSIZE*sizeof(cl_object));
  281. for (j = 0; j < RTABSIZE; j++)
  282. mark_object(p[j]);
  283. }
  284. }
  285. break;
  286. case t_pathname:
  287. mark_object(x->pathname.host);
  288. mark_object(x->pathname.device);
  289. mark_object(x->pathname.directory);
  290. mark_object(x->pathname.name);
  291. mark_object(x->pathname.type);
  292. mark_object(x->pathname.version);
  293. break;
  294. case t_bytecodes: {
  295. cl_index i, size;
  296. size = x->bytecodes.size;
  297. mark_object(x->bytecodes.lex);
  298. mark_contblock(x->bytecodes.data, size * sizeof(cl_object));
  299. for (i=0; i<size; i++)
  300. mark_object(x->bytecodes.data[i]);
  301. break;
  302. }
  303. case t_cfun:
  304. mark_object(x->cfun.block);
  305. mark_object(x->cfun.name);
  306. break;
  307. case t_cclosure:
  308. mark_object(x->cfun.block);
  309. mark_object(x->cclosure.env);
  310. break;
  311. #ifdef THREADS
  312. case t_cont:
  313. mark_next(x->cn.cn_thread);
  314. break;
  315. case t_thread:
  316. /* Already marked by malloc
  317. mark_contblock(x->thread.data, x->thread.size);
  318. */
  319. mark_next(x->thread.entry);
  320. break;
  321. #endif THREADS
  322. case t_instance:
  323. mark_object(x->instance.class);
  324. p = x->instance.slots;
  325. if (p == NULL)
  326. break;
  327. for (i = 0, j = x->instance.length; i < j; i++)
  328. mark_object(p[i]);
  329. mark_contblock(p, j*sizeof(cl_object));
  330. break;
  331. case t_gfun:
  332. mark_object(x->gfun.name);
  333. mark_object(x->gfun.method_hash);
  334. mark_object(x->gfun.instance);
  335. p = x->gfun.specializers;
  336. if (p == NULL)
  337. break;
  338. for (i = 0, j = x->gfun.arg_no; i < j; i++)
  339. mark_object(p[i]);
  340. mark_contblock(p, j*sizeof(cl_object));
  341. break;
  342. case t_codeblock:
  343. mark_object(x->cblock.name);
  344. mark_contblock(x->cblock.start, x->cblock.size);
  345. if (x->cblock.data) {
  346. cl_index i = x->cblock.data_size;
  347. cl_object *p = x->cblock.data;
  348. while (i--)
  349. mark_object(p[i]);
  350. }
  351. break;
  352. default:
  353. if (debug)
  354. printf("\ttype = %d\n", ecl_t_of(x));
  355. error("mark botch");
  356. }
  357. }
  358. static void
  359. mark_stack_conservative(int *top, int *bottom)
  360. {
  361. int p, m;
  362. cl_object x;
  363. struct typemanager *tm;
  364. register int *j;
  365. if (debug) { printf("Traversing C stack .."); fflush(stdout); }
  366. /* On machines which align local pointers on multiple of 2 rather
  367. than 4 we need to mark twice
  368. if (offset) mark_stack_conservative(bottom, ((char *) top) + offset, 0);
  369. */
  370. for (j = top ; j >= bottom ; j--) {
  371. /* improved Beppe: */
  372. if (VALID_DATA_ADDRESS(*j) && type_map[p = page(*j)] < (char)t_end) {
  373. tm = tm_of((enum type)type_map[p]);
  374. x = (cl_object)(*j - (*j - (int)pagetochar(p)) % tm->tm_size);
  375. if (!get_mark_bit(x))
  376. mark_object(x);
  377. }
  378. }
  379. if (debug) {printf(". done.\n"); fflush(stdout); }
  380. }
  381. static void
  382. mark_phase(void)
  383. {
  384. register int i;
  385. register struct package *pp;
  386. register ecl_bds_ptr bdp;
  387. register ecl_frame_ptr frp;
  388. register ecl_ihs_ptr ihsp;
  389. mark_object(ECL_NIL);
  390. mark_object(ECL_T);
  391. #ifdef THREADS
  392. {
  393. pd *pdp;
  394. lpd *old_clwp = clwp;
  395. for (pdp = running_head; pdp != (pd *)NULL; pdp = pdp->pd_next) {
  396. clwp = pdp->pd_lpd;
  397. #endif THREADS
  398. for (i=0; i<NValues; i++)
  399. mark_object(VALUES(i));
  400. for (bdp = bds_org; bdp <= bds_top; bdp++) {
  401. mark_object(bdp->bds_sym);
  402. mark_object(bdp->bds_val);
  403. }
  404. for (frp = frs_org; frp <= frs_top; frp++) {
  405. mark_object(frp->frs_val);
  406. mark_object(frp->frs_lex);
  407. }
  408. for (ihsp = ihs_org; ihsp <= ihs_top; ihsp++) {
  409. mark_object(ihsp->ihs_function);
  410. mark_object(ihsp->ihs_base);
  411. }
  412. mark_object(lex_env);
  413. #ifdef THREADS
  414. /* added to mark newly allocated objects */
  415. mark_object(clwp->lwp_alloc_temporary);
  416. mark_object(clwp->lwp_fmt_temporary_stream);
  417. mark_object(clwp->lwp_PRINTstream);
  418. mark_object(clwp->lwp_PRINTcase);
  419. mark_object(clwp->lwp_READtable);
  420. mark_object(clwp->lwp_delimiting_char);
  421. mark_object(clwp->lwp_token);
  422. /* (current-thread) can return it at any time
  423. */
  424. mark_object(clwp->lwp_thread);
  425. #endif THREADS
  426. /* now collect from the c-stack of the thread ... */
  427. { int *where;
  428. volatile jmp_buf buf;
  429. /* ensure flushing of register caches */
  430. if (ecl_setjmp(buf) == 0) ecl_longjmp(buf, 1);
  431. #ifdef THREADS
  432. if (clwp != old_clwp) /* is not the executing stack */
  433. # ifdef __linux
  434. where = (int *)pdp->pd_env[0].__jmpbuf[0].__sp;
  435. # else
  436. where = (int *)pdp->pd_env[JB_SP];
  437. # endif
  438. else
  439. #endif THREADS
  440. where = (int *)&where ;
  441. /* If the locals of type object in a C function could be
  442. aligned other than on multiples of sizeof (char *)
  443. we would have to mark twice */
  444. if (where > cs_org)
  445. mark_stack_conservative(where, cs_org);
  446. else
  447. mark_stack_conservative(cs_org, where);
  448. }
  449. #ifdef THREADS
  450. }
  451. clwp = old_clwp;
  452. }
  453. #endif THREADS
  454. /* mark roots */
  455. for (i = 0; i < gc_roots; i++)
  456. mark_object(*gc_root[i]);
  457. /* mark registered symbols & keywords */
  458. {
  459. const struct keyword_info *k;
  460. const struct symbol_info *s;
  461. for (k = all_keywords; k->loc != NULL; k++)
  462. mark_object(*(k->loc));
  463. for (s = all_symbols; s->loc != NULL; s++)
  464. mark_object(*(s->loc));
  465. }
  466. if (debug) {
  467. printf("symbol navigation\n");
  468. fflush(stdout);
  469. }
  470. }
  471. static void
  472. sweep_phase(void)
  473. {
  474. register int i, j, k;
  475. register cl_object x;
  476. register char *p;
  477. register struct typemanager *tm;
  478. register cl_object f;
  479. ECL_NIL->symbol.m = FALSE;
  480. ECL_T->symbol.m = FALSE;
  481. if (debug)
  482. printf("type map\n");
  483. for (i = 0; i < maxpage; i++) {
  484. if (type_map[i] == (int)t_contiguous) {
  485. if (debug) {
  486. printf("-");
  487. continue;
  488. }
  489. }
  490. if (type_map[i] >= (int)t_end)
  491. continue;
  492. tm = tm_of((enum type)type_map[i]);
  493. /*
  494. general sweeper
  495. */
  496. if (debug)
  497. printf("%c", tm->tm_name[0]);
  498. p = pagetochar(i);
  499. f = tm->tm_free;
  500. k = 0;
  501. for (j = tm->tm_nppage; j > 0; --j, p += tm->tm_size) {
  502. x = (cl_object)p;
  503. if (!get_mark_bit(x)) {
  504. ((struct freelist *)x)->f_link = f;
  505. f = x;
  506. k++;
  507. }
  508. }
  509. tm->tm_free = f;
  510. tm->tm_nfree += k;
  511. tm->tm_nused -= k;
  512. }
  513. if (debug) {
  514. putchar('\n');
  515. fflush(stdout);
  516. }
  517. }
  518. static void
  519. contblock_sweep_phase(void)
  520. {
  521. register int i, j;
  522. register char *s, *e, *p, *q;
  523. register struct contblock *cbp;
  524. cb_pointer = NULL;
  525. ncb = 0;
  526. for (i = 0; i < maxpage;) {
  527. if (type_map[i] != (int)t_contiguous) {
  528. i++;
  529. continue;
  530. }
  531. for (j = i+1;
  532. j < maxpage && type_map[j] == (int)t_contiguous;
  533. j++)
  534. ;
  535. s = pagetochar(i);
  536. e = pagetochar(j);
  537. for (p = s; p < e;) {
  538. if (get_mark_bit((int *)p)) {
  539. p += 4;
  540. continue;
  541. }
  542. q = p + 4;
  543. while (q < e && !get_mark_bit((int *)q))
  544. q += 4;
  545. dealloc(p, q - p);
  546. p = q + 4;
  547. }
  548. i = j + 1;
  549. }
  550. if (debug) {
  551. for (cbp = cb_pointer; cbp != NULL; cbp = cbp->cb_link)
  552. printf("0x%p %d\n", cbp, cbp->cb_size);
  553. fflush(stdout);
  554. }
  555. }
  556. cl_object (*GC_enter_hook)() = NULL;
  557. cl_object (*GC_exit_hook)() = NULL;
  558. #ifdef THREADS
  559. /*
  560. * We execute the GC routine in the main stack.
  561. * The idea is to switch over the main stack that is stopped in the intha
  562. * and to call the GC from there on garbage_parameter. Then you can switch
  563. * back after.
  564. * In addition the interrupt is disabled.
  565. */
  566. static int i, j;
  567. static sigjmp_buf old_env;
  568. static int val;
  569. static lpd *old_clwp;
  570. static enum type t;
  571. static bool stack_switched = FALSE;
  572. static enum type garbage_parameter;
  573. void
  574. gc(enum type new_name)
  575. {
  576. int tm;
  577. int gc_start = runtime();
  578. start_critical_section();
  579. t = new_name;
  580. garbage_parameter = new_name;
  581. #else
  582. void
  583. gc(enum type t)
  584. {
  585. int i, j;
  586. int tm;
  587. int gc_start = runtime();
  588. #endif THREADS
  589. if (!GC_enabled())
  590. return;
  591. if (SYM_VAL(siVgc_verbose) != ECL_NIL) {
  592. printf("\n[GC ..");
  593. /* To use this should add entries in tm_table for reloc and contig.
  594. fprintf(stdout, "\n[GC for %d %s pages ..",
  595. tm_of(t)->tm_npage,
  596. tm_table[(int)t].tm_name + 1); */
  597. fflush(stdout);
  598. }
  599. debug = symbol_value(siVgc_message) != ECL_NIL;
  600. #ifdef THREADS
  601. if (clwp != &main_lpd) {
  602. if (debug) {
  603. printf("*STACK SWITCH*\n");
  604. fflush (stdout);
  605. }
  606. stack_switched = TRUE;
  607. val = sigsetjmp(old_env, 1);
  608. if (val == 0) {
  609. /* informations used by the garbage collector need to be updated */
  610. # ifdef __linux
  611. running_head->pd_env[0].__jmpbuf[0].__sp = old_env[0].__jmpbuf[0].__sp;
  612. # else
  613. running_head->pd_env[JB_SP] = old_env[JB_SP];
  614. # endif
  615. old_clwp = clwp;
  616. Values = main_lpd.lwp_Values;
  617. clwp = &main_lpd;
  618. siglongjmp(main_pd.pd_env, 2); /* new line */
  619. }
  620. }
  621. else val = 1;
  622. if (val == 1) {
  623. #endif THREADS
  624. if (GC_enter_hook != NULL)
  625. (*GC_enter_hook)(0);
  626. interrupt_enable = FALSE;
  627. collect_blocks = t > t_end;
  628. if (collect_blocks)
  629. cbgccount++;
  630. else
  631. tm_table[(int)t].tm_gccount++;
  632. if (debug) {
  633. if (collect_blocks)
  634. printf("GC entered for collecting blocks\n");
  635. else
  636. printf("GC entered for collecting %s\n", tm_table[(int)t].tm_name);
  637. fflush(stdout);
  638. }
  639. maxpage = page(heap_end);
  640. if (collect_blocks) {
  641. /*
  642. 1 page = 512 word
  643. 512 bit = 16 word
  644. */
  645. int mark_table_size = maxpage * (LISP_PAGESIZE / 32);
  646. extern void resize_hole(size_t);
  647. if (holepage < mark_table_size*sizeof(int)/LISP_PAGESIZE + 1)
  648. new_holepage = mark_table_size*sizeof(int)/LISP_PAGESIZE + 1;
  649. if (new_holepage < HOLEPAGE)
  650. new_holepage = HOLEPAGE;
  651. resize_hole(new_holepage);
  652. mark_table = (int*)heap_end;
  653. for (i = 0; i < mark_table_size; i++)
  654. mark_table[i] = 0;
  655. }
  656. if (debug) {
  657. printf("mark phase\n");
  658. fflush(stdout);
  659. tm = runtime();
  660. }
  661. mark_phase();
  662. if (debug) {
  663. printf("mark ended (%d)\n", runtime() - tm);
  664. printf("sweep phase\n");
  665. fflush(stdout);
  666. tm = runtime();
  667. }
  668. sweep_phase();
  669. if (debug) {
  670. printf("sweep ended (%d)\n", runtime() - tm);
  671. fflush(stdout);
  672. }
  673. if (t == t_contiguous) {
  674. if (debug) {
  675. printf("contblock sweep phase\n");
  676. fflush(stdout);
  677. tm = runtime();
  678. }
  679. contblock_sweep_phase();
  680. if (debug)
  681. printf("contblock sweep ended (%d)\n", runtime() - tm);
  682. }
  683. if (debug) {
  684. for (i = 0, j = 0; i < (int)t_end; i++) {
  685. if (tm_table[i].tm_type == (enum type)i) {
  686. printf("%13s: %8d used %8d free %4d/%d pages\n",
  687. tm_table[i].tm_name,
  688. tm_table[i].tm_nused,
  689. tm_table[i].tm_nfree,
  690. tm_table[i].tm_npage,
  691. tm_table[i].tm_maxpage);
  692. j += tm_table[i].tm_npage;
  693. } else
  694. printf("%13s: linked to %s\n",
  695. tm_table[i].tm_name,
  696. tm_table[(int)tm_table[i].tm_type].tm_name);
  697. }
  698. printf("contblock: %d blocks %d pages\n", ncb, ncbpage);
  699. printf("hole: %d pages\n", holepage);
  700. printf("GC ended\n");
  701. fflush(stdout);
  702. }
  703. interrupt_enable = TRUE;
  704. if (GC_exit_hook != NULL)
  705. (*GC_exit_hook)();
  706. #ifdef THREADS
  707. /*
  708. * Back in the right stack
  709. */
  710. if (stack_switched) {
  711. if (debug) {
  712. printf("*STACK BACK*\n");
  713. fflush (stdout);
  714. }
  715. stack_switched = FALSE;
  716. end_critical_section(); /* we get here from the GC call in scheduler */
  717. clwp = old_clwp;
  718. Values = clwp->lwp_Values;
  719. siglongjmp(old_env, 2);
  720. }
  721. }
  722. #endif THREADS
  723. gc_time += (gc_start = runtime() - gc_start);
  724. if (SYM_VAL(siVgc_verbose) != ECL_NIL) {
  725. /* Don't use fprintf since on Linux it calls malloc() */
  726. printf(". finished in %.2f\"]", gc_start/60.0);
  727. fflush(stdout);
  728. }
  729. #ifdef unix
  730. if (interrupt_flag) sigint();
  731. #endif unix
  732. #ifdef THREADS
  733. end_critical_section();
  734. #endif THREADS
  735. }
  736. /*
  737. *----------------------------------------------------------------------
  738. *
  739. * mark_contblock --
  740. * sets the mark bit for words from address p to address p+s.
  741. * Both p and p+s are rounded to word boundaries.
  742. *
  743. * Results:
  744. * none.
  745. *
  746. * Side effects:
  747. * mark_table
  748. *
  749. *----------------------------------------------------------------------
  750. */
  751. static void
  752. _mark_contblock(void *x, size_t s)
  753. {
  754. register char *p = x, *q;
  755. register ptrdiff_t pg = page(p);
  756. if (pg < 0 || (enum type)type_map[pg] != t_contiguous)
  757. return;
  758. #if 1
  759. q = p + s;
  760. p = (char *)((int)p&~3);
  761. q = (char *)(((int)q+3)&~3);
  762. for (; p < q; p+= 4)
  763. set_mark_bit(p);
  764. #elif 0
  765. {
  766. int bit_start = ((int)p - DATA_START) >> 2;
  767. int bit_end = ((int)p + s + 3 - DATA_START) >> 2;
  768. int *w = &mark_table[bit_start >> 5];
  769. int b = bit_start & (32 - 1);
  770. int mask = ~0 << b;
  771. int bits = b + bit_end - bit_start;
  772. while (bits >= 32) {
  773. *w |= mask;
  774. w++;
  775. bits -= 32;
  776. mask = ~0;
  777. }
  778. mask &= ~(~0 << bits);
  779. *w |= mask;
  780. }
  781. #else
  782. {
  783. int bit_start = ((int)p - DATA_START) >> 2;
  784. int bits = ((int)p + s + 3 - DATA_START) >> 2 - bit_start;
  785. int mask = 1 << bit_start & (32 - 1);
  786. int *w = &mark_table[bit_start >> 5];
  787. while (bits) {
  788. *w |= mask;
  789. mask <<= 1;
  790. if (!mask) {
  791. mask = 1;
  792. w++;
  793. }
  794. }
  795. }
  796. #endif
  797. }
  798. /*----------------------------------------------------------------------
  799. * Utilities
  800. *----------------------------------------------------------------------
  801. */
  802. @(defun si::room-report ()
  803. int i;
  804. cl_object *tl;
  805. @
  806. NValues = 8;
  807. VALUES(0) = ecl_make_fixnum(real_maxpage);
  808. VALUES(1) = ecl_make_fixnum(available_pages());
  809. VALUES(2) = ecl_make_fixnum(ncbpage);
  810. VALUES(3) = ecl_make_fixnum(maxcbpage);
  811. VALUES(4) = ecl_make_fixnum(ncb);
  812. VALUES(5) = ecl_make_fixnum(cbgccount);
  813. VALUES(6) = ecl_make_fixnum(holepage);
  814. VALUES(7) = ECL_NIL;
  815. tl = &VALUES(7);
  816. for (i = 0; i < (int)t_end; i++) {
  817. if (tm_table[i].tm_type == (enum type)i) {
  818. tl = &CDR(*tl = CONS(ecl_make_fixnum(tm_table[i].tm_nused), ECL_NIL));
  819. tl = &CDR(*tl = CONS(ecl_make_fixnum(tm_table[i].tm_nfree), ECL_NIL));
  820. tl = &CDR(*tl = CONS(ecl_make_fixnum(tm_table[i].tm_npage), ECL_NIL));
  821. tl = &CDR(*tl = CONS(ecl_make_fixnum(tm_table[i].tm_maxpage), ECL_NIL));
  822. tl = &CDR(*tl = CONS(ecl_make_fixnum(tm_table[i].tm_gccount), ECL_NIL));
  823. } else {
  824. tl = &CDR(*tl = CONS(ECL_NIL, ECL_NIL));
  825. tl = &CDR(*tl = CONS(ecl_make_fixnum(tm_table[i].tm_type), ECL_NIL));
  826. tl = &CDR(*tl = CONS(ECL_NIL, ECL_NIL));
  827. tl = &CDR(*tl = CONS(ECL_NIL, ECL_NIL));
  828. tl = &CDR(*tl = CONS(ECL_NIL, ECL_NIL));
  829. }
  830. }
  831. return VALUES(0);
  832. @)
  833. @(defun si::reset-gc-count ()
  834. int i;
  835. @
  836. cbgccount = 0;
  837. for (i = 0; i < (int)t_end; i++)
  838. tm_table[i].tm_gccount = 0;
  839. @(return)
  840. @)
  841. @(defun si::gc-time ()
  842. @
  843. @(return ecl_make_fixnum(gc_time))
  844. @)
  845. void
  846. init_GC(void)
  847. {
  848. register_root(&siVgc_verbose);
  849. register_root(&siVgc_message);
  850. siVgc_verbose = make_si_special("*GC-VERBOSE*", ECL_NIL);
  851. siVgc_message = make_si_special("*GC-MESSAGE*", ECL_NIL);
  852. GC_enable();
  853. gc_time = 0;
  854. }