gc-card.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
  2. *
  3. * This library is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU Lesser General Public License
  5. * as published by the Free Software Foundation; either version 3 of
  6. * the License, or (at your option) any later version.
  7. *
  8. * This library is distributed in the hope that it will be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. * Lesser General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Lesser General Public
  14. * License along with this library; if not, write to the Free Software
  15. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  16. * 02110-1301 USA
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. # include <config.h>
  20. #endif
  21. #include <assert.h>
  22. #include <stdio.h>
  23. #include <count-one-bits.h>
  24. #include <gmp.h>
  25. #include "libguile/_scm.h"
  26. #include "libguile/async.h"
  27. #include "libguile/deprecation.h"
  28. #include "libguile/eval.h"
  29. #include "libguile/gc.h"
  30. #include "libguile/hashtab.h"
  31. #include "libguile/numbers.h"
  32. #include "libguile/ports.h"
  33. #include "libguile/private-gc.h"
  34. #include "libguile/root.h"
  35. #include "libguile/smob.h"
  36. #include "libguile/srfi-4.h"
  37. #include "libguile/stackchk.h"
  38. #include "libguile/stime.h"
  39. #include "libguile/strings.h"
  40. #include "libguile/struct.h"
  41. #include "libguile/tags.h"
  42. #include "libguile/unif.h"
  43. #include "libguile/validate.h"
  44. #include "libguile/vectors.h"
  45. #include "libguile/weaks.h"
  46. #include "libguile/private-gc.h"
  47. long int scm_i_deprecated_memory_return;
  48. /* During collection, this accumulates structures which are to be freed.
  49. */
  50. SCM scm_i_structs_to_free;
  51. /*
  52. Init all the free cells in CARD, prepending to *FREE_LIST.
  53. Return: FREE_COUNT, the number of cells collected. This is
  54. typically the length of the *FREE_LIST, but for some special cases,
  55. we do not actually free the cell. To make the numbers match up, we
  56. do increase the FREE_COUNT.
  57. It would be cleaner to have a separate function sweep_value (), but
  58. that is too slow (functions with switch statements can't be
  59. inlined).
  60. NOTE:
  61. For many types of cells, allocation and a de-allocation involves
  62. calling malloc () and free (). This is costly for small objects (due
  63. to malloc/free overhead.) (should measure this).
  64. It might also be bad for threads: if several threads are allocating
  65. strings concurrently, then mallocs for both threads may have to
  66. fiddle with locks.
  67. It might be interesting to add a separate memory pool for small
  68. objects to each freelist.
  69. --hwn.
  70. */
  71. int
  72. scm_i_sweep_card (scm_t_cell *card, SCM *free_list, scm_t_heap_segment *seg)
  73. #define FUNC_NAME "sweep_card"
  74. {
  75. scm_t_c_bvec_long *bitvec = SCM_GC_CARD_BVEC (card);
  76. scm_t_cell *end = card + SCM_GC_CARD_N_CELLS;
  77. scm_t_cell *p = card;
  78. int span = seg->span;
  79. int offset = SCM_MAX (SCM_GC_CARD_N_HEADER_CELLS, span);
  80. int free_count = 0;
  81. /*
  82. I tried something fancy with shifting by one bit every word from
  83. the bitvec in turn, but it wasn't any faster, but quite a bit
  84. hairier.
  85. */
  86. for (p += offset; p < end; p += span, offset += span)
  87. {
  88. SCM scmptr = PTR2SCM (p);
  89. if (SCM_C_BVEC_GET (bitvec, offset))
  90. continue;
  91. free_count++;
  92. switch (SCM_TYP7 (scmptr))
  93. {
  94. case scm_tcs_struct:
  95. /* The card can be swept more than once. Check that it's
  96. * the first time!
  97. */
  98. if (!SCM_STRUCT_GC_CHAIN (scmptr))
  99. {
  100. /* Structs need to be freed in a special order.
  101. * This is handled by GC C hooks in struct.c.
  102. */
  103. SCM_SET_STRUCT_GC_CHAIN (scmptr, scm_i_structs_to_free);
  104. scm_i_structs_to_free = scmptr;
  105. }
  106. continue;
  107. case scm_tcs_cons_imcar:
  108. case scm_tcs_cons_nimcar:
  109. case scm_tcs_closures:
  110. case scm_tc7_pws:
  111. break;
  112. case scm_tc7_wvect:
  113. case scm_tc7_vector:
  114. scm_i_vector_free (scmptr);
  115. break;
  116. case scm_tc7_number:
  117. switch SCM_TYP16 (scmptr)
  118. {
  119. case scm_tc16_real:
  120. break;
  121. case scm_tc16_big:
  122. mpz_clear (SCM_I_BIG_MPZ (scmptr));
  123. /* nothing else to do here since the mpz is in a double cell */
  124. break;
  125. case scm_tc16_complex:
  126. scm_gc_free (SCM_COMPLEX_MEM (scmptr), sizeof (scm_t_complex),
  127. "complex");
  128. break;
  129. case scm_tc16_fraction:
  130. /* nothing to do here since the num/denum of a fraction
  131. are proper SCM objects themselves. */
  132. break;
  133. }
  134. break;
  135. case scm_tc7_string:
  136. scm_i_string_free (scmptr);
  137. break;
  138. case scm_tc7_stringbuf:
  139. scm_i_stringbuf_free (scmptr);
  140. break;
  141. case scm_tc7_symbol:
  142. scm_i_symbol_free (scmptr);
  143. break;
  144. case scm_tc7_variable:
  145. break;
  146. case scm_tcs_subrs:
  147. /* the various "subrs" (primitives) are never freed */
  148. continue;
  149. case scm_tc7_port:
  150. if SCM_OPENP (scmptr)
  151. {
  152. int k = SCM_PTOBNUM (scmptr);
  153. size_t mm;
  154. #if (SCM_DEBUG_CELL_ACCESSES == 1)
  155. if (!(k < scm_numptob))
  156. {
  157. fprintf (stderr, "undefined port type");
  158. abort ();
  159. }
  160. #endif
  161. /* Keep "revealed" ports alive. */
  162. if (scm_revealed_count (scmptr) > 0)
  163. continue;
  164. /* Yes, I really do mean scm_ptobs[k].free */
  165. /* rather than ftobs[k].close. .close */
  166. /* is for explicit CLOSE-PORT by user */
  167. mm = scm_ptobs[k].free (scmptr);
  168. if (mm != 0)
  169. {
  170. #if SCM_ENABLE_DEPRECATED == 1
  171. scm_c_issue_deprecation_warning
  172. ("Returning non-0 from a port free function is "
  173. "deprecated. Use scm_gc_free et al instead.");
  174. scm_c_issue_deprecation_warning_fmt
  175. ("(You just returned non-0 while freeing a %s.)",
  176. SCM_PTOBNAME (k));
  177. scm_i_deprecated_memory_return += mm;
  178. #else
  179. abort ();
  180. #endif
  181. }
  182. SCM_SETSTREAM (scmptr, 0);
  183. scm_i_remove_port (scmptr);
  184. SCM_CLR_PORT_OPEN_FLAG (scmptr);
  185. }
  186. break;
  187. case scm_tc7_smob:
  188. switch SCM_TYP16 (scmptr)
  189. {
  190. case scm_tc_free_cell:
  191. break;
  192. default:
  193. {
  194. int k;
  195. k = SCM_SMOBNUM (scmptr);
  196. #if (SCM_DEBUG_CELL_ACCESSES == 1)
  197. if (!(k < scm_numsmob))
  198. {
  199. fprintf (stderr, "undefined smob type");
  200. abort ();
  201. }
  202. #endif
  203. if (scm_smobs[k].free)
  204. {
  205. size_t mm;
  206. mm = scm_smobs[k].free (scmptr);
  207. if (mm != 0)
  208. {
  209. #if SCM_ENABLE_DEPRECATED == 1
  210. scm_c_issue_deprecation_warning
  211. ("Returning non-0 from a smob free function is "
  212. "deprecated. Use scm_gc_free et al instead.");
  213. scm_c_issue_deprecation_warning_fmt
  214. ("(You just returned non-0 while freeing a %s.)",
  215. SCM_SMOBNAME (k));
  216. scm_i_deprecated_memory_return += mm;
  217. #else
  218. abort ();
  219. #endif
  220. }
  221. }
  222. break;
  223. }
  224. }
  225. break;
  226. default:
  227. fprintf (stderr, "unknown type");
  228. abort ();
  229. }
  230. SCM_GC_SET_CELL_WORD (scmptr, 0, scm_tc_free_cell);
  231. SCM_SET_FREE_CELL_CDR (scmptr, PTR2SCM (*free_list));
  232. *free_list = scmptr;
  233. }
  234. return free_count;
  235. }
  236. #undef FUNC_NAME
  237. /*
  238. Like sweep, but no complicated logic to do the sweeping.
  239. */
  240. int
  241. scm_i_init_card_freelist (scm_t_cell *card, SCM *free_list,
  242. scm_t_heap_segment *seg)
  243. {
  244. int span = seg->span;
  245. scm_t_cell *end = card + SCM_GC_CARD_N_CELLS;
  246. scm_t_cell *p = end - span;
  247. int collected = 0;
  248. scm_t_c_bvec_long *bvec_ptr = (scm_t_c_bvec_long*) seg->bounds[1];
  249. int idx = (card - seg->bounds[0]) / SCM_GC_CARD_N_CELLS;
  250. bvec_ptr += idx * SCM_GC_CARD_BVEC_SIZE_IN_LONGS;
  251. SCM_GC_SET_CELL_BVEC (card, bvec_ptr);
  252. /*
  253. ASSUMPTION: n_header_cells <= 2.
  254. */
  255. for (; p > card; p -= span)
  256. {
  257. const SCM scmptr = PTR2SCM (p);
  258. SCM_GC_SET_CELL_WORD (scmptr, 0, scm_tc_free_cell);
  259. SCM_SET_FREE_CELL_CDR (scmptr, PTR2SCM (*free_list));
  260. *free_list = scmptr;
  261. collected ++;
  262. }
  263. return collected;
  264. }
  265. /*
  266. Amount of cells marked in this cell, measured in 1-cells.
  267. */
  268. int
  269. scm_i_card_marked_count (scm_t_cell *card, int span)
  270. {
  271. scm_t_c_bvec_long* bvec = SCM_GC_CARD_BVEC (card);
  272. scm_t_c_bvec_long* bvec_end = (bvec + SCM_GC_CARD_BVEC_SIZE_IN_LONGS);
  273. int count = 0;
  274. while (bvec < bvec_end)
  275. {
  276. count += count_one_bits_l (*bvec);
  277. bvec ++;
  278. }
  279. return count * span;
  280. }
  281. void
  282. scm_i_card_statistics (scm_t_cell *p, SCM hashtab, scm_t_heap_segment *seg)
  283. {
  284. scm_t_c_bvec_long *bitvec = SCM_GC_CARD_BVEC (p);
  285. scm_t_cell * end = p + SCM_GC_CARD_N_CELLS;
  286. int span = seg->span;
  287. int offset = SCM_MAX (SCM_GC_CARD_N_HEADER_CELLS, span);
  288. if (!bitvec)
  289. /* Card P hasn't been initialized yet by `scm_i_init_card_freelist ()'. */
  290. return;
  291. for (p += offset; p < end; p += span, offset += span)
  292. {
  293. scm_t_bits tag = -1;
  294. SCM scmptr = PTR2SCM (p);
  295. if (!SCM_C_BVEC_GET (bitvec, offset))
  296. continue;
  297. tag = SCM_TYP7 (scmptr);
  298. if (tag == scm_tc7_smob || tag == scm_tc7_number)
  299. {
  300. /* Record smobs and numbers under 16 bits of the tag, so the
  301. different smob objects are distinguished, and likewise the
  302. different numbers big, real, complex and fraction. */
  303. tag = SCM_TYP16(scmptr);
  304. }
  305. else
  306. switch (tag)
  307. {
  308. case scm_tcs_cons_imcar:
  309. tag = scm_tc2_int;
  310. break;
  311. case scm_tcs_cons_nimcar:
  312. tag = scm_tc3_cons;
  313. break;
  314. case scm_tcs_struct:
  315. tag = scm_tc3_struct;
  316. break;
  317. case scm_tcs_closures:
  318. tag = scm_tc3_closure;
  319. break;
  320. case scm_tcs_subrs:
  321. tag = scm_tc7_asubr;
  322. break;
  323. }
  324. {
  325. SCM handle = scm_hashq_create_handle_x (hashtab,
  326. scm_from_int (tag), SCM_INUM0);
  327. SCM_SETCDR (handle, scm_from_int (scm_to_int (SCM_CDR (handle)) + 1));
  328. }
  329. }
  330. }
  331. /* TAG is the tag word of a cell, return a string which is its name, or NULL
  332. if unknown. Currently this is only used by gc-live-object-stats and the
  333. distinctions between types are oriented towards what that code records
  334. while scanning what's alive. */
  335. char const *
  336. scm_i_tag_name (scm_t_bits tag)
  337. {
  338. switch (tag & 0x7F) /* 7 bits */
  339. {
  340. case scm_tcs_struct:
  341. return "struct";
  342. case scm_tcs_cons_imcar:
  343. return "cons (immediate car)";
  344. case scm_tcs_cons_nimcar:
  345. return "cons (non-immediate car)";
  346. case scm_tcs_closures:
  347. return "closures";
  348. case scm_tc7_pws:
  349. return "pws";
  350. case scm_tc7_wvect:
  351. return "weak vector";
  352. case scm_tc7_vector:
  353. return "vector";
  354. case scm_tc7_number:
  355. switch (tag)
  356. {
  357. case scm_tc16_real:
  358. return "real";
  359. case scm_tc16_big:
  360. return "bignum";
  361. case scm_tc16_complex:
  362. return "complex number";
  363. case scm_tc16_fraction:
  364. return "fraction";
  365. }
  366. /* shouldn't reach here unless there's a new class of numbers */
  367. return "number";
  368. case scm_tc7_string:
  369. return "string";
  370. case scm_tc7_stringbuf:
  371. return "string buffer";
  372. case scm_tc7_symbol:
  373. return "symbol";
  374. case scm_tc7_variable:
  375. return "variable";
  376. case scm_tcs_subrs:
  377. return "subrs";
  378. case scm_tc7_port:
  379. return "port";
  380. case scm_tc7_smob:
  381. /* scm_tc_free_cell is smob 0, the name field in that scm_smobs[]
  382. entry should be ok for our return here */
  383. return scm_smobs[SCM_TC2SMOBNUM (tag)].name;
  384. }
  385. return NULL;
  386. }
  387. #if (SCM_DEBUG_DEBUGGING_SUPPORT == 1)
  388. typedef struct scm_dbg_t_list_cell {
  389. scm_t_bits car;
  390. struct scm_dbg_t_list_cell * cdr;
  391. } scm_dbg_t_list_cell;
  392. typedef struct scm_dbg_t_double_cell {
  393. scm_t_bits word_0;
  394. scm_t_bits word_1;
  395. scm_t_bits word_2;
  396. scm_t_bits word_3;
  397. } scm_dbg_t_double_cell;
  398. int scm_dbg_gc_marked_p (SCM obj);
  399. scm_t_cell * scm_dbg_gc_get_card (SCM obj);
  400. scm_t_c_bvec_long * scm_dbg_gc_get_bvec (SCM obj);
  401. int
  402. scm_dbg_gc_marked_p (SCM obj)
  403. {
  404. if (!SCM_IMP (obj))
  405. return SCM_GC_MARK_P (obj);
  406. else
  407. return 0;
  408. }
  409. scm_t_cell *
  410. scm_dbg_gc_get_card (SCM obj)
  411. {
  412. if (!SCM_IMP (obj))
  413. return SCM_GC_CELL_CARD (obj);
  414. else
  415. return NULL;
  416. }
  417. scm_t_c_bvec_long *
  418. scm_dbg_gc_get_bvec (SCM obj)
  419. {
  420. if (!SCM_IMP (obj))
  421. return SCM_GC_CARD_BVEC (SCM_GC_CELL_CARD (obj));
  422. else
  423. return NULL;
  424. }
  425. #endif