finalize.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. /*
  2. * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
  3. * Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
  4. * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
  5. * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
  6. * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
  7. *
  8. * Permission is hereby granted to use or copy this program
  9. * for any purpose, provided the above notices are retained on all copies.
  10. * Permission to modify the code and to distribute modified code is granted,
  11. * provided the above notices are retained, and a notice that the code was
  12. * modified is included with the above copyright notice.
  13. */
  14. /* Boehm, February 1, 1996 1:19 pm PST */
  15. # define I_HIDE_POINTERS
  16. # include "private/gc_pmark.h"
  17. # ifdef FINALIZE_ON_DEMAND
  18. int GC_finalize_on_demand = 1;
  19. # else
  20. int GC_finalize_on_demand = 0;
  21. # endif
  22. # ifdef JAVA_FINALIZATION
  23. int GC_java_finalization = 1;
  24. # else
  25. int GC_java_finalization = 0;
  26. # endif
  27. /* Type of mark procedure used for marking from finalizable object. */
  28. /* This procedure normally does not mark the object, only its */
  29. /* descendents. */
  30. typedef void finalization_mark_proc(/* ptr_t finalizable_obj_ptr */);
  31. # define HASH3(addr,size,log_size) \
  32. ((((word)(addr) >> 3) ^ ((word)(addr) >> (3+(log_size)))) \
  33. & ((size) - 1))
  34. #define HASH2(addr,log_size) HASH3(addr, 1 << log_size, log_size)
  35. struct hash_chain_entry {
  36. word hidden_key;
  37. struct hash_chain_entry * next;
  38. };
  39. unsigned GC_finalization_failures = 0;
  40. /* Number of finalization requests that failed for lack of memory. */
  41. static struct disappearing_link {
  42. struct hash_chain_entry prolog;
  43. # define dl_hidden_link prolog.hidden_key
  44. /* Field to be cleared. */
  45. # define dl_next(x) (struct disappearing_link *)((x) -> prolog.next)
  46. # define dl_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
  47. word dl_hidden_obj; /* Pointer to object base */
  48. } **dl_head = 0;
  49. static signed_word log_dl_table_size = -1;
  50. /* Binary log of */
  51. /* current size of array pointed to by dl_head. */
  52. /* -1 ==> size is 0. */
  53. word GC_dl_entries = 0; /* Number of entries currently in disappearing */
  54. /* link table. */
  55. static struct finalizable_object {
  56. struct hash_chain_entry prolog;
  57. # define fo_hidden_base prolog.hidden_key
  58. /* Pointer to object base. */
  59. /* No longer hidden once object */
  60. /* is on finalize_now queue. */
  61. # define fo_next(x) (struct finalizable_object *)((x) -> prolog.next)
  62. # define fo_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
  63. GC_finalization_proc fo_fn; /* Finalizer. */
  64. ptr_t fo_client_data;
  65. word fo_object_size; /* In bytes. */
  66. finalization_mark_proc * fo_mark_proc; /* Mark-through procedure */
  67. } **fo_head = 0;
  68. struct finalizable_object * GC_finalize_now = 0;
  69. /* LIst of objects that should be finalized now. */
  70. static signed_word log_fo_table_size = -1;
  71. word GC_fo_entries = 0;
  72. void GC_push_finalizer_structures GC_PROTO((void))
  73. {
  74. GC_push_all((ptr_t)(&dl_head), (ptr_t)(&dl_head) + sizeof(word));
  75. GC_push_all((ptr_t)(&fo_head), (ptr_t)(&fo_head) + sizeof(word));
  76. GC_push_all((ptr_t)(&GC_finalize_now),
  77. (ptr_t)(&GC_finalize_now) + sizeof(word));
  78. }
  79. /* Double the size of a hash table. *size_ptr is the log of its current */
  80. /* size. May be a noop. */
  81. /* *table is a pointer to an array of hash headers. If we succeed, we */
  82. /* update both *table and *log_size_ptr. */
  83. /* Lock is held. Signals are disabled. */
  84. void GC_grow_table(table, log_size_ptr)
  85. struct hash_chain_entry ***table;
  86. signed_word * log_size_ptr;
  87. {
  88. register word i;
  89. register struct hash_chain_entry *p;
  90. int log_old_size = *log_size_ptr;
  91. register int log_new_size = log_old_size + 1;
  92. word old_size = ((log_old_size == -1)? 0: (1 << log_old_size));
  93. register word new_size = 1 << log_new_size;
  94. struct hash_chain_entry **new_table = (struct hash_chain_entry **)
  95. GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
  96. (size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
  97. if (new_table == 0) {
  98. if (table == 0) {
  99. ABORT("Insufficient space for initial table allocation");
  100. } else {
  101. return;
  102. }
  103. }
  104. for (i = 0; i < old_size; i++) {
  105. p = (*table)[i];
  106. while (p != 0) {
  107. register ptr_t real_key = (ptr_t)REVEAL_POINTER(p -> hidden_key);
  108. register struct hash_chain_entry *next = p -> next;
  109. register int new_hash = HASH3(real_key, new_size, log_new_size);
  110. p -> next = new_table[new_hash];
  111. new_table[new_hash] = p;
  112. p = next;
  113. }
  114. }
  115. *log_size_ptr = log_new_size;
  116. *table = new_table;
  117. }
  118. # if defined(__STDC__) || defined(__cplusplus)
  119. int GC_register_disappearing_link(GC_PTR * link)
  120. # else
  121. int GC_register_disappearing_link(link)
  122. GC_PTR * link;
  123. # endif
  124. {
  125. ptr_t base;
  126. base = (ptr_t)GC_base((GC_PTR)link);
  127. if (base == 0)
  128. ABORT("Bad arg to GC_register_disappearing_link");
  129. return(GC_general_register_disappearing_link(link, base));
  130. }
  131. # if defined(__STDC__) || defined(__cplusplus)
  132. int GC_general_register_disappearing_link(GC_PTR * link,
  133. GC_PTR obj)
  134. # else
  135. int GC_general_register_disappearing_link(link, obj)
  136. GC_PTR * link;
  137. GC_PTR obj;
  138. # endif
  139. {
  140. struct disappearing_link *curr_dl;
  141. int index;
  142. struct disappearing_link * new_dl;
  143. DCL_LOCK_STATE;
  144. if ((word)link & (ALIGNMENT-1))
  145. ABORT("Bad arg to GC_general_register_disappearing_link");
  146. # ifdef THREADS
  147. DISABLE_SIGNALS();
  148. LOCK();
  149. # endif
  150. if (log_dl_table_size == -1
  151. || GC_dl_entries > ((word)1 << log_dl_table_size)) {
  152. # ifndef THREADS
  153. DISABLE_SIGNALS();
  154. # endif
  155. GC_grow_table((struct hash_chain_entry ***)(&dl_head),
  156. &log_dl_table_size);
  157. # ifdef CONDPRINT
  158. if (GC_print_stats) {
  159. GC_printf1("Grew dl table to %lu entries\n",
  160. (unsigned long)(1 << log_dl_table_size));
  161. }
  162. # endif
  163. # ifndef THREADS
  164. ENABLE_SIGNALS();
  165. # endif
  166. }
  167. index = HASH2(link, log_dl_table_size);
  168. curr_dl = dl_head[index];
  169. for (curr_dl = dl_head[index]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
  170. if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
  171. curr_dl -> dl_hidden_obj = HIDE_POINTER(obj);
  172. # ifdef THREADS
  173. UNLOCK();
  174. ENABLE_SIGNALS();
  175. # endif
  176. return(1);
  177. }
  178. }
  179. new_dl = (struct disappearing_link *)
  180. GC_INTERNAL_MALLOC(sizeof(struct disappearing_link),NORMAL);
  181. if (0 == new_dl) {
  182. # ifdef THREADS
  183. UNLOCK();
  184. ENABLE_SIGNALS();
  185. # endif
  186. new_dl = (struct disappearing_link *)
  187. GC_oom_fn(sizeof(struct disappearing_link));
  188. if (0 == new_dl) {
  189. GC_finalization_failures++;
  190. return(0);
  191. }
  192. /* It's not likely we'll make it here, but ... */
  193. # ifdef THREADS
  194. DISABLE_SIGNALS();
  195. LOCK();
  196. # endif
  197. }
  198. new_dl -> dl_hidden_obj = HIDE_POINTER(obj);
  199. new_dl -> dl_hidden_link = HIDE_POINTER(link);
  200. dl_set_next(new_dl, dl_head[index]);
  201. dl_head[index] = new_dl;
  202. GC_dl_entries++;
  203. # ifdef THREADS
  204. UNLOCK();
  205. ENABLE_SIGNALS();
  206. # endif
  207. return(0);
  208. }
  209. # if defined(__STDC__) || defined(__cplusplus)
  210. int GC_unregister_disappearing_link(GC_PTR * link)
  211. # else
  212. int GC_unregister_disappearing_link(link)
  213. GC_PTR * link;
  214. # endif
  215. {
  216. struct disappearing_link *curr_dl, *prev_dl;
  217. int index;
  218. DCL_LOCK_STATE;
  219. DISABLE_SIGNALS();
  220. LOCK();
  221. index = HASH2(link, log_dl_table_size);
  222. if (((unsigned long)link & (ALIGNMENT-1))) goto out;
  223. prev_dl = 0; curr_dl = dl_head[index];
  224. while (curr_dl != 0) {
  225. if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
  226. if (prev_dl == 0) {
  227. dl_head[index] = dl_next(curr_dl);
  228. } else {
  229. dl_set_next(prev_dl, dl_next(curr_dl));
  230. }
  231. GC_dl_entries--;
  232. UNLOCK();
  233. ENABLE_SIGNALS();
  234. # ifdef DBG_HDRS_ALL
  235. dl_set_next(curr_dl, 0);
  236. # else
  237. GC_free((GC_PTR)curr_dl);
  238. # endif
  239. return(1);
  240. }
  241. prev_dl = curr_dl;
  242. curr_dl = dl_next(curr_dl);
  243. }
  244. out:
  245. UNLOCK();
  246. ENABLE_SIGNALS();
  247. return(0);
  248. }
  249. /* Possible finalization_marker procedures. Note that mark stack */
  250. /* overflow is handled by the caller, and is not a disaster. */
  251. GC_API void GC_normal_finalize_mark_proc(p)
  252. ptr_t p;
  253. {
  254. hdr * hhdr = HDR(p);
  255. PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top,
  256. &(GC_mark_stack[GC_mark_stack_size]));
  257. }
  258. /* This only pays very partial attention to the mark descriptor. */
  259. /* It does the right thing for normal and atomic objects, and treats */
  260. /* most others as normal. */
  261. GC_API void GC_ignore_self_finalize_mark_proc(p)
  262. ptr_t p;
  263. {
  264. hdr * hhdr = HDR(p);
  265. word descr = hhdr -> hb_descr;
  266. ptr_t q, r;
  267. ptr_t scan_limit;
  268. ptr_t target_limit = p + WORDS_TO_BYTES(hhdr -> hb_sz) - 1;
  269. if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) {
  270. scan_limit = p + descr - sizeof(word);
  271. } else {
  272. scan_limit = target_limit + 1 - sizeof(word);
  273. }
  274. for (q = p; q <= scan_limit; q += ALIGNMENT) {
  275. r = *(ptr_t *)q;
  276. if (r < p || r > target_limit) {
  277. GC_PUSH_ONE_HEAP((word)r, q);
  278. }
  279. }
  280. }
  281. /*ARGSUSED*/
  282. GC_API void GC_null_finalize_mark_proc(p)
  283. ptr_t p;
  284. {
  285. }
  286. /* Register a finalization function. See gc.h for details. */
  287. /* in the nonthreads case, we try to avoid disabling signals, */
  288. /* since it can be expensive. Threads packages typically */
  289. /* make it cheaper. */
  290. /* The last parameter is a procedure that determines */
  291. /* marking for finalization ordering. Any objects marked */
  292. /* by that procedure will be guaranteed to not have been */
  293. /* finalized when this finalizer is invoked. */
  294. GC_API void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp)
  295. GC_PTR obj;
  296. GC_finalization_proc fn;
  297. GC_PTR cd;
  298. GC_finalization_proc * ofn;
  299. GC_PTR * ocd;
  300. finalization_mark_proc * mp;
  301. {
  302. ptr_t base;
  303. struct finalizable_object * curr_fo, * prev_fo;
  304. int index;
  305. struct finalizable_object *new_fo;
  306. hdr *hhdr;
  307. DCL_LOCK_STATE;
  308. # ifdef THREADS
  309. DISABLE_SIGNALS();
  310. LOCK();
  311. # endif
  312. if (log_fo_table_size == -1
  313. || GC_fo_entries > ((word)1 << log_fo_table_size)) {
  314. # ifndef THREADS
  315. DISABLE_SIGNALS();
  316. # endif
  317. GC_grow_table((struct hash_chain_entry ***)(&fo_head),
  318. &log_fo_table_size);
  319. # ifdef CONDPRINT
  320. if (GC_print_stats) {
  321. GC_printf1("Grew fo table to %lu entries\n",
  322. (unsigned long)(1 << log_fo_table_size));
  323. }
  324. # endif
  325. # ifndef THREADS
  326. ENABLE_SIGNALS();
  327. # endif
  328. }
  329. /* in the THREADS case signals are disabled and we hold allocation */
  330. /* lock; otherwise neither is true. Proceed carefully. */
  331. base = (ptr_t)obj;
  332. index = HASH2(base, log_fo_table_size);
  333. prev_fo = 0; curr_fo = fo_head[index];
  334. while (curr_fo != 0) {
  335. if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
  336. /* Interruption by a signal in the middle of this */
  337. /* should be safe. The client may see only *ocd */
  338. /* updated, but we'll declare that to be his */
  339. /* problem. */
  340. if (ocd) *ocd = (GC_PTR) curr_fo -> fo_client_data;
  341. if (ofn) *ofn = curr_fo -> fo_fn;
  342. /* Delete the structure for base. */
  343. if (prev_fo == 0) {
  344. fo_head[index] = fo_next(curr_fo);
  345. } else {
  346. fo_set_next(prev_fo, fo_next(curr_fo));
  347. }
  348. if (fn == 0) {
  349. GC_fo_entries--;
  350. /* May not happen if we get a signal. But a high */
  351. /* estimate will only make the table larger than */
  352. /* necessary. */
  353. # if !defined(THREADS) && !defined(DBG_HDRS_ALL)
  354. GC_free((GC_PTR)curr_fo);
  355. # endif
  356. } else {
  357. curr_fo -> fo_fn = fn;
  358. curr_fo -> fo_client_data = (ptr_t)cd;
  359. curr_fo -> fo_mark_proc = mp;
  360. /* Reinsert it. We deleted it first to maintain */
  361. /* consistency in the event of a signal. */
  362. if (prev_fo == 0) {
  363. fo_head[index] = curr_fo;
  364. } else {
  365. fo_set_next(prev_fo, curr_fo);
  366. }
  367. }
  368. # ifdef THREADS
  369. UNLOCK();
  370. ENABLE_SIGNALS();
  371. # endif
  372. return;
  373. }
  374. prev_fo = curr_fo;
  375. curr_fo = fo_next(curr_fo);
  376. }
  377. if (ofn) *ofn = 0;
  378. if (ocd) *ocd = 0;
  379. if (fn == 0) {
  380. # ifdef THREADS
  381. UNLOCK();
  382. ENABLE_SIGNALS();
  383. # endif
  384. return;
  385. }
  386. GET_HDR(base, hhdr);
  387. if (0 == hhdr) {
  388. /* We won't collect it, hence finalizer wouldn't be run. */
  389. # ifdef THREADS
  390. UNLOCK();
  391. ENABLE_SIGNALS();
  392. # endif
  393. return;
  394. }
  395. new_fo = (struct finalizable_object *)
  396. GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL);
  397. if (0 == new_fo) {
  398. # ifdef THREADS
  399. UNLOCK();
  400. ENABLE_SIGNALS();
  401. # endif
  402. new_fo = (struct finalizable_object *)
  403. GC_oom_fn(sizeof(struct finalizable_object));
  404. if (0 == new_fo) {
  405. GC_finalization_failures++;
  406. return;
  407. }
  408. /* It's not likely we'll make it here, but ... */
  409. # ifdef THREADS
  410. DISABLE_SIGNALS();
  411. LOCK();
  412. # endif
  413. }
  414. new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
  415. new_fo -> fo_fn = fn;
  416. new_fo -> fo_client_data = (ptr_t)cd;
  417. new_fo -> fo_object_size = hhdr -> hb_sz;
  418. new_fo -> fo_mark_proc = mp;
  419. fo_set_next(new_fo, fo_head[index]);
  420. GC_fo_entries++;
  421. fo_head[index] = new_fo;
  422. # ifdef THREADS
  423. UNLOCK();
  424. ENABLE_SIGNALS();
  425. # endif
  426. }
  427. # if defined(__STDC__)
  428. void GC_register_finalizer(void * obj,
  429. GC_finalization_proc fn, void * cd,
  430. GC_finalization_proc *ofn, void ** ocd)
  431. # else
  432. void GC_register_finalizer(obj, fn, cd, ofn, ocd)
  433. GC_PTR obj;
  434. GC_finalization_proc fn;
  435. GC_PTR cd;
  436. GC_finalization_proc * ofn;
  437. GC_PTR * ocd;
  438. # endif
  439. {
  440. GC_register_finalizer_inner(obj, fn, cd, ofn,
  441. ocd, GC_normal_finalize_mark_proc);
  442. }
  443. # if defined(__STDC__)
  444. void GC_register_finalizer_ignore_self(void * obj,
  445. GC_finalization_proc fn, void * cd,
  446. GC_finalization_proc *ofn, void ** ocd)
  447. # else
  448. void GC_register_finalizer_ignore_self(obj, fn, cd, ofn, ocd)
  449. GC_PTR obj;
  450. GC_finalization_proc fn;
  451. GC_PTR cd;
  452. GC_finalization_proc * ofn;
  453. GC_PTR * ocd;
  454. # endif
  455. {
  456. GC_register_finalizer_inner(obj, fn, cd, ofn,
  457. ocd, GC_ignore_self_finalize_mark_proc);
  458. }
  459. # if defined(__STDC__)
  460. void GC_register_finalizer_no_order(void * obj,
  461. GC_finalization_proc fn, void * cd,
  462. GC_finalization_proc *ofn, void ** ocd)
  463. # else
  464. void GC_register_finalizer_no_order(obj, fn, cd, ofn, ocd)
  465. GC_PTR obj;
  466. GC_finalization_proc fn;
  467. GC_PTR cd;
  468. GC_finalization_proc * ofn;
  469. GC_PTR * ocd;
  470. # endif
  471. {
  472. GC_register_finalizer_inner(obj, fn, cd, ofn,
  473. ocd, GC_null_finalize_mark_proc);
  474. }
  475. #ifndef NO_DEBUGGING
  476. void GC_dump_finalization()
  477. {
  478. struct disappearing_link * curr_dl;
  479. struct finalizable_object * curr_fo;
  480. ptr_t real_ptr, real_link;
  481. int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
  482. int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
  483. int i;
  484. GC_printf0("Disappearing links:\n");
  485. for (i = 0; i < dl_size; i++) {
  486. for (curr_dl = dl_head[i]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
  487. real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
  488. real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
  489. GC_printf2("Object: 0x%lx, Link:0x%lx\n", real_ptr, real_link);
  490. }
  491. }
  492. GC_printf0("Finalizers:\n");
  493. for (i = 0; i < fo_size; i++) {
  494. for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
  495. real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
  496. GC_printf1("Finalizable object: 0x%lx\n", real_ptr);
  497. }
  498. }
  499. }
  500. #endif
  501. /* Called with world stopped. Cause disappearing links to disappear, */
  502. /* and invoke finalizers. */
  503. void GC_finalize()
  504. {
  505. struct disappearing_link * curr_dl, * prev_dl, * next_dl;
  506. struct finalizable_object * curr_fo, * prev_fo, * next_fo;
  507. ptr_t real_ptr, real_link;
  508. register int i;
  509. int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
  510. int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
  511. /* Make disappearing links disappear */
  512. for (i = 0; i < dl_size; i++) {
  513. curr_dl = dl_head[i];
  514. prev_dl = 0;
  515. while (curr_dl != 0) {
  516. real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
  517. real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
  518. if (!GC_is_marked(real_ptr)) {
  519. *(word *)real_link = 0;
  520. next_dl = dl_next(curr_dl);
  521. if (prev_dl == 0) {
  522. dl_head[i] = next_dl;
  523. } else {
  524. dl_set_next(prev_dl, next_dl);
  525. }
  526. GC_clear_mark_bit((ptr_t)curr_dl);
  527. GC_dl_entries--;
  528. curr_dl = next_dl;
  529. } else {
  530. prev_dl = curr_dl;
  531. curr_dl = dl_next(curr_dl);
  532. }
  533. }
  534. }
  535. /* Mark all objects reachable via chains of 1 or more pointers */
  536. /* from finalizable objects. */
  537. GC_ASSERT(GC_mark_state == MS_NONE);
  538. for (i = 0; i < fo_size; i++) {
  539. for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
  540. real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
  541. if (!GC_is_marked(real_ptr)) {
  542. GC_MARKED_FOR_FINALIZATION(real_ptr);
  543. GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc);
  544. if (GC_is_marked(real_ptr)) {
  545. WARN("Finalization cycle involving %lx\n", real_ptr);
  546. }
  547. }
  548. }
  549. }
  550. /* Enqueue for finalization all objects that are still */
  551. /* unreachable. */
  552. GC_words_finalized = 0;
  553. for (i = 0; i < fo_size; i++) {
  554. curr_fo = fo_head[i];
  555. prev_fo = 0;
  556. while (curr_fo != 0) {
  557. real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
  558. if (!GC_is_marked(real_ptr)) {
  559. if (!GC_java_finalization) {
  560. GC_set_mark_bit(real_ptr);
  561. }
  562. /* Delete from hash table */
  563. next_fo = fo_next(curr_fo);
  564. if (prev_fo == 0) {
  565. fo_head[i] = next_fo;
  566. } else {
  567. fo_set_next(prev_fo, next_fo);
  568. }
  569. GC_fo_entries--;
  570. /* Add to list of objects awaiting finalization. */
  571. fo_set_next(curr_fo, GC_finalize_now);
  572. GC_finalize_now = curr_fo;
  573. /* unhide object pointer so any future collections will */
  574. /* see it. */
  575. curr_fo -> fo_hidden_base =
  576. (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
  577. GC_words_finalized +=
  578. ALIGNED_WORDS(curr_fo -> fo_object_size)
  579. + ALIGNED_WORDS(sizeof(struct finalizable_object));
  580. GC_ASSERT(GC_is_marked(GC_base((ptr_t)curr_fo)));
  581. curr_fo = next_fo;
  582. } else {
  583. prev_fo = curr_fo;
  584. curr_fo = fo_next(curr_fo);
  585. }
  586. }
  587. }
  588. if (GC_java_finalization) {
  589. /* make sure we mark everything reachable from objects finalized
  590. using the no_order mark_proc */
  591. for (curr_fo = GC_finalize_now;
  592. curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
  593. real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
  594. if (!GC_is_marked(real_ptr)) {
  595. if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
  596. GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
  597. }
  598. GC_set_mark_bit(real_ptr);
  599. }
  600. }
  601. }
  602. /* Remove dangling disappearing links. */
  603. for (i = 0; i < dl_size; i++) {
  604. curr_dl = dl_head[i];
  605. prev_dl = 0;
  606. while (curr_dl != 0) {
  607. real_link = GC_base((ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link));
  608. if (real_link != 0 && !GC_is_marked(real_link)) {
  609. next_dl = dl_next(curr_dl);
  610. if (prev_dl == 0) {
  611. dl_head[i] = next_dl;
  612. } else {
  613. dl_set_next(prev_dl, next_dl);
  614. }
  615. GC_clear_mark_bit((ptr_t)curr_dl);
  616. GC_dl_entries--;
  617. curr_dl = next_dl;
  618. } else {
  619. prev_dl = curr_dl;
  620. curr_dl = dl_next(curr_dl);
  621. }
  622. }
  623. }
  624. }
  625. #ifndef JAVA_FINALIZATION_NOT_NEEDED
  626. /* Enqueue all remaining finalizers to be run - Assumes lock is
  627. * held, and signals are disabled */
  628. void GC_enqueue_all_finalizers()
  629. {
  630. struct finalizable_object * curr_fo, * prev_fo, * next_fo;
  631. ptr_t real_ptr;
  632. register int i;
  633. int fo_size;
  634. fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
  635. GC_words_finalized = 0;
  636. for (i = 0; i < fo_size; i++) {
  637. curr_fo = fo_head[i];
  638. prev_fo = 0;
  639. while (curr_fo != 0) {
  640. real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
  641. GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
  642. GC_set_mark_bit(real_ptr);
  643. /* Delete from hash table */
  644. next_fo = fo_next(curr_fo);
  645. if (prev_fo == 0) {
  646. fo_head[i] = next_fo;
  647. } else {
  648. fo_set_next(prev_fo, next_fo);
  649. }
  650. GC_fo_entries--;
  651. /* Add to list of objects awaiting finalization. */
  652. fo_set_next(curr_fo, GC_finalize_now);
  653. GC_finalize_now = curr_fo;
  654. /* unhide object pointer so any future collections will */
  655. /* see it. */
  656. curr_fo -> fo_hidden_base =
  657. (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
  658. GC_words_finalized +=
  659. ALIGNED_WORDS(curr_fo -> fo_object_size)
  660. + ALIGNED_WORDS(sizeof(struct finalizable_object));
  661. curr_fo = next_fo;
  662. }
  663. }
  664. return;
  665. }
  666. /* Invoke all remaining finalizers that haven't yet been run.
  667. * This is needed for strict compliance with the Java standard,
  668. * which can make the runtime guarantee that all finalizers are run.
  669. * Unfortunately, the Java standard implies we have to keep running
  670. * finalizers until there are no more left, a potential infinite loop.
  671. * YUCK.
  672. * Note that this is even more dangerous than the usual Java
  673. * finalizers, in that objects reachable from static variables
  674. * may have been finalized when these finalizers are run.
  675. * Finalizers run at this point must be prepared to deal with a
  676. * mostly broken world.
  677. * This routine is externally callable, so is called without
  678. * the allocation lock.
  679. */
  680. GC_API void GC_finalize_all()
  681. {
  682. DCL_LOCK_STATE;
  683. DISABLE_SIGNALS();
  684. LOCK();
  685. while (GC_fo_entries > 0) {
  686. GC_enqueue_all_finalizers();
  687. UNLOCK();
  688. ENABLE_SIGNALS();
  689. GC_INVOKE_FINALIZERS();
  690. DISABLE_SIGNALS();
  691. LOCK();
  692. }
  693. UNLOCK();
  694. ENABLE_SIGNALS();
  695. }
  696. #endif
  697. /* Returns true if it is worth calling GC_invoke_finalizers. (Useful if */
  698. /* finalizers can only be called from some kind of `safe state' and */
  699. /* getting into that safe state is expensive.) */
  700. int GC_should_invoke_finalizers GC_PROTO((void))
  701. {
  702. return GC_finalize_now != 0;
  703. }
  704. /* Invoke finalizers for all objects that are ready to be finalized. */
  705. /* Should be called without allocation lock. */
  706. int GC_invoke_finalizers()
  707. {
  708. struct finalizable_object * curr_fo;
  709. int count = 0;
  710. word mem_freed_before;
  711. DCL_LOCK_STATE;
  712. while (GC_finalize_now != 0) {
  713. # ifdef THREADS
  714. DISABLE_SIGNALS();
  715. LOCK();
  716. # endif
  717. if (count == 0) {
  718. mem_freed_before = GC_mem_freed;
  719. }
  720. curr_fo = GC_finalize_now;
  721. # ifdef THREADS
  722. if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
  723. UNLOCK();
  724. ENABLE_SIGNALS();
  725. if (curr_fo == 0) break;
  726. # else
  727. GC_finalize_now = fo_next(curr_fo);
  728. # endif
  729. fo_set_next(curr_fo, 0);
  730. (*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
  731. curr_fo -> fo_client_data);
  732. curr_fo -> fo_client_data = 0;
  733. ++count;
  734. # ifdef UNDEFINED
  735. /* This is probably a bad idea. It throws off accounting if */
  736. /* nearly all objects are finalizable. O.w. it shouldn't */
  737. /* matter. */
  738. GC_free((GC_PTR)curr_fo);
  739. # endif
  740. }
  741. if (count != 0 && mem_freed_before != GC_mem_freed) {
  742. LOCK();
  743. GC_finalizer_mem_freed += (GC_mem_freed - mem_freed_before);
  744. UNLOCK();
  745. }
  746. return count;
  747. }
  748. void (* GC_finalizer_notifier)() = (void (*) GC_PROTO((void)))0;
  749. static GC_word last_finalizer_notification = 0;
  750. #ifdef KEEP_BACK_PTRS
  751. void GC_generate_random_backtrace_no_gc(void);
  752. #endif
  753. void GC_notify_or_invoke_finalizers GC_PROTO((void))
  754. {
  755. /* This is a convenient place to generate backtraces if appropriate, */
  756. /* since that code is not callable with the allocation lock. */
  757. # ifdef KEEP_BACK_PTRS
  758. if (GC_backtraces > 0) {
  759. static word last_back_trace_gc_no = 3; /* Skip early ones. */
  760. long i;
  761. LOCK();
  762. if (GC_gc_no > last_back_trace_gc_no) {
  763. /* Stops when GC_gc_no wraps; that's OK. */
  764. last_back_trace_gc_no = (word)(-1); /* disable others. */
  765. for (i = 0; i < GC_backtraces; ++i) {
  766. /* FIXME: This tolerates concurrent heap mutation, */
  767. /* which may cause occasional mysterious results. */
  768. /* We need to release the GC lock, since GC_print_callers */
  769. /* acquires it. It probably shouldn't. */
  770. UNLOCK();
  771. GC_generate_random_backtrace_no_gc();
  772. LOCK();
  773. }
  774. last_back_trace_gc_no = GC_gc_no;
  775. }
  776. UNLOCK();
  777. }
  778. # endif
  779. if (GC_finalize_now == 0) return;
  780. if (!GC_finalize_on_demand) {
  781. (void) GC_invoke_finalizers();
  782. # ifndef THREADS
  783. GC_ASSERT(GC_finalize_now == 0);
  784. # endif /* Otherwise GC can run concurrently and add more */
  785. return;
  786. }
  787. if (GC_finalizer_notifier != (void (*) GC_PROTO((void)))0
  788. && last_finalizer_notification != GC_gc_no) {
  789. last_finalizer_notification = GC_gc_no;
  790. GC_finalizer_notifier();
  791. }
  792. }
  793. # ifdef __STDC__
  794. GC_PTR GC_call_with_alloc_lock(GC_fn_type fn,
  795. GC_PTR client_data)
  796. # else
  797. GC_PTR GC_call_with_alloc_lock(fn, client_data)
  798. GC_fn_type fn;
  799. GC_PTR client_data;
  800. # endif
  801. {
  802. GC_PTR result;
  803. DCL_LOCK_STATE;
  804. # ifdef THREADS
  805. DISABLE_SIGNALS();
  806. LOCK();
  807. SET_LOCK_HOLDER();
  808. # endif
  809. result = (*fn)(client_data);
  810. # ifdef THREADS
  811. # ifndef GC_ASSERTIONS
  812. UNSET_LOCK_HOLDER();
  813. # endif /* o.w. UNLOCK() does it implicitly */
  814. UNLOCK();
  815. ENABLE_SIGNALS();
  816. # endif
  817. return(result);
  818. }
  819. #if !defined(NO_DEBUGGING)
  820. void GC_print_finalization_stats()
  821. {
  822. struct finalizable_object *fo = GC_finalize_now;
  823. size_t ready = 0;
  824. GC_printf2("%lu finalization table entries; %lu disappearing links\n",
  825. GC_fo_entries, GC_dl_entries);
  826. for (; 0 != fo; fo = fo_next(fo)) ++ready;
  827. GC_printf1("%lu objects are eligible for immediate finalization\n", ready);
  828. }
  829. #endif /* NO_DEBUGGING */