Mercurial > emacs
comparison src/alloc.c @ 55816:a4fe04f4d9c2
Undo Kim's recent changes and fix the same bug differently.
(marker_blocks_pending_free): Remove.
(Fgarbage_collect): Sweep after cleaning up undo-lists.
Mark the undo lists after claning them up.
Don't free block in marker_blocks_pending_free.
(mark_buffer): Don't mark undo_list.
(gc_sweep): Sweep hash-tables and strings first.
Do free marker blocks that are empty.
| author | Stefan Monnier <monnier@iro.umontreal.ca> |
|---|---|
| date | Sat, 29 May 2004 00:00:17 +0000 |
| parents | a1bb695e9a0c |
| children | a05a653f63af 62cf3d6337a0 |
comparison
equal
deleted
inserted
replaced
| 55815:a6b86fce5676 | 55816:a4fe04f4d9c2 |
|---|---|
| 2864 struct marker_block *marker_block; | 2864 struct marker_block *marker_block; |
| 2865 int marker_block_index; | 2865 int marker_block_index; |
| 2866 | 2866 |
| 2867 union Lisp_Misc *marker_free_list; | 2867 union Lisp_Misc *marker_free_list; |
| 2868 | 2868 |
| 2869 /* Marker blocks which should be freed at end of GC. */ | |
| 2870 | |
| 2871 struct marker_block *marker_blocks_pending_free; | |
| 2872 | |
| 2873 /* Total number of marker blocks now in use. */ | 2869 /* Total number of marker blocks now in use. */ |
| 2874 | 2870 |
| 2875 int n_marker_blocks; | 2871 int n_marker_blocks; |
| 2876 | 2872 |
| 2877 void | 2873 void |
| 2878 init_marker () | 2874 init_marker () |
| 2879 { | 2875 { |
| 2880 marker_block = NULL; | 2876 marker_block = NULL; |
| 2881 marker_block_index = MARKER_BLOCK_SIZE; | 2877 marker_block_index = MARKER_BLOCK_SIZE; |
| 2882 marker_free_list = 0; | 2878 marker_free_list = 0; |
| 2883 marker_blocks_pending_free = 0; | |
| 2884 n_marker_blocks = 0; | 2879 n_marker_blocks = 0; |
| 2885 } | 2880 } |
| 2886 | 2881 |
| 2887 /* Return a newly allocated Lisp_Misc object, with no substructure. */ | 2882 /* Return a newly allocated Lisp_Misc object, with no substructure. */ |
| 2888 | 2883 |
| 4457 extern void xg_mark_data (); | 4452 extern void xg_mark_data (); |
| 4458 xg_mark_data (); | 4453 xg_mark_data (); |
| 4459 } | 4454 } |
| 4460 #endif | 4455 #endif |
| 4461 | 4456 |
| 4462 gc_sweep (); | 4457 /* Everything is now marked, except for the things that require special |
| 4463 | 4458 finalization, i.e. the undo_list. |
| 4464 /* Look thru every buffer's undo list for elements that used to | 4459 Look thru every buffer's undo list |
| 4465 contain update markers that were changed to Lisp_Misc_Free | 4460 for elements that update markers that were not marked, |
| 4466 objects and delete them. This may leave a few cons cells | 4461 and delete them. */ |
| 4467 unchained, but we will get those on the next sweep. */ | |
| 4468 { | 4462 { |
| 4469 register struct buffer *nextb = all_buffers; | 4463 register struct buffer *nextb = all_buffers; |
| 4470 | 4464 |
| 4471 while (nextb) | 4465 while (nextb) |
| 4472 { | 4466 { |
| 4473 /* If a buffer's undo list is Qt, that means that undo is | 4467 /* If a buffer's undo list is Qt, that means that undo is |
| 4474 turned off in that buffer. */ | 4468 turned off in that buffer. Calling truncate_undo_list on |
| 4469 Qt tends to return NULL, which effectively turns undo back on. | |
| 4470 So don't call truncate_undo_list if undo_list is Qt. */ | |
| 4475 if (! EQ (nextb->undo_list, Qt)) | 4471 if (! EQ (nextb->undo_list, Qt)) |
| 4476 { | 4472 { |
| 4477 Lisp_Object tail, prev, elt, car; | 4473 Lisp_Object tail, prev; |
| 4478 tail = nextb->undo_list; | 4474 tail = nextb->undo_list; |
| 4479 prev = Qnil; | 4475 prev = Qnil; |
| 4480 while (CONSP (tail)) | 4476 while (CONSP (tail)) |
| 4481 { | 4477 { |
| 4482 if ((elt = XCAR (tail), GC_CONSP (elt)) | 4478 if (GC_CONSP (XCAR (tail)) |
| 4483 && (car = XCAR (elt), GC_MISCP (car)) | 4479 && GC_MARKERP (XCAR (XCAR (tail))) |
| 4484 && XMISCTYPE (car) == Lisp_Misc_Free) | 4480 && !XMARKER (XCAR (XCAR (tail)))->gcmarkbit) |
| 4485 { | 4481 { |
| 4486 Lisp_Object cdr = XCDR (tail); | |
| 4487 /* Do not use free_cons here, as we don't know if | |
| 4488 anybody else has a pointer to these conses. */ | |
| 4489 XSETCAR (elt, Qnil); | |
| 4490 XSETCDR (elt, Qnil); | |
| 4491 XSETCAR (tail, Qnil); | |
| 4492 XSETCDR (tail, Qnil); | |
| 4493 if (NILP (prev)) | 4482 if (NILP (prev)) |
| 4494 nextb->undo_list = tail = cdr; | 4483 nextb->undo_list = tail = XCDR (tail); |
| 4495 else | 4484 else |
| 4496 { | 4485 { |
| 4497 tail = cdr; | 4486 tail = XCDR (tail); |
| 4498 XSETCDR (prev, tail); | 4487 XSETCDR (prev, tail); |
| 4499 } | 4488 } |
| 4500 } | 4489 } |
| 4501 else | 4490 else |
| 4502 { | 4491 { |
| 4503 prev = tail; | 4492 prev = tail; |
| 4504 tail = XCDR (tail); | 4493 tail = XCDR (tail); |
| 4505 } | 4494 } |
| 4506 } | 4495 } |
| 4507 } | 4496 } |
| 4497 /* Now that we have stripped the elements that need not be in the | |
| 4498 undo_list any more, we can finally mark the list. */ | |
| 4499 mark_object (nextb->undo_list); | |
| 4508 | 4500 |
| 4509 nextb = nextb->next; | 4501 nextb = nextb->next; |
| 4510 } | 4502 } |
| 4511 } | 4503 } |
| 4512 | 4504 |
| 4513 /* Undo lists have been cleaned up, so we can free marker blocks now. */ | 4505 gc_sweep (); |
| 4514 | |
| 4515 { | |
| 4516 struct marker_block *mblk; | |
| 4517 | |
| 4518 while ((mblk = marker_blocks_pending_free) != 0) | |
| 4519 { | |
| 4520 marker_blocks_pending_free = mblk->next; | |
| 4521 lisp_free (mblk); | |
| 4522 } | |
| 4523 } | |
| 4524 | 4506 |
| 4525 /* Clear the mark bits that we set in certain root slots. */ | 4507 /* Clear the mark bits that we set in certain root slots. */ |
| 4526 | 4508 |
| 4527 unmark_byte_stack (); | 4509 unmark_byte_stack (); |
| 4528 VECTOR_UNMARK (&buffer_defaults); | 4510 VECTOR_UNMARK (&buffer_defaults); |
| 5086 | 5068 |
| 5087 VECTOR_MARK (buffer); | 5069 VECTOR_MARK (buffer); |
| 5088 | 5070 |
| 5089 MARK_INTERVAL_TREE (BUF_INTERVALS (buffer)); | 5071 MARK_INTERVAL_TREE (BUF_INTERVALS (buffer)); |
| 5090 | 5072 |
| 5091 if (CONSP (buffer->undo_list)) | 5073 /* For now, we just don't mark the undo_list. It's done later in |
| 5092 { | 5074 a special way just before the sweep phase, and after stripping |
| 5093 Lisp_Object tail; | 5075 some of its elements that are not needed any more. */ |
| 5094 tail = buffer->undo_list; | |
| 5095 | |
| 5096 /* We mark the undo list specially because | |
| 5097 its pointers to markers should be weak. */ | |
| 5098 | |
| 5099 while (CONSP (tail)) | |
| 5100 { | |
| 5101 register struct Lisp_Cons *ptr = XCONS (tail); | |
| 5102 | |
| 5103 if (CONS_MARKED_P (ptr)) | |
| 5104 break; | |
| 5105 CONS_MARK (ptr); | |
| 5106 if (GC_CONSP (ptr->car) | |
| 5107 && !CONS_MARKED_P (XCONS (ptr->car)) | |
| 5108 && GC_MARKERP (XCAR (ptr->car))) | |
| 5109 { | |
| 5110 CONS_MARK (XCONS (ptr->car)); | |
| 5111 mark_object (XCDR (ptr->car)); | |
| 5112 } | |
| 5113 else | |
| 5114 mark_object (ptr->car); | |
| 5115 | |
| 5116 if (CONSP (ptr->cdr)) | |
| 5117 tail = ptr->cdr; | |
| 5118 else | |
| 5119 break; | |
| 5120 } | |
| 5121 | |
| 5122 mark_object (XCDR (tail)); | |
| 5123 } | |
| 5124 else | |
| 5125 mark_object (buffer->undo_list); | |
| 5126 | 5076 |
| 5127 if (buffer->overlays_before) | 5077 if (buffer->overlays_before) |
| 5128 { | 5078 { |
| 5129 XSETMISC (tmp, buffer->overlays_before); | 5079 XSETMISC (tmp, buffer->overlays_before); |
| 5130 mark_object (tmp); | 5080 mark_object (tmp); |
| 5200 /* Sweep: find all structures not marked, and free them. */ | 5150 /* Sweep: find all structures not marked, and free them. */ |
| 5201 | 5151 |
| 5202 static void | 5152 static void |
| 5203 gc_sweep () | 5153 gc_sweep () |
| 5204 { | 5154 { |
| 5155 /* Remove or mark entries in weak hash tables. | |
| 5156 This must be done before any object is unmarked. */ | |
| 5157 sweep_weak_hash_tables (); | |
| 5158 | |
| 5159 sweep_strings (); | |
| 5160 #ifdef GC_CHECK_STRING_BYTES | |
| 5161 if (!noninteractive) | |
| 5162 check_string_bytes (1); | |
| 5163 #endif | |
| 5164 | |
| 5205 /* Put all unmarked conses on free list */ | 5165 /* Put all unmarked conses on free list */ |
| 5206 { | 5166 { |
| 5207 register struct cons_block *cblk; | 5167 register struct cons_block *cblk; |
| 5208 struct cons_block **cprev = &cons_block; | 5168 struct cons_block **cprev = &cons_block; |
| 5209 register int lim = cons_block_index; | 5169 register int lim = cons_block_index; |
| 5249 } | 5209 } |
| 5250 } | 5210 } |
| 5251 total_conses = num_used; | 5211 total_conses = num_used; |
| 5252 total_free_conses = num_free; | 5212 total_free_conses = num_free; |
| 5253 } | 5213 } |
| 5254 | |
| 5255 /* Remove or mark entries in weak hash tables. | |
| 5256 This must be done before any object is unmarked. */ | |
| 5257 sweep_weak_hash_tables (); | |
| 5258 | |
| 5259 sweep_strings (); | |
| 5260 #ifdef GC_CHECK_STRING_BYTES | |
| 5261 if (!noninteractive) | |
| 5262 check_string_bytes (1); | |
| 5263 #endif | |
| 5264 | 5214 |
| 5265 /* Put all unmarked floats on free list */ | 5215 /* Put all unmarked floats on free list */ |
| 5266 { | 5216 { |
| 5267 register struct float_block *fblk; | 5217 register struct float_block *fblk; |
| 5268 struct float_block **fprev = &float_block; | 5218 struct float_block **fprev = &float_block; |
| 5428 struct marker_block **mprev = &marker_block; | 5378 struct marker_block **mprev = &marker_block; |
| 5429 register int lim = marker_block_index; | 5379 register int lim = marker_block_index; |
| 5430 register int num_free = 0, num_used = 0; | 5380 register int num_free = 0, num_used = 0; |
| 5431 | 5381 |
| 5432 marker_free_list = 0; | 5382 marker_free_list = 0; |
| 5433 marker_blocks_pending_free = 0; | |
| 5434 | 5383 |
| 5435 for (mblk = marker_block; mblk; mblk = *mprev) | 5384 for (mblk = marker_block; mblk; mblk = *mprev) |
| 5436 { | 5385 { |
| 5437 register int i; | 5386 register int i; |
| 5438 int this_free = 0; | 5387 int this_free = 0; |
| 5464 if (this_free == MARKER_BLOCK_SIZE && num_free > MARKER_BLOCK_SIZE) | 5413 if (this_free == MARKER_BLOCK_SIZE && num_free > MARKER_BLOCK_SIZE) |
| 5465 { | 5414 { |
| 5466 *mprev = mblk->next; | 5415 *mprev = mblk->next; |
| 5467 /* Unhook from the free list. */ | 5416 /* Unhook from the free list. */ |
| 5468 marker_free_list = mblk->markers[0].u_free.chain; | 5417 marker_free_list = mblk->markers[0].u_free.chain; |
| 5418 lisp_free (mblk); | |
| 5469 n_marker_blocks--; | 5419 n_marker_blocks--; |
| 5470 | |
| 5471 /* It is not safe to free the marker block at this stage, | |
| 5472 since there may still be pointers to these markers from | |
| 5473 a buffer's undo list. KFS 2004-05-25. */ | |
| 5474 mblk->next = marker_blocks_pending_free; | |
| 5475 marker_blocks_pending_free = mblk; | |
| 5476 } | 5420 } |
| 5477 else | 5421 else |
| 5478 { | 5422 { |
| 5479 num_free += this_free; | 5423 num_free += this_free; |
| 5480 mprev = &mblk->next; | 5424 mprev = &mblk->next; |
