aboutsummaryrefslogtreecommitdiffstats
path: root/src/alloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/alloc.c')
-rw-r--r--src/alloc.c213
1 files changed, 186 insertions, 27 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 9aa94b8a559..1f4b1a4694e 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -441,6 +441,15 @@ mmap_lisp_allowed_p (void)
441 return pointers_fit_in_lispobj_p () && !might_dump; 441 return pointers_fit_in_lispobj_p () && !might_dump;
442} 442}
443 443
444/* Head of a circularly-linked list of extant finalizers. */
445static struct Lisp_Finalizer finalizers;
446
447/* Head of a circularly-linked list of finalizers that must be invoked
448 because we deemed them unreachable. This list must be global, and
449 not a local inside garbage_collect_1, in case we GC again while
450 running finalizers. */
451static struct Lisp_Finalizer doomed_finalizers;
452
444 453
445/************************************************************************ 454/************************************************************************
446 Malloc 455 Malloc
@@ -3414,7 +3423,7 @@ union aligned_Lisp_Misc
3414}; 3423};
3415 3424
3416/* Allocation of markers and other objects that share that structure. 3425/* Allocation of markers and other objects that share that structure.
3417 Works like allocation of conses. */ 3426 Works like allocation of conses. */
3418 3427
3419#define MARKER_BLOCK_SIZE \ 3428#define MARKER_BLOCK_SIZE \
3420 ((1020 - sizeof (struct marker_block *)) / sizeof (union aligned_Lisp_Misc)) 3429 ((1020 - sizeof (struct marker_block *)) / sizeof (union aligned_Lisp_Misc))
@@ -3695,6 +3704,128 @@ make_event_array (ptrdiff_t nargs, Lisp_Object *args)
3695 } 3704 }
3696} 3705}
3697 3706
3707static void
3708init_finalizer_list (struct Lisp_Finalizer *head)
3709{
3710 head->prev = head->next = head;
3711}
3712
3713/* Insert FINALIZER before ELEMENT. */
3714
3715static void
3716finalizer_insert (struct Lisp_Finalizer *element,
3717 struct Lisp_Finalizer *finalizer)
3718{
3719 eassert (finalizer->prev == NULL);
3720 eassert (finalizer->next == NULL);
3721 finalizer->next = element;
3722 finalizer->prev = element->prev;
3723 finalizer->prev->next = finalizer;
3724 element->prev = finalizer;
3725}
3726
3727static void
3728unchain_finalizer (struct Lisp_Finalizer *finalizer)
3729{
3730 if (finalizer->prev != NULL)
3731 {
3732 eassert (finalizer->next != NULL);
3733 finalizer->prev->next = finalizer->next;
3734 finalizer->next->prev = finalizer->prev;
3735 finalizer->prev = finalizer->next = NULL;
3736 }
3737}
3738
3739static void
3740mark_finalizer_list (struct Lisp_Finalizer *head)
3741{
3742 for (struct Lisp_Finalizer *finalizer = head->next;
3743 finalizer != head;
3744 finalizer = finalizer->next)
3745 {
3746 finalizer->base.gcmarkbit = true;
3747 mark_object (finalizer->function);
3748 }
3749}
3750
3751/* Move doomed finalizers to list DEST from list SRC. A doomed
3752 finalizer is one that is not GC-reachable and whose
3753 finalizer->function is non-nil. */
3754
3755static void
3756queue_doomed_finalizers (struct Lisp_Finalizer *dest,
3757 struct Lisp_Finalizer *src)
3758{
3759 struct Lisp_Finalizer *finalizer = src->next;
3760 while (finalizer != src)
3761 {
3762 struct Lisp_Finalizer *next = finalizer->next;
3763 if (!finalizer->base.gcmarkbit && !NILP (finalizer->function))
3764 {
3765 unchain_finalizer (finalizer);
3766 finalizer_insert (dest, finalizer);
3767 }
3768
3769 finalizer = next;
3770 }
3771}
3772
3773static Lisp_Object
3774run_finalizer_handler (Lisp_Object args)
3775{
3776 add_to_log ("finalizer failed: %S", args, Qnil);
3777 return Qnil;
3778}
3779
3780static void
3781run_finalizer_function (Lisp_Object function)
3782{
3783 struct gcpro gcpro1;
3784 ptrdiff_t count = SPECPDL_INDEX ();
3785
3786 GCPRO1 (function);
3787 specbind (Qinhibit_quit, Qt);
3788 internal_condition_case_1 (call0, function, Qt, run_finalizer_handler);
3789 unbind_to (count, Qnil);
3790 UNGCPRO;
3791}
3792
3793static void
3794run_finalizers (struct Lisp_Finalizer *finalizers)
3795{
3796 struct Lisp_Finalizer *finalizer;
3797 Lisp_Object function;
3798
3799 while (finalizers->next != finalizers)
3800 {
3801 finalizer = finalizers->next;
3802 eassert (finalizer->base.type == Lisp_Misc_Finalizer);
3803 unchain_finalizer (finalizer);
3804 function = finalizer->function;
3805 if (!NILP (function))
3806 {
3807 finalizer->function = Qnil;
3808 run_finalizer_function (function);
3809 }
3810 }
3811}
3812
3813DEFUN ("make-finalizer", Fmake_finalizer, Smake_finalizer, 1, 1, 0,
3814 doc: /* Make a finalizer that will run FUNCTION.
3815FUNCTION will be called after garbage collection when the returned
3816finalizer object becomes unreachable. If the finalizer object is
3817reachable only through references from finalizer objects, it does not
3818count as reachable for the purpose of deciding whether to run
3819FUNCTION. FUNCTION will be run once per finalizer object. */)
3820 (Lisp_Object function)
3821{
3822 Lisp_Object val = allocate_misc (Lisp_Misc_Finalizer);
3823 struct Lisp_Finalizer *finalizer = XFINALIZER (val);
3824 finalizer->function = function;
3825 finalizer->prev = finalizer->next = NULL;
3826 finalizer_insert (&finalizers, finalizer);
3827 return val;
3828}
3698 3829
3699 3830
3700/************************************************************************ 3831/************************************************************************
@@ -4613,7 +4744,7 @@ mark_maybe_pointer (void *p)
4613#endif 4744#endif
4614 4745
4615/* Mark Lisp objects referenced from the address range START+OFFSET..END 4746/* Mark Lisp objects referenced from the address range START+OFFSET..END
4616 or END+OFFSET..START. */ 4747 or END+OFFSET..START. */
4617 4748
4618static void ATTRIBUTE_NO_SANITIZE_ADDRESS 4749static void ATTRIBUTE_NO_SANITIZE_ADDRESS
4619mark_memory (void *start, void *end) 4750mark_memory (void *start, void *end)
@@ -5225,7 +5356,6 @@ make_pure_vector (ptrdiff_t len)
5225 return new; 5356 return new;
5226} 5357}
5227 5358
5228
5229DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0, 5359DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0,
5230 doc: /* Make a copy of object OBJ in pure storage. 5360 doc: /* Make a copy of object OBJ in pure storage.
5231Recursively copies contents of vectors and cons cells. 5361Recursively copies contents of vectors and cons cells.
@@ -5260,28 +5390,26 @@ purecopy (Lisp_Object obj)
5260 else if (FLOATP (obj)) 5390 else if (FLOATP (obj))
5261 obj = make_pure_float (XFLOAT_DATA (obj)); 5391 obj = make_pure_float (XFLOAT_DATA (obj));
5262 else if (STRINGP (obj)) 5392 else if (STRINGP (obj))
5263 obj = make_pure_string (SSDATA (obj), SCHARS (obj),
5264 SBYTES (obj),
5265 STRING_MULTIBYTE (obj));
5266 else if (COMPILEDP (obj) || VECTORP (obj))
5267 { 5393 {
5268 register struct Lisp_Vector *vec; 5394 if (XSTRING (obj)->intervals)
5395 message ("Dropping text-properties when making string pure");
5396 obj = make_pure_string (SSDATA (obj), SCHARS (obj),
5397 SBYTES (obj),
5398 STRING_MULTIBYTE (obj));
5399 }
5400 else if (COMPILEDP (obj) || VECTORP (obj) || HASH_TABLE_P (obj))
5401 {
5402 struct Lisp_Vector *objp = XVECTOR (obj);
5403 ptrdiff_t nbytes = vector_nbytes (objp);
5404 struct Lisp_Vector *vec = pure_alloc (nbytes, Lisp_Vectorlike);
5269 register ptrdiff_t i; 5405 register ptrdiff_t i;
5270 ptrdiff_t size; 5406 ptrdiff_t size = ASIZE (obj);
5271
5272 size = ASIZE (obj);
5273 if (size & PSEUDOVECTOR_FLAG) 5407 if (size & PSEUDOVECTOR_FLAG)
5274 size &= PSEUDOVECTOR_SIZE_MASK; 5408 size &= PSEUDOVECTOR_SIZE_MASK;
5275 vec = XVECTOR (make_pure_vector (size)); 5409 memcpy (vec, objp, nbytes);
5276 for (i = 0; i < size; i++) 5410 for (i = 0; i < size; i++)
5277 vec->contents[i] = purecopy (AREF (obj, i)); 5411 vec->contents[i] = purecopy (vec->contents[i]);
5278 if (COMPILEDP (obj)) 5412 XSETVECTOR (obj, vec);
5279 {
5280 XSETPVECTYPE (vec, PVEC_COMPILED);
5281 XSETCOMPILED (obj, vec);
5282 }
5283 else
5284 XSETVECTOR (obj, vec);
5285 } 5413 }
5286 else if (SYMBOLP (obj)) 5414 else if (SYMBOLP (obj))
5287 { 5415 {
@@ -5291,6 +5419,7 @@ purecopy (Lisp_Object obj)
5291 XSYMBOL (obj)->pinned = true; 5419 XSYMBOL (obj)->pinned = true;
5292 symbol_block_pinned = symbol_block; 5420 symbol_block_pinned = symbol_block;
5293 } 5421 }
5422 /* Don't hash-cons it. */
5294 return obj; 5423 return obj;
5295 } 5424 }
5296 else 5425 else
@@ -5613,9 +5742,9 @@ garbage_collect_1 (void *end)
5613 mark_stack (end); 5742 mark_stack (end);
5614#endif 5743#endif
5615 5744
5616 /* Everything is now marked, except for the data in font caches 5745 /* Everything is now marked, except for the data in font caches,
5617 and undo lists. They're compacted by removing an items which 5746 undo lists, and finalizers. The first two are compacted by
5618 aren't reachable otherwise. */ 5747 removing an items which aren't reachable otherwise. */
5619 5748
5620 compact_font_caches (); 5749 compact_font_caches ();
5621 5750
@@ -5628,6 +5757,16 @@ garbage_collect_1 (void *end)
5628 mark_object (BVAR (nextb, undo_list)); 5757 mark_object (BVAR (nextb, undo_list));
5629 } 5758 }
5630 5759
5760 /* Now pre-sweep finalizers. Here, we add any unmarked finalizers
5761 to doomed_finalizers so we can run their associated functions
5762 after GC. It's important to scan finalizers at this stage so
5763 that we can be sure that unmarked finalizers are really
5764 unreachable except for references from their associated functions
5765 and from other finalizers. */
5766
5767 queue_doomed_finalizers (&doomed_finalizers, &finalizers);
5768 mark_finalizer_list (&doomed_finalizers);
5769
5631 gc_sweep (); 5770 gc_sweep ();
5632 5771
5633 /* Clear the mark bits that we set in certain root slots. */ 5772 /* Clear the mark bits that we set in certain root slots. */
@@ -5728,6 +5867,9 @@ garbage_collect_1 (void *end)
5728 } 5867 }
5729#endif 5868#endif
5730 5869
5870 /* GC is complete: now we can run our finalizer callbacks. */
5871 run_finalizers (&doomed_finalizers);
5872
5731 if (!NILP (Vpost_gc_hook)) 5873 if (!NILP (Vpost_gc_hook))
5732 { 5874 {
5733 ptrdiff_t gc_count = inhibit_garbage_collection (); 5875 ptrdiff_t gc_count = inhibit_garbage_collection ();
@@ -6085,13 +6227,14 @@ mark_discard_killed_buffers (Lisp_Object list)
6085void 6227void
6086mark_object (Lisp_Object arg) 6228mark_object (Lisp_Object arg)
6087{ 6229{
6088 register Lisp_Object obj = arg; 6230 register Lisp_Object obj;
6089 void *po; 6231 void *po;
6090#ifdef GC_CHECK_MARKED_OBJECTS 6232#ifdef GC_CHECK_MARKED_OBJECTS
6091 struct mem_node *m; 6233 struct mem_node *m;
6092#endif 6234#endif
6093 ptrdiff_t cdr_count = 0; 6235 ptrdiff_t cdr_count = 0;
6094 6236
6237 obj = arg;
6095 loop: 6238 loop:
6096 6239
6097 po = XPNTR (obj); 6240 po = XPNTR (obj);
@@ -6364,7 +6507,12 @@ mark_object (Lisp_Object arg)
6364 6507
6365 case Lisp_Misc_Overlay: 6508 case Lisp_Misc_Overlay:
6366 mark_overlay (XOVERLAY (obj)); 6509 mark_overlay (XOVERLAY (obj));
6367 break; 6510 break;
6511
6512 case Lisp_Misc_Finalizer:
6513 XMISCANY (obj)->gcmarkbit = true;
6514 mark_object (XFINALIZER (obj)->function);
6515 break;
6368 6516
6369 default: 6517 default:
6370 emacs_abort (); 6518 emacs_abort ();
@@ -6721,7 +6869,7 @@ sweep_symbols (void)
6721 total_free_symbols = num_free; 6869 total_free_symbols = num_free;
6722} 6870}
6723 6871
6724NO_INLINE /* For better stack traces */ 6872NO_INLINE /* For better stack traces. */
6725static void 6873static void
6726sweep_misc (void) 6874sweep_misc (void)
6727{ 6875{
@@ -6746,6 +6894,8 @@ sweep_misc (void)
6746 { 6894 {
6747 if (mblk->markers[i].m.u_any.type == Lisp_Misc_Marker) 6895 if (mblk->markers[i].m.u_any.type == Lisp_Misc_Marker)
6748 unchain_marker (&mblk->markers[i].m.u_marker); 6896 unchain_marker (&mblk->markers[i].m.u_marker);
6897 if (mblk->markers[i].m.u_any.type == Lisp_Misc_Finalizer)
6898 unchain_finalizer (&mblk->markers[i].m.u_finalizer);
6749 /* Set the type of the freed object to Lisp_Misc_Free. 6899 /* Set the type of the freed object to Lisp_Misc_Free.
6750 We could leave the type alone, since nobody checks it, 6900 We could leave the type alone, since nobody checks it,
6751 but this might catch bugs faster. */ 6901 but this might catch bugs faster. */
@@ -7115,11 +7265,14 @@ init_alloc_once (void)
7115{ 7265{
7116 /* Even though Qt's contents are not set up, its address is known. */ 7266 /* Even though Qt's contents are not set up, its address is known. */
7117 Vpurify_flag = Qt; 7267 Vpurify_flag = Qt;
7268 gc_precise = (GC_MARK_STACK == GC_USE_GCPROS_AS_BEFORE);
7118 7269
7119 purebeg = PUREBEG; 7270 purebeg = PUREBEG;
7120 pure_size = PURESIZE; 7271 pure_size = PURESIZE;
7121 7272
7122 verify_alloca (); 7273 verify_alloca ();
7274 init_finalizer_list (&finalizers);
7275 init_finalizer_list (&doomed_finalizers);
7123 7276
7124#if GC_MARK_STACK || defined GC_MALLOC_CHECK 7277#if GC_MARK_STACK || defined GC_MALLOC_CHECK
7125 mem_init (); 7278 mem_init ();
@@ -7254,7 +7407,12 @@ do hash-consing of the objects allocated to pure space. */);
7254 doc: /* Accumulated time elapsed in garbage collections. 7407 doc: /* Accumulated time elapsed in garbage collections.
7255The time is in seconds as a floating point value. */); 7408The time is in seconds as a floating point value. */);
7256 DEFVAR_INT ("gcs-done", gcs_done, 7409 DEFVAR_INT ("gcs-done", gcs_done,
7257 doc: /* Accumulated number of garbage collections done. */); 7410 doc: /* Accumulated number of garbage collections done. */);
7411
7412 DEFVAR_BOOL ("gc-precise", gc_precise,
7413 doc: /* Non-nil means GC stack marking is precise.
7414Useful mainly for automated GC tests. Build time constant.*/);
7415 XSYMBOL (intern_c_string ("gc-precise"))->constant = 1;
7258 7416
7259 defsubr (&Scons); 7417 defsubr (&Scons);
7260 defsubr (&Slist); 7418 defsubr (&Slist);
@@ -7267,6 +7425,7 @@ The time is in seconds as a floating point value. */);
7267 defsubr (&Smake_bool_vector); 7425 defsubr (&Smake_bool_vector);
7268 defsubr (&Smake_symbol); 7426 defsubr (&Smake_symbol);
7269 defsubr (&Smake_marker); 7427 defsubr (&Smake_marker);
7428 defsubr (&Smake_finalizer);
7270 defsubr (&Spurecopy); 7429 defsubr (&Spurecopy);
7271 defsubr (&Sgarbage_collect); 7430 defsubr (&Sgarbage_collect);
7272 defsubr (&Smemory_limit); 7431 defsubr (&Smemory_limit);