diff options
| author | Daniel Colascione | 2015-03-02 02:23:09 -0800 |
|---|---|---|
| committer | Daniel Colascione | 2015-03-02 15:39:01 -0800 |
| commit | 9d8d0658147dfe5a90e2fb07ff666f35b1162d6e (patch) | |
| tree | 6d593ab42386348b1842688c75f892db45c5b59e /src | |
| parent | b149ecd8aa3aa9c179dd5496f64e1f50750414fa (diff) | |
| download | emacs-9d8d0658147dfe5a90e2fb07ff666f35b1162d6e.tar.gz emacs-9d8d0658147dfe5a90e2fb07ff666f35b1162d6e.zip | |
Add support for finalizers
+2015-03-02 Daniel Colascione <dancol@dancol.org>
+
+ * NEWS: Mention finalizers.
+
2015-02-09 Gareth Rees <gdr@garethrees.org> (tiny change)
* NEWS.24: Fix typo (bug#19820)
diff --git a/src/ChangeLog b/src/ChangeLog
index 4aa64c1..2f04d0b 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,21 @@
+2015-03-02 Daniel Colascione <dancol@dancol.org>
+
+ * print.c (print_object): Print finalizers.
+
+ * alloc.c:
+ (finalizers, doomed_finalizers): New variables.
+ (init_finalizer_list, finalizer_insert, unchain_finalizer)
+ (mark_finalizer_list, queue_doomed_finalizers)
+ (run_finalizer_handler, run_finalizer_function, run_finalizers):
+ New functions.
+ (garbage_collect_1, mark_object, sweep_misc)
+ (init_alloc_once, syms_of_alloc): Support finalizers.
+ (gc-precise-p): New Lisp variable.
+
+ * lisp.h (Lisp_Misc_Type): New value Lisp_Misc_Finalizer.
+ (FINALIZERP, XFINALIZER): New functions.
+ (Lisp_Finalizer): New structure.
+
2015-02-28 Paul Eggert <eggert@cs.ucla.edu>
* character.c (alphabeticp, decimalnump): Avoid undefined behavior
diff --git a/test/ChangeLog b/test/ChangeLog
index cf1b2c1..684e98f 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,9 @@
+2015-03-02 Daniel Colascione <dancol@dancol.org>
+
+ * automated/finalizer-tests.el (finalizer-basic)
+ (finalizer-circular-reference, finalizer-cross-reference)
+ (finalizer-error): New tests.
+
2015-03-01 Michael Albinus <michael.albinus@gmx.de>
* automated/vc-tests.el (vc-test--create-repo): Add check for
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 18 | ||||
| -rw-r--r-- | src/alloc.c | 172 | ||||
| -rw-r--r-- | src/lisp.h | 33 | ||||
| -rw-r--r-- | src/print.c | 6 |
4 files changed, 223 insertions, 6 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 4aa64c1d6f9..2f04d0b040a 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,21 @@ | |||
| 1 | 2015-03-02 Daniel Colascione <dancol@dancol.org> | ||
| 2 | |||
| 3 | * print.c (print_object): Print finalizers. | ||
| 4 | |||
| 5 | * alloc.c: | ||
| 6 | (finalizers, doomed_finalizers): New variables. | ||
| 7 | (init_finalizer_list, finalizer_insert, unchain_finalizer) | ||
| 8 | (mark_finalizer_list, queue_doomed_finalizers) | ||
| 9 | (run_finalizer_handler, run_finalizer_function, run_finalizers): | ||
| 10 | New functions. | ||
| 11 | (garbage_collect_1, mark_object, sweep_misc) | ||
| 12 | (init_alloc_once, syms_of_alloc): Support finalizers. | ||
| 13 | (gc-precise-p): New Lisp variable. | ||
| 14 | |||
| 15 | * lisp.h (Lisp_Misc_Type): New value Lisp_Misc_Finalizer. | ||
| 16 | (FINALIZERP, XFINALIZER): New functions. | ||
| 17 | (Lisp_Finalizer): New structure. | ||
| 18 | |||
| 1 | 2015-02-28 Paul Eggert <eggert@cs.ucla.edu> | 19 | 2015-02-28 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 20 | ||
| 3 | * character.c (alphabeticp, decimalnump): Avoid undefined behavior | 21 | * character.c (alphabeticp, decimalnump): Avoid undefined behavior |
diff --git a/src/alloc.c b/src/alloc.c index 9aa94b8a559..eec53e7d844 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. */ | ||
| 445 | static 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. */ | ||
| 451 | static struct Lisp_Finalizer doomed_finalizers; | ||
| 452 | |||
| 444 | 453 | ||
| 445 | /************************************************************************ | 454 | /************************************************************************ |
| 446 | Malloc | 455 | Malloc |
| @@ -3695,6 +3704,131 @@ make_event_array (ptrdiff_t nargs, Lisp_Object *args) | |||
| 3695 | } | 3704 | } |
| 3696 | } | 3705 | } |
| 3697 | 3706 | ||
| 3707 | static void | ||
| 3708 | init_finalizer_list (struct Lisp_Finalizer *head) | ||
| 3709 | { | ||
| 3710 | head->prev = head->next = head; | ||
| 3711 | } | ||
| 3712 | |||
| 3713 | /* Insert FINALIZER before ELEMENT. */ | ||
| 3714 | |||
| 3715 | static void | ||
| 3716 | finalizer_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 | |||
| 3727 | static void | ||
| 3728 | unchain_finalizer (struct Lisp_Finalizer *finalizer) | ||
| 3729 | { | ||
| 3730 | if (finalizer->prev != NULL) { | ||
| 3731 | eassert (finalizer->next != NULL); | ||
| 3732 | finalizer->prev->next = finalizer->next; | ||
| 3733 | finalizer->next->prev = finalizer->prev; | ||
| 3734 | finalizer->prev = finalizer->next = NULL; | ||
| 3735 | } | ||
| 3736 | } | ||
| 3737 | |||
| 3738 | static void | ||
| 3739 | mark_finalizer_list (struct Lisp_Finalizer *head) | ||
| 3740 | { | ||
| 3741 | for (struct Lisp_Finalizer *finalizer = head->next; | ||
| 3742 | finalizer != head; | ||
| 3743 | finalizer = finalizer->next) | ||
| 3744 | { | ||
| 3745 | finalizer->base.gcmarkbit = 1; | ||
| 3746 | mark_object (finalizer->function); | ||
| 3747 | } | ||
| 3748 | } | ||
| 3749 | |||
| 3750 | /* Move doomed finalizers in list SRC onto list DEST. A doomed | ||
| 3751 | finalizer is one that is not GC-reachable and whose | ||
| 3752 | finalizer->function is non-nil. (We reset finalizer->function to | ||
| 3753 | before attempting to run it.) */ | ||
| 3754 | |||
| 3755 | static void | ||
| 3756 | queue_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 | |||
| 3773 | static Lisp_Object | ||
| 3774 | run_finalizer_handler (Lisp_Object args) | ||
| 3775 | { | ||
| 3776 | add_to_log ("finalizer failed: %S", args, Qnil); | ||
| 3777 | return Qnil; | ||
| 3778 | } | ||
| 3779 | |||
| 3780 | static void | ||
| 3781 | run_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 | |||
| 3793 | static void | ||
| 3794 | run_finalizers (struct Lisp_Finalizer* finalizers) | ||
| 3795 | { | ||
| 3796 | struct Lisp_Finalizer* finalizer; | ||
| 3797 | Lisp_Object function; | ||
| 3798 | struct gcpro gcpro1; | ||
| 3799 | |||
| 3800 | while (finalizers->next != finalizers) { | ||
| 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 | |||
| 3813 | DEFUN ("make-finalizer", Fmake_finalizer, Smake_finalizer, 1, 1, 0, | ||
| 3814 | doc: /* Make a finalizer that will run FUNCTION. | ||
| 3815 | FUNCTION will be called after garbage collection when the returned | ||
| 3816 | finalizer object becomes unreachable. If the finalizer object is | ||
| 3817 | reachable only through references from finalizer objects, it does not | ||
| 3818 | count as reachable for the purpose of deciding whether to run | ||
| 3819 | FUNCTION. FUNCTION will be run once per finalizer object. */) | ||
| 3820 | (Lisp_Object function) | ||
| 3821 | { | ||
| 3822 | Lisp_Object val; | ||
| 3823 | struct Lisp_Finalizer *finalizer; | ||
| 3824 | |||
| 3825 | val = allocate_misc (Lisp_Misc_Finalizer); | ||
| 3826 | finalizer = XFINALIZER (val); | ||
| 3827 | finalizer->function = function; | ||
| 3828 | finalizer->prev = finalizer->next = NULL; | ||
| 3829 | finalizer_insert (&finalizers, finalizer); | ||
| 3830 | return val; | ||
| 3831 | } | ||
| 3698 | 3832 | ||
| 3699 | 3833 | ||
| 3700 | /************************************************************************ | 3834 | /************************************************************************ |
| @@ -5613,9 +5747,9 @@ garbage_collect_1 (void *end) | |||
| 5613 | mark_stack (end); | 5747 | mark_stack (end); |
| 5614 | #endif | 5748 | #endif |
| 5615 | 5749 | ||
| 5616 | /* Everything is now marked, except for the data in font caches | 5750 | /* Everything is now marked, except for the data in font caches, |
| 5617 | and undo lists. They're compacted by removing an items which | 5751 | undo lists, and finalizers. The first two are compacted by |
| 5618 | aren't reachable otherwise. */ | 5752 | removing an items which aren't reachable otherwise. */ |
| 5619 | 5753 | ||
| 5620 | compact_font_caches (); | 5754 | compact_font_caches (); |
| 5621 | 5755 | ||
| @@ -5628,6 +5762,16 @@ garbage_collect_1 (void *end) | |||
| 5628 | mark_object (BVAR (nextb, undo_list)); | 5762 | mark_object (BVAR (nextb, undo_list)); |
| 5629 | } | 5763 | } |
| 5630 | 5764 | ||
| 5765 | /* Now pre-sweep finalizers. Here, we add any unmarked finalizers | ||
| 5766 | to doomed_finalizers so we can run their associated functions | ||
| 5767 | after GC. It's important to scan finalizers at this stage so | ||
| 5768 | that we can be sure that unmarked finalizers are really | ||
| 5769 | unreachable except for references from their associated functions | ||
| 5770 | and from other finalizers. */ | ||
| 5771 | |||
| 5772 | queue_doomed_finalizers (&doomed_finalizers, &finalizers); | ||
| 5773 | mark_finalizer_list (&doomed_finalizers); | ||
| 5774 | |||
| 5631 | gc_sweep (); | 5775 | gc_sweep (); |
| 5632 | 5776 | ||
| 5633 | /* Clear the mark bits that we set in certain root slots. */ | 5777 | /* Clear the mark bits that we set in certain root slots. */ |
| @@ -5728,6 +5872,9 @@ garbage_collect_1 (void *end) | |||
| 5728 | } | 5872 | } |
| 5729 | #endif | 5873 | #endif |
| 5730 | 5874 | ||
| 5875 | /* GC is complete: now we can run our finalizer callbacks. */ | ||
| 5876 | run_finalizers (&doomed_finalizers); | ||
| 5877 | |||
| 5731 | if (!NILP (Vpost_gc_hook)) | 5878 | if (!NILP (Vpost_gc_hook)) |
| 5732 | { | 5879 | { |
| 5733 | ptrdiff_t gc_count = inhibit_garbage_collection (); | 5880 | ptrdiff_t gc_count = inhibit_garbage_collection (); |
| @@ -6364,7 +6511,12 @@ mark_object (Lisp_Object arg) | |||
| 6364 | 6511 | ||
| 6365 | case Lisp_Misc_Overlay: | 6512 | case Lisp_Misc_Overlay: |
| 6366 | mark_overlay (XOVERLAY (obj)); | 6513 | mark_overlay (XOVERLAY (obj)); |
| 6367 | break; | 6514 | break; |
| 6515 | |||
| 6516 | case Lisp_Misc_Finalizer: | ||
| 6517 | XMISCANY (obj)->gcmarkbit = 1; | ||
| 6518 | mark_object (XFINALIZER (obj)->function); | ||
| 6519 | break; | ||
| 6368 | 6520 | ||
| 6369 | default: | 6521 | default: |
| 6370 | emacs_abort (); | 6522 | emacs_abort (); |
| @@ -6746,6 +6898,8 @@ sweep_misc (void) | |||
| 6746 | { | 6898 | { |
| 6747 | if (mblk->markers[i].m.u_any.type == Lisp_Misc_Marker) | 6899 | if (mblk->markers[i].m.u_any.type == Lisp_Misc_Marker) |
| 6748 | unchain_marker (&mblk->markers[i].m.u_marker); | 6900 | unchain_marker (&mblk->markers[i].m.u_marker); |
| 6901 | if (mblk->markers[i].m.u_any.type == Lisp_Misc_Finalizer) | ||
| 6902 | unchain_finalizer (&mblk->markers[i].m.u_finalizer); | ||
| 6749 | /* Set the type of the freed object to Lisp_Misc_Free. | 6903 | /* Set the type of the freed object to Lisp_Misc_Free. |
| 6750 | We could leave the type alone, since nobody checks it, | 6904 | We could leave the type alone, since nobody checks it, |
| 6751 | but this might catch bugs faster. */ | 6905 | but this might catch bugs faster. */ |
| @@ -7115,11 +7269,14 @@ init_alloc_once (void) | |||
| 7115 | { | 7269 | { |
| 7116 | /* Even though Qt's contents are not set up, its address is known. */ | 7270 | /* Even though Qt's contents are not set up, its address is known. */ |
| 7117 | Vpurify_flag = Qt; | 7271 | Vpurify_flag = Qt; |
| 7272 | gc_precise_p = (GC_MARK_STACK == GC_USE_GCPROS_AS_BEFORE); | ||
| 7118 | 7273 | ||
| 7119 | purebeg = PUREBEG; | 7274 | purebeg = PUREBEG; |
| 7120 | pure_size = PURESIZE; | 7275 | pure_size = PURESIZE; |
| 7121 | 7276 | ||
| 7122 | verify_alloca (); | 7277 | verify_alloca (); |
| 7278 | init_finalizer_list (&finalizers); | ||
| 7279 | init_finalizer_list (&doomed_finalizers); | ||
| 7123 | 7280 | ||
| 7124 | #if GC_MARK_STACK || defined GC_MALLOC_CHECK | 7281 | #if GC_MARK_STACK || defined GC_MALLOC_CHECK |
| 7125 | mem_init (); | 7282 | mem_init (); |
| @@ -7254,7 +7411,11 @@ do hash-consing of the objects allocated to pure space. */); | |||
| 7254 | doc: /* Accumulated time elapsed in garbage collections. | 7411 | doc: /* Accumulated time elapsed in garbage collections. |
| 7255 | The time is in seconds as a floating point value. */); | 7412 | The time is in seconds as a floating point value. */); |
| 7256 | DEFVAR_INT ("gcs-done", gcs_done, | 7413 | DEFVAR_INT ("gcs-done", gcs_done, |
| 7257 | doc: /* Accumulated number of garbage collections done. */); | 7414 | doc: /* Accumulated number of garbage collections done. */); |
| 7415 | |||
| 7416 | DEFVAR_BOOL ("gc-precise-p", gc_precise_p, | ||
| 7417 | doc: /* Non-nil means GC stack marking is precise. | ||
| 7418 | Useful mainly for automated GC tests. Build time constant.*/); | ||
| 7258 | 7419 | ||
| 7259 | defsubr (&Scons); | 7420 | defsubr (&Scons); |
| 7260 | defsubr (&Slist); | 7421 | defsubr (&Slist); |
| @@ -7267,6 +7428,7 @@ The time is in seconds as a floating point value. */); | |||
| 7267 | defsubr (&Smake_bool_vector); | 7428 | defsubr (&Smake_bool_vector); |
| 7268 | defsubr (&Smake_symbol); | 7429 | defsubr (&Smake_symbol); |
| 7269 | defsubr (&Smake_marker); | 7430 | defsubr (&Smake_marker); |
| 7431 | defsubr (&Smake_finalizer); | ||
| 7270 | defsubr (&Spurecopy); | 7432 | defsubr (&Spurecopy); |
| 7271 | defsubr (&Sgarbage_collect); | 7433 | defsubr (&Sgarbage_collect); |
| 7272 | defsubr (&Smemory_limit); | 7434 | defsubr (&Smemory_limit); |
diff --git a/src/lisp.h b/src/lisp.h index fb436776121..37f3b28242b 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -488,6 +488,7 @@ enum Lisp_Misc_Type | |||
| 488 | Lisp_Misc_Marker, | 488 | Lisp_Misc_Marker, |
| 489 | Lisp_Misc_Overlay, | 489 | Lisp_Misc_Overlay, |
| 490 | Lisp_Misc_Save_Value, | 490 | Lisp_Misc_Save_Value, |
| 491 | Lisp_Misc_Finalizer, | ||
| 491 | /* Currently floats are not a misc type, | 492 | /* Currently floats are not a misc type, |
| 492 | but let's define this in case we want to change that. */ | 493 | but let's define this in case we want to change that. */ |
| 493 | Lisp_Misc_Float, | 494 | Lisp_Misc_Float, |
| @@ -600,6 +601,7 @@ INLINE bool OVERLAYP (Lisp_Object); | |||
| 600 | INLINE bool PROCESSP (Lisp_Object); | 601 | INLINE bool PROCESSP (Lisp_Object); |
| 601 | INLINE bool PSEUDOVECTORP (Lisp_Object, int); | 602 | INLINE bool PSEUDOVECTORP (Lisp_Object, int); |
| 602 | INLINE bool SAVE_VALUEP (Lisp_Object); | 603 | INLINE bool SAVE_VALUEP (Lisp_Object); |
| 604 | INLINE bool FINALIZERP (Lisp_Object); | ||
| 603 | INLINE void set_sub_char_table_contents (Lisp_Object, ptrdiff_t, | 605 | INLINE void set_sub_char_table_contents (Lisp_Object, ptrdiff_t, |
| 604 | Lisp_Object); | 606 | Lisp_Object); |
| 605 | INLINE bool STRINGP (Lisp_Object); | 607 | INLINE bool STRINGP (Lisp_Object); |
| @@ -610,6 +612,7 @@ INLINE bool (VECTORLIKEP) (Lisp_Object); | |||
| 610 | INLINE bool WINDOWP (Lisp_Object); | 612 | INLINE bool WINDOWP (Lisp_Object); |
| 611 | INLINE bool TERMINALP (Lisp_Object); | 613 | INLINE bool TERMINALP (Lisp_Object); |
| 612 | INLINE struct Lisp_Save_Value *XSAVE_VALUE (Lisp_Object); | 614 | INLINE struct Lisp_Save_Value *XSAVE_VALUE (Lisp_Object); |
| 615 | INLINE struct Lisp_Finalizer *XFINALIZER (Lisp_Object); | ||
| 613 | INLINE struct Lisp_Symbol *(XSYMBOL) (Lisp_Object); | 616 | INLINE struct Lisp_Symbol *(XSYMBOL) (Lisp_Object); |
| 614 | INLINE void *(XUNTAG) (Lisp_Object, int); | 617 | INLINE void *(XUNTAG) (Lisp_Object, int); |
| 615 | 618 | ||
| @@ -2183,6 +2186,21 @@ XSAVE_OBJECT (Lisp_Object obj, int n) | |||
| 2183 | return XSAVE_VALUE (obj)->data[n].object; | 2186 | return XSAVE_VALUE (obj)->data[n].object; |
| 2184 | } | 2187 | } |
| 2185 | 2188 | ||
| 2189 | /* A finalizer sentinel. We run FUNCTION when this value becomes | ||
| 2190 | unreachable. We treat these values specially in the GC to ensure | ||
| 2191 | that we still run the finalizer even if FUNCTION contains a | ||
| 2192 | reference to the finalizer; i.e., we run a finalizer's function | ||
| 2193 | when FUNCTION is reachable _only_ through finalizers. */ | ||
| 2194 | struct Lisp_Finalizer | ||
| 2195 | { | ||
| 2196 | struct Lisp_Misc_Any base; | ||
| 2197 | /* Circular list of all active weak references */ | ||
| 2198 | struct Lisp_Finalizer *prev; | ||
| 2199 | struct Lisp_Finalizer *next; | ||
| 2200 | /* Called when this object becomes unreachable */ | ||
| 2201 | Lisp_Object function; | ||
| 2202 | }; | ||
| 2203 | |||
| 2186 | /* A miscellaneous object, when it's on the free list. */ | 2204 | /* A miscellaneous object, when it's on the free list. */ |
| 2187 | struct Lisp_Free | 2205 | struct Lisp_Free |
| 2188 | { | 2206 | { |
| @@ -2202,6 +2220,7 @@ union Lisp_Misc | |||
| 2202 | struct Lisp_Marker u_marker; | 2220 | struct Lisp_Marker u_marker; |
| 2203 | struct Lisp_Overlay u_overlay; | 2221 | struct Lisp_Overlay u_overlay; |
| 2204 | struct Lisp_Save_Value u_save_value; | 2222 | struct Lisp_Save_Value u_save_value; |
| 2223 | struct Lisp_Finalizer u_finalizer; | ||
| 2205 | }; | 2224 | }; |
| 2206 | 2225 | ||
| 2207 | INLINE union Lisp_Misc * | 2226 | INLINE union Lisp_Misc * |
| @@ -2243,6 +2262,14 @@ XSAVE_VALUE (Lisp_Object a) | |||
| 2243 | eassert (SAVE_VALUEP (a)); | 2262 | eassert (SAVE_VALUEP (a)); |
| 2244 | return & XMISC (a)->u_save_value; | 2263 | return & XMISC (a)->u_save_value; |
| 2245 | } | 2264 | } |
| 2265 | |||
| 2266 | INLINE struct Lisp_Finalizer * | ||
| 2267 | XFINALIZER (Lisp_Object a) | ||
| 2268 | { | ||
| 2269 | eassert (FINALIZERP (a)); | ||
| 2270 | return & XMISC (a)->u_finalizer; | ||
| 2271 | } | ||
| 2272 | |||
| 2246 | 2273 | ||
| 2247 | /* Forwarding pointer to an int variable. | 2274 | /* Forwarding pointer to an int variable. |
| 2248 | This is allowed only in the value cell of a symbol, | 2275 | This is allowed only in the value cell of a symbol, |
| @@ -2490,6 +2517,12 @@ SAVE_VALUEP (Lisp_Object x) | |||
| 2490 | } | 2517 | } |
| 2491 | 2518 | ||
| 2492 | INLINE bool | 2519 | INLINE bool |
| 2520 | FINALIZERP (Lisp_Object x) | ||
| 2521 | { | ||
| 2522 | return MISCP (x) && XMISCTYPE (x) == Lisp_Misc_Finalizer; | ||
| 2523 | } | ||
| 2524 | |||
| 2525 | INLINE bool | ||
| 2493 | AUTOLOADP (Lisp_Object x) | 2526 | AUTOLOADP (Lisp_Object x) |
| 2494 | { | 2527 | { |
| 2495 | return CONSP (x) && EQ (Qautoload, XCAR (x)); | 2528 | return CONSP (x) && EQ (Qautoload, XCAR (x)); |
diff --git a/src/print.c b/src/print.c index 1a0aebbeba7..d391fd5f7a3 100644 --- a/src/print.c +++ b/src/print.c | |||
| @@ -2043,7 +2043,11 @@ print_object (Lisp_Object obj, Lisp_Object printcharfun, bool escapeflag) | |||
| 2043 | printcharfun); | 2043 | printcharfun); |
| 2044 | } | 2044 | } |
| 2045 | PRINTCHAR ('>'); | 2045 | PRINTCHAR ('>'); |
| 2046 | break; | 2046 | break; |
| 2047 | |||
| 2048 | case Lisp_Misc_Finalizer: | ||
| 2049 | strout ("#<finalizer>", -1, -1, printcharfun); | ||
| 2050 | break; | ||
| 2047 | 2051 | ||
| 2048 | /* Remaining cases shouldn't happen in normal usage, but let's | 2052 | /* Remaining cases shouldn't happen in normal usage, but let's |
| 2049 | print them anyway for the benefit of the debugger. */ | 2053 | print them anyway for the benefit of the debugger. */ |