* MPS prstack
@ 2024-05-20 17:54 Helmut Eller
2024-05-20 18:21 ` Gerd Möllmann
2024-05-22 16:27 ` Helmut Eller
0 siblings, 2 replies; 22+ messages in thread
From: Helmut Eller @ 2024-05-20 17:54 UTC (permalink / raw)
To: Gerd Möllmann; +Cc: Eli Zaretskii, Emacs Devel
[-- Attachment #1: Type: text/plain, Size: 748 bytes --]
In print.c, there is a global variable prstack that is not yet scanned.
This causes a crash for comp-tests but this example triggers the same
problem:
(progn
(defun make-tree (i)
(cond ((= i 0) nil)
(t (list (make-string 10000 i)
(make-tree (1- i)) (make-tree (1- i))))))
(prin1-to-string (make-tree 13)))
We could create an ambiguous root for this but I thought it would be an
interesting exercise to scan it exactly. It's interesting because this is
a static variable and the type is only declared in print.c. So I added
a new function igc_xpalloc_exact to igc.h. That uses a callback that
calls another callback. I'm not sure if this allowed by the MPS rules
but it seems to work or at least doesn't seem to crash.
WDYT?
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Add-a-igc_xpalloc_exact-function.patch --]
[-- Type: text/x-diff, Size: 5208 bytes --]
From 925a4b0daeef769e6048b068a7c35674000797db Mon Sep 17 00:00:00 2001
From: Helmut Eller <eller.helmut@gmail.com>
Date: Mon, 20 May 2024 17:44:34 +0200
Subject: [PATCH 1/2] Add a igc_xpalloc_exact function
* src/igc.h (igc_xpalloc_exact): New.
(igc_scan_result_t, igc_opaque, igc_scan_cell_t, igc_scan_area_t): New
auxilarry types.
* src/igc.c (igc_xpalloc_exact): Implement it.
(scan_xpalloced, scan_cell_callback): New helpers.
(root_create): Allow a closure argument.
(root_create_ambig, root_create_exact, root_create_igc)
(root_create_pure): Set the closure argument to NULL.
---
src/igc.c | 58 ++++++++++++++++++++++++++++++++++++++++++++++++-------
src/igc.h | 18 +++++++++++++++--
2 files changed, 67 insertions(+), 9 deletions(-)
diff --git a/src/igc.c b/src/igc.c
index 5e0e2e8fdd2..e2e9af97f94 100644
--- a/src/igc.c
+++ b/src/igc.c
@@ -2001,15 +2001,28 @@ fix_vector (mps_ss_t ss, struct Lisp_Vector *v)
return MPS_RES_OK;
}
+static igc_scan_result_t
+scan_cell_callback (struct igc_opaque *op, Lisp_Object *addr)
+{
+ mps_ss_t ss = (mps_ss_t)op;
+ MPS_SCAN_BEGIN (ss)
+ {
+ IGC_FIX12_OBJ (ss, addr);
+ }
+ MPS_SCAN_END (ss);
+ return MPS_RES_OK;
+}
+
#pragma GCC diagnostic pop
static igc_root_list *
root_create (struct igc *gc, void *start, void *end, mps_rank_t rank,
- mps_area_scan_t scan, bool ambig)
+ mps_area_scan_t scan, void *closure, bool ambig)
{
mps_root_t root;
mps_res_t res
- = mps_root_create_area (&root, gc->arena, rank, 0, start, end, scan, 0);
+ = mps_root_create_area (&root, gc->arena, rank, 0, start, end, scan,
+ closure);
IGC_CHECK_RES (res);
return register_root (gc, root, start, end, ambig);
}
@@ -2017,13 +2030,15 @@ root_create (struct igc *gc, void *start, void *end, mps_rank_t rank,
static igc_root_list *
root_create_ambig (struct igc *gc, void *start, void *end)
{
- return root_create (gc, start, end, mps_rank_ambig (), scan_ambig, true);
+ return root_create (gc, start, end, mps_rank_ambig (), scan_ambig, NULL,
+ true);
}
static igc_root_list *
-root_create_exact (struct igc *gc, void *start, void *end, mps_area_scan_t scan)
+root_create_exact (struct igc *gc, void *start, void *end,
+ mps_area_scan_t scan)
{
- return root_create (gc, start, end, mps_rank_exact (), scan, false);
+ return root_create (gc, start, end, mps_rank_exact (), scan, NULL, false);
}
static void
@@ -2115,7 +2130,7 @@ root_create_bc (struct igc_thread_list *t)
static void
root_create_igc (struct igc *gc)
{
- root_create (gc, gc, gc + 1, mps_rank_exact (), scan_igc, false);
+ root_create (gc, gc, gc + 1, mps_rank_exact (), scan_igc, NULL, false);
}
#ifndef IN_MY_FORK
@@ -2124,7 +2139,7 @@ root_create_pure (struct igc *gc)
{
void *start = &pure[0];
void *end = &pure[PURESIZE];
- root_create (gc, start, end, mps_rank_ambig (), scan_pure, true);
+ root_create (gc, start, end, mps_rank_ambig (), scan_pure, NULL, true);
}
#endif
@@ -2355,6 +2370,35 @@ igc_xpalloc_ambig (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min,
return pa;
}
+static mps_res_t
+scan_xpalloced (mps_ss_t ss, void *start, void *end, void *closure)
+{
+ igc_scan_area_t scan_area = closure;
+ igc_scan_cell_t scan_cell = (igc_scan_cell_t)scan_cell_callback;
+ return scan_area ((struct igc_opaque *)ss, start, end, scan_cell);
+}
+
+void *
+igc_xpalloc_exact (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min,
+ ptrdiff_t nitems_max, ptrdiff_t item_size,
+ igc_scan_area_t scan_area)
+{
+ IGC_WITH_PARKED (global_igc)
+ {
+ if (pa)
+ {
+ struct igc_root_list *r = root_find (pa);
+ igc_assert (r != NULL);
+ destroy_root (&r);
+ }
+ pa = xpalloc (pa, nitems, nitems_incr_min, nitems_max, item_size);
+ char *end = (char *)pa + *nitems * item_size;
+ root_create (global_igc, pa, end, mps_rank_exact (),
+ scan_xpalloced, scan_area, false);
+ }
+ return pa;
+}
+
void *
igc_xnrealloc_ambig (void *pa, ptrdiff_t nitems, ptrdiff_t item_size)
{
diff --git a/src/igc.h b/src/igc.h
index 2fe134bc2d7..384d5acdf1b 100644
--- a/src/igc.h
+++ b/src/igc.h
@@ -72,8 +72,22 @@ #define EMACS_IGC_H
void *igc_realloc_ambig (void *block, size_t size);
void igc_xfree (void *p);
Lisp_Object *igc_xalloc_lisp_objs_exact (size_t n);
-void *igc_xpalloc_ambig (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min,
- ptrdiff_t nitems_max, ptrdiff_t item_size);
+
+void *igc_xpalloc_ambig (void *pa, ptrdiff_t *nitems,
+ ptrdiff_t nitems_incr_min, ptrdiff_t nitems_max,
+ ptrdiff_t item_size);
+
+typedef uintptr_t igc_scan_result_t; /* zero means success */
+struct igc_opaque;
+typedef igc_scan_result_t (*igc_scan_cell_t) (struct igc_opaque *,
+ Lisp_Object *addr);
+typedef igc_scan_result_t (*igc_scan_area_t) (struct igc_opaque *,
+ void *start, void *end,
+ igc_scan_cell_t fun);
+void *igc_xpalloc_exact (void *pa, ptrdiff_t *nitems,
+ ptrdiff_t nitems_incr_min, ptrdiff_t nitems_max,
+ ptrdiff_t item_size, igc_scan_area_t scan);
+
void *igc_xnrealloc_ambig (void *pa, ptrdiff_t nitems, ptrdiff_t item_size);
struct Lisp_Vector *igc_alloc_pseudovector (size_t nwords_mem,
--
2.39.2
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Allocate-prstack-as-exact-root.patch --]
[-- Type: text/x-diff, Size: 1862 bytes --]
From 928270d0f7ad2200fb3b5a6f126fd43c7740bbe3 Mon Sep 17 00:00:00 2001
From: Helmut Eller <eller.helmut@gmail.com>
Date: Mon, 20 May 2024 17:49:29 +0200
Subject: [PATCH 2/2] Allocate prstack as exact root
* src/print.c (grow_print_stack): Use igc_xpalloc_exact.
(scan_prstack): New.
---
src/print.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/src/print.c b/src/print.c
index 440c1c0e575..f043da92c1f 100644
--- a/src/print.c
+++ b/src/print.c
@@ -2200,12 +2200,52 @@ named_escape (int i)
static struct print_stack prstack = {NULL, 0, 0};
+static igc_scan_result_t
+scan_prstack (struct igc_opaque *op, void *start, void *end,
+ igc_scan_cell_t scan1)
+{
+ eassert (start == (void *)prstack.stack);
+ eassert (end == (void *)(prstack.stack + prstack.size));
+ struct print_stack_entry *p = start;
+ struct print_stack_entry *q = p + prstack.sp;
+ for (; p < q; p++)
+ {
+ igc_scan_result_t err = 0;
+ switch (p->type)
+ {
+ case PE_list:
+ if (err = scan1 (op, &p->u.list.last), err != 0)
+ return err;
+ if (err = scan1 (op, &p->u.list.tortoise), err != 0)
+ return err;
+ continue;
+ case PE_rbrac:
+ continue;
+ case PE_vector:
+ if (err = scan1 (op, &p->u.vector.obj), err != 0)
+ return err;
+ continue;
+ case PE_hash:
+ if (err = scan1 (op, &p->u.hash.obj), err != 0)
+ return err;
+ continue;
+ }
+ eassert (!"not yet implemented");
+ }
+ return 0;
+}
+
NO_INLINE static void
grow_print_stack (void)
{
struct print_stack *ps = &prstack;
eassert (ps->sp == ps->size);
+#ifdef HAVE_MPS
+ ps->stack = igc_xpalloc_exact (ps->stack, &ps->size, 1, -1,
+ sizeof *ps->stack, scan_prstack);
+#else
ps->stack = xpalloc (ps->stack, &ps->size, 1, -1, sizeof *ps->stack);
+#endif
eassert (ps->sp < ps->size);
}
--
2.39.2
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-20 17:54 MPS prstack Helmut Eller
@ 2024-05-20 18:21 ` Gerd Möllmann
2024-05-20 18:32 ` Helmut Eller
2024-05-22 16:27 ` Helmut Eller
1 sibling, 1 reply; 22+ messages in thread
From: Gerd Möllmann @ 2024-05-20 18:21 UTC (permalink / raw)
To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel
Helmut Eller <eller.helmut@gmail.com> writes:
> In print.c, there is a global variable prstack that is not yet scanned.
> This causes a crash for comp-tests but this example triggers the same
> problem:
>
> (progn
> (defun make-tree (i)
> (cond ((= i 0) nil)
> (t (list (make-string 10000 i)
> (make-tree (1- i)) (make-tree (1- i))))))
> (prin1-to-string (make-tree 13)))
>
> We could create an ambiguous root for this but I thought it would be an
> interesting exercise to scan it exactly. It's interesting because this is
> a static variable and the type is only declared in print.c. So I added
> a new function igc_xpalloc_exact to igc.h. That uses a callback that
> calls another callback. I'm not sure if this allowed by the MPS rules
> but it seems to work or at least doesn't seem to crash.
>
> WDYT?
LGTM and pushed. Thanks!
AFAICT, taking the reference literally, it is permissible to pass the
mps_ss_t around. It merely says this
type mps_ss_t
The type of scan states.
A scan state represents the state of the current scan. The MPS passes
a scan state to the scan method of an object format when it needs to
scan for references within a region of memory. The scan method must
pass the scan state to MPS_SCAN_BEGIN and MPS_SCAN_END to delimit a
sequence of fix operations, and to the functions MPS_FIX1(),
MPS_FIX2() and MPS_FIX12() when fixing a reference.
And that we do...
And it doesn't crash :-)
I've BTW also protected all the user-defined hash test functions in some
commit today, which are malloc'd in fns.c. Reason is that these persist
beyond the lifetime of hash tables using them, IIUC. Strange thing,
somewhat. Whatever :-).
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-20 18:21 ` Gerd Möllmann
@ 2024-05-20 18:32 ` Helmut Eller
2024-05-21 3:30 ` Gerd Möllmann
0 siblings, 1 reply; 22+ messages in thread
From: Helmut Eller @ 2024-05-20 18:32 UTC (permalink / raw)
To: Gerd Möllmann; +Cc: Eli Zaretskii, Emacs Devel
On Mon, May 20 2024, Gerd Möllmann wrote:
> I've BTW also protected all the user-defined hash test functions in some
> commit today, which are malloc'd in fns.c. Reason is that these persist
> beyond the lifetime of hash tables using them, IIUC. Strange thing,
> somewhat. Whatever :-).
Yes, that's good. The code in fix_hash_table can then be deleted.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-20 18:32 ` Helmut Eller
@ 2024-05-21 3:30 ` Gerd Möllmann
0 siblings, 0 replies; 22+ messages in thread
From: Gerd Möllmann @ 2024-05-21 3:30 UTC (permalink / raw)
To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel
Helmut Eller <eller.helmut@gmail.com> writes:
> On Mon, May 20 2024, Gerd Möllmann wrote:
>
>> I've BTW also protected all the user-defined hash test functions in some
>> commit today, which are malloc'd in fns.c. Reason is that these persist
>> beyond the lifetime of hash tables using them, IIUC. Strange thing,
>> somewhat. Whatever :-).
>
> Yes, that's good. The code in fix_hash_table can then be deleted.
Right. Thanks, now done.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-20 17:54 MPS prstack Helmut Eller
2024-05-20 18:21 ` Gerd Möllmann
@ 2024-05-22 16:27 ` Helmut Eller
2024-05-22 17:55 ` Gerd Möllmann
2024-05-24 14:17 ` Helmut Eller
1 sibling, 2 replies; 22+ messages in thread
From: Helmut Eller @ 2024-05-22 16:27 UTC (permalink / raw)
To: Gerd Möllmann; +Cc: Eli Zaretskii, Emacs Devel
[-- Attachment #1: Type: text/plain, Size: 365 bytes --]
On Mon, May 20 2024, Helmut Eller wrote:
> In print.c, there is a global variable prstack that is not yet scanned.
> This causes a crash for comp-tests but this example triggers the same
> problem:
There is another one: ppstack. I wasn't able to create a small test
case for this but ppstack is needed when print-circle=t. The native
compiler uses that a lot.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-Make-ppstack-an-exact-root.patch --]
[-- Type: text/x-diff, Size: 1634 bytes --]
From 61943bbd287efaa8ebf9994be1d536d82456072e Mon Sep 17 00:00:00 2001
From: Helmut Eller <eller.helmut@gmail.com>
Date: Wed, 22 May 2024 15:03:41 +0200
Subject: [PATCH] Make ppstack an exact root
* src/print.c (grow_pp_stack): Use igc_xpalloc_exact.
(scan_ppstack): New.
---
src/print.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/src/print.c b/src/print.c
index f043da92c1f..c87597be899 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1326,12 +1326,44 @@ #define PRINT_CIRCLE_CANDIDATE_P(obj) \
static struct print_pp_stack ppstack = {NULL, 0, 0};
+static igc_scan_result_t
+scan_ppstack (struct igc_opaque *op, void *start, void *end,
+ igc_scan_cell_t scan1)
+{
+ eassert (start == (void *)ppstack.stack);
+ eassert (end == (void *)(ppstack.stack + ppstack.size));
+ struct print_pp_entry *p = start;
+ struct print_pp_entry *q = p + ppstack.sp;
+ for (; p < q; p++)
+ {
+ igc_scan_result_t err = 0;
+ if (p->n == 0)
+ {
+ if (err = scan1 (op, &p->u.value), err != 0)
+ return err;
+ }
+ else
+ {
+ eassert (p->n > 0);
+ for (size_t i = 0; i < p->n; i++)
+ if (err = scan1 (op, &p->u.values[i]), err != 0)
+ return err;
+ }
+ }
+ return 0;
+}
+
NO_INLINE static void
grow_pp_stack (void)
{
struct print_pp_stack *ps = &ppstack;
eassert (ps->sp == ps->size);
+#ifdef HAVE_MPS
+ ps->stack = igc_xpalloc_exact (ps->stack, &ps->size, 1, -1,
+ sizeof *ps->stack, scan_ppstack);
+#else
ps->stack = xpalloc (ps->stack, &ps->size, 1, -1, sizeof *ps->stack);
+#endif
eassert (ps->sp < ps->size);
}
--
2.39.2
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-22 16:27 ` Helmut Eller
@ 2024-05-22 17:55 ` Gerd Möllmann
2024-05-24 14:17 ` Helmut Eller
1 sibling, 0 replies; 22+ messages in thread
From: Gerd Möllmann @ 2024-05-22 17:55 UTC (permalink / raw)
To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel
Helmut Eller <eller.helmut@gmail.com> writes:
> On Mon, May 20 2024, Helmut Eller wrote:
>
>> In print.c, there is a global variable prstack that is not yet scanned.
>> This causes a crash for comp-tests but this example triggers the same
>> problem:
>
> There is another one: ppstack. I wasn't able to create a small test
> case for this but ppstack is needed when print-circle=t. The native
> compiler uses that a lot.
Thanks, and pushed!
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-22 16:27 ` Helmut Eller
2024-05-22 17:55 ` Gerd Möllmann
@ 2024-05-24 14:17 ` Helmut Eller
2024-05-24 14:27 ` Gerd Möllmann
1 sibling, 1 reply; 22+ messages in thread
From: Helmut Eller @ 2024-05-24 14:17 UTC (permalink / raw)
To: Gerd Möllmann; +Cc: Eli Zaretskii, Emacs Devel
[-- Attachment #1: Type: text/plain, Size: 274 bytes --]
On Wed, May 22 2024, Helmut Eller wrote:
> There is another one: ppstack. I wasn't able to create a small test
> case for this but ppstack is needed when print-circle=t. The native
> compiler uses that a lot.
This needs some work. The patches below should help a bit.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: 0001-For-igc_xpalloc_exact-make-PA-an-in-out-parameter.patch --]
[-- Type: text/x-diff, Size: 3498 bytes --]
From 316e6894d6d432be763593b2e8ff816f413264dd Mon Sep 17 00:00:00 2001
From: Helmut Eller <eller.helmut@gmail.com>
Date: Fri, 24 May 2024 15:49:23 +0200
Subject: [PATCH 1/2] For igc_xpalloc_exact, make PA an in-out parameter
Because igc_xpalloc_exact uses mps_arena_release the scan_area callback
may be called before igc_xpalloc_exact returns. With an in-out
parameter, the client has the option to receive the new address before
the igc_xpalloc_exact returns.
* src/igc.h (igc_xpalloc_exact): Change the type of PA.
* src/igc.c (igc_xpalloc_exact): Implement the new protocol.
* src/print.c (grow_pp_stack, grow_print_stack): Update accordingly.
---
src/igc.c | 11 ++++++-----
src/igc.h | 6 +++---
src/print.c | 8 ++++----
3 files changed, 13 insertions(+), 12 deletions(-)
diff --git a/src/igc.c b/src/igc.c
index dc4512713f7..4f22221e952 100644
--- a/src/igc.c
+++ b/src/igc.c
@@ -2416,13 +2416,14 @@ scan_xpalloced (mps_ss_t ss, void *start, void *end, void *closure)
return scan_area ((struct igc_opaque *)ss, start, end, scan_cell);
}
-void *
-igc_xpalloc_exact (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min,
- ptrdiff_t nitems_max, ptrdiff_t item_size,
- igc_scan_area_t scan_area)
+void
+igc_xpalloc_exact (void **pa_cell, ptrdiff_t *nitems,
+ ptrdiff_t nitems_incr_min, ptrdiff_t nitems_max,
+ ptrdiff_t item_size, igc_scan_area_t scan_area)
{
IGC_WITH_PARKED (global_igc)
{
+ void *pa = *pa_cell;
if (pa)
{
struct igc_root_list *r = root_find (pa);
@@ -2433,8 +2434,8 @@ igc_xpalloc_exact (void *pa, ptrdiff_t *nitems, ptrdiff_t nitems_incr_min,
char *end = (char *)pa + *nitems * item_size;
root_create (global_igc, pa, end, mps_rank_exact (),
scan_xpalloced, scan_area, false);
+ *pa_cell = pa;
}
- return pa;
}
void *
diff --git a/src/igc.h b/src/igc.h
index fb37ce22e22..5b97787916c 100644
--- a/src/igc.h
+++ b/src/igc.h
@@ -84,9 +84,9 @@ #define EMACS_IGC_H
typedef igc_scan_result_t (*igc_scan_area_t) (struct igc_opaque *,
void *start, void *end,
igc_scan_cell_t fun);
-void *igc_xpalloc_exact (void *pa, ptrdiff_t *nitems,
- ptrdiff_t nitems_incr_min, ptrdiff_t nitems_max,
- ptrdiff_t item_size, igc_scan_area_t scan);
+void igc_xpalloc_exact (void **pa_cell, ptrdiff_t *nitems,
+ ptrdiff_t nitems_incr_min, ptrdiff_t nitems_max,
+ ptrdiff_t item_size, igc_scan_area_t scan);
void *igc_xnrealloc_ambig (void *pa, ptrdiff_t nitems, ptrdiff_t item_size);
diff --git a/src/print.c b/src/print.c
index c87597be899..5aec73c15e3 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1359,8 +1359,8 @@ grow_pp_stack (void)
struct print_pp_stack *ps = &ppstack;
eassert (ps->sp == ps->size);
#ifdef HAVE_MPS
- ps->stack = igc_xpalloc_exact (ps->stack, &ps->size, 1, -1,
- sizeof *ps->stack, scan_ppstack);
+ igc_xpalloc_exact ((void **)&ppstack.stack, &ps->size, 1, -1,
+ sizeof *ps->stack, scan_ppstack);
#else
ps->stack = xpalloc (ps->stack, &ps->size, 1, -1, sizeof *ps->stack);
#endif
@@ -2273,8 +2273,8 @@ grow_print_stack (void)
struct print_stack *ps = &prstack;
eassert (ps->sp == ps->size);
#ifdef HAVE_MPS
- ps->stack = igc_xpalloc_exact (ps->stack, &ps->size, 1, -1,
- sizeof *ps->stack, scan_prstack);
+ igc_xpalloc_exact ((void **)&prstack.stack, &ps->size, 1, -1,
+ sizeof *ps->stack, scan_prstack);
#else
ps->stack = xpalloc (ps->stack, &ps->size, 1, -1, sizeof *ps->stack);
#endif
--
2.39.2
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #3: 0002-Safer-use-of-ppstack.patch --]
[-- Type: text/x-diff, Size: 3113 bytes --]
From dd2033d482a29dff2275daf082148ffc2bea16fd Mon Sep 17 00:00:00 2001
From: Helmut Eller <eller.helmut@gmail.com>
Date: Fri, 24 May 2024 16:00:12 +0200
Subject: [PATCH 2/2] Safer use of ppstack
In print_pp_entry, the u.values fields holds a pointer into the interior
of a vectorlike object. This doesn't work for a moving GC. It's safer
to keep the original object and access it with AREF.
* print.c (print_pp_entry): Add a vectorlike variant to the union.
(scan_ppstack, pp_stack_push_values, print_preprocess): Update accordingly.
---
src/print.c | 34 ++++++++++++++++++++++++++++++----
1 file changed, 30 insertions(+), 4 deletions(-)
diff --git a/src/print.c b/src/print.c
index 5aec73c15e3..cc86e1e9710 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1314,7 +1314,11 @@ #define PRINT_CIRCLE_CANDIDATE_P(obj) \
ptrdiff_t n; /* number of values, or 0 if a single value */
union {
Lisp_Object value; /* when n = 0 */
+#ifdef HAVE_MPS
+ Lisp_Object vectorlike; /* when n > 0 */
+#else
Lisp_Object *values; /* when n > 0 */
+#endif
} u;
};
@@ -1345,9 +1349,8 @@ scan_ppstack (struct igc_opaque *op, void *start, void *end,
else
{
eassert (p->n > 0);
- for (size_t i = 0; i < p->n; i++)
- if (err = scan1 (op, &p->u.values[i]), err != 0)
- return err;
+ if (err = scan1 (op, &p->u.vectorlike), err != 0)
+ return err;
}
}
return 0;
@@ -1376,6 +1379,20 @@ pp_stack_push_value (Lisp_Object value)
.u.value = value};
}
+#ifdef HAVE_MPS
+static inline void
+pp_stack_push_values (Lisp_Object vectorlike, ptrdiff_t n)
+{
+ eassert (VECTORLIKEP (vectorlike));
+ eassume (n >= 0);
+ if (n == 0)
+ return;
+ if (ppstack.sp >= ppstack.size)
+ grow_pp_stack ();
+ ppstack.stack[ppstack.sp++]
+ = (struct print_pp_entry){ .n = n, .u.vectorlike = vectorlike };
+}
+#else
static inline void
pp_stack_push_values (Lisp_Object *values, ptrdiff_t n)
{
@@ -1387,6 +1404,7 @@ pp_stack_push_values (Lisp_Object *values, ptrdiff_t n)
ppstack.stack[ppstack.sp++] = (struct print_pp_entry){.n = n,
.u.values = values};
}
+#endif
static inline bool
pp_stack_empty_p (void)
@@ -1409,7 +1427,11 @@ pp_stack_pop (void)
e->n--;
if (e->n == 0)
--ppstack.sp; /* last value consumed */
+#ifdef HAVE_MPS
+ return AREF (e->u.vectorlike, e->n);
+#else
return (++e->u.values)[-1];
+#endif
}
/* Construct Vprint_number_table for the print-circle feature
@@ -1475,13 +1497,17 @@ print_preprocess (Lisp_Object obj)
case Lisp_Vectorlike:
{
- struct Lisp_Vector *vec = XVECTOR (obj);
ptrdiff_t size = ASIZE (obj);
if (size & PSEUDOVECTOR_FLAG)
size &= PSEUDOVECTOR_SIZE_MASK;
ptrdiff_t start = (SUB_CHAR_TABLE_P (obj)
? SUB_CHAR_TABLE_OFFSET : 0);
+#ifdef HAVE_MPS
+ pp_stack_push_values (obj, size - start);
+#else
+ struct Lisp_Vector *vec = XVECTOR (obj);
pp_stack_push_values (vec->contents + start, size - start);
+#endif
if (HASH_TABLE_P (obj))
{
struct Lisp_Hash_Table *h = XHASH_TABLE (obj);
--
2.39.2
^ permalink raw reply related [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-24 14:17 ` Helmut Eller
@ 2024-05-24 14:27 ` Gerd Möllmann
2024-05-25 13:45 ` Gerd Möllmann
0 siblings, 1 reply; 22+ messages in thread
From: Gerd Möllmann @ 2024-05-24 14:27 UTC (permalink / raw)
To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel
Helmut Eller <eller.helmut@gmail.com> writes:
> On Wed, May 22 2024, Helmut Eller wrote:
>
>> There is another one: ppstack. I wasn't able to create a small test
>> case for this but ppstack is needed when print-circle=t. The native
>> compiler uses that a lot.
>
> This needs some work. The patches below should help a bit.
Pushed. Thanks!
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-24 14:27 ` Gerd Möllmann
@ 2024-05-25 13:45 ` Gerd Möllmann
2024-05-27 7:27 ` Helmut Eller
0 siblings, 1 reply; 22+ messages in thread
From: Gerd Möllmann @ 2024-05-25 13:45 UTC (permalink / raw)
To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel
Gerd Möllmann <gerd.moellmann@gmail.com> writes:
> Helmut Eller <eller.helmut@gmail.com> writes:
>
>> On Wed, May 22 2024, Helmut Eller wrote:
>>
>>> There is another one: ppstack. I wasn't able to create a small test
>>> case for this but ppstack is needed when print-circle=t. The native
>>> compiler uses that a lot.
>>
>> This needs some work. The patches below should help a bit.
>
> Pushed. Thanks!
Moint Helmut. I've pushed another fix that prevents processing non-Lisp
objs in sub char-tables.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-25 13:45 ` Gerd Möllmann
@ 2024-05-27 7:27 ` Helmut Eller
2024-05-27 8:43 ` Gerd Möllmann
2024-05-27 11:34 ` Eli Zaretskii
0 siblings, 2 replies; 22+ messages in thread
From: Helmut Eller @ 2024-05-27 7:27 UTC (permalink / raw)
To: Gerd Möllmann; +Cc: Eli Zaretskii, Emacs Devel
On Sat, May 25 2024, Gerd Möllmann wrote:
> Moint Helmut. I've pushed another fix that prevents processing non-Lisp
> objs in sub char-tables.
Oops. Would be nice if print-tests.el would cover some of the more
exotic cases.
Somewhat related: I wonder if this line in print_stack_push is safe:
prstack.stack[prstack.sp++] = e;
This is not an atomic operation and prstack.sp gets updated before the
new stack slot is initialized. In theory, there is a small time window
where scan_prstack can see the new prstack.sp but not the new value for
the slot. Do we need to worry about such issues?
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-27 7:27 ` Helmut Eller
@ 2024-05-27 8:43 ` Gerd Möllmann
2024-05-27 9:15 ` Helmut Eller
2024-05-27 11:34 ` Eli Zaretskii
1 sibling, 1 reply; 22+ messages in thread
From: Gerd Möllmann @ 2024-05-27 8:43 UTC (permalink / raw)
To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel
Helmut Eller <eller.helmut@gmail.com> writes:
> On Sat, May 25 2024, Gerd Möllmann wrote:
>
>> Moint Helmut. I've pushed another fix that prevents processing non-Lisp
>> objs in sub char-tables.
>
> Oops. Would be nice if print-tests.el would cover some of the more
> exotic cases.
>
> Somewhat related: I wonder if this line in print_stack_push is safe:
>
> prstack.stack[prstack.sp++] = e;
>
> This is not an atomic operation and prstack.sp gets updated before the
> new stack slot is initialized. In theory, there is a small time window
> where scan_prstack can see the new prstack.sp but not the new value for
> the slot. Do we need to worry about such issues?
Hm. No idea when the increment is sequenced. The side effect of postfix
++ could be applied anywhere before the next sequence point. But where
is that sequence point? There is one at the end of the whole expression
I think.
Reminds me why I avoid postfix ++ and -- :-)
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-27 8:43 ` Gerd Möllmann
@ 2024-05-27 9:15 ` Helmut Eller
2024-05-27 9:47 ` Gerd Möllmann
2024-05-27 11:45 ` Eli Zaretskii
0 siblings, 2 replies; 22+ messages in thread
From: Helmut Eller @ 2024-05-27 9:15 UTC (permalink / raw)
To: Gerd Möllmann; +Cc: Eli Zaretskii, Emacs Devel
On Mon, May 27 2024, Gerd Möllmann wrote:
>> prstack.stack[prstack.sp++] = e;
>
> Hm. No idea when the increment is sequenced. The side effect of postfix
> ++ could be applied anywhere before the next sequence point. But where
> is that sequence point? There is one at the end of the whole expression
> I think.
The generated code with O0 looks like this:
...
0x000055555587fcb1 <+28>: call 0x55555587fbd0 <grow_print_stack>
0x000055555587fcb6 <+33>: mov 0x8845c3(%rip),%rcx # 0x555556104280 <prstack>
0x000055555587fcbd <+40>: mov 0x8845cc(%rip),%rax # 0x555556104290 <prstack+16>
0x000055555587fcc4 <+47>: lea 0x1(%rax),%rdx
0x000055555587fcc8 <+51>: mov %rdx,0x8845c1(%rip) # 0x555556104290 <prstack+16>
0x000055555587fccf <+58>: mov %rax,%rdx
0x000055555587fcd2 <+61>: mov %rdx,%rax
0x000055555587fcd5 <+64>: shl $0x3,%rax
0x000055555587fcd9 <+68>: sub %rdx,%rax
0x000055555587fcdc <+71>: shl $0x3,%rax
0x000055555587fce0 <+75>: add %rcx,%rax
0x000055555587fce3 <+78>: mov 0x10(%rbp),%rcx
0x000055555587fce7 <+82>: mov 0x18(%rbp),%rbx
...
So it looks like prstack.sp is updated with the move at +51, i.e. before
the stack slot is initialized.
We could write
prstack.stack[prstack.sp] = e;
prstack.sp += 1;
Not sure how we then guarantee that e still in a register or the control
stack at the second line.
But my question was more whether MPS actually does call scan_prstack at
"any moment" or if this is just a theoretical possibility for some
possible future version of MPS.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-27 9:15 ` Helmut Eller
@ 2024-05-27 9:47 ` Gerd Möllmann
2024-05-27 11:45 ` Eli Zaretskii
1 sibling, 0 replies; 22+ messages in thread
From: Gerd Möllmann @ 2024-05-27 9:47 UTC (permalink / raw)
To: Helmut Eller; +Cc: Eli Zaretskii, Emacs Devel
Helmut Eller <eller.helmut@gmail.com> writes:
> On Mon, May 27 2024, Gerd Möllmann wrote:
>
>>> prstack.stack[prstack.sp++] = e;
>>
>> Hm. No idea when the increment is sequenced. The side effect of postfix
>> ++ could be applied anywhere before the next sequence point. But where
>> is that sequence point? There is one at the end of the whole expression
>> I think.
>
> The generated code with O0 looks like this:
>
> ...
> 0x000055555587fcb1 <+28>: call 0x55555587fbd0 <grow_print_stack>
> 0x000055555587fcb6 <+33>: mov 0x8845c3(%rip),%rcx # 0x555556104280 <prstack>
> 0x000055555587fcbd <+40>: mov 0x8845cc(%rip),%rax # 0x555556104290 <prstack+16>
> 0x000055555587fcc4 <+47>: lea 0x1(%rax),%rdx
> 0x000055555587fcc8 <+51>: mov %rdx,0x8845c1(%rip) # 0x555556104290 <prstack+16>
> 0x000055555587fccf <+58>: mov %rax,%rdx
> 0x000055555587fcd2 <+61>: mov %rdx,%rax
> 0x000055555587fcd5 <+64>: shl $0x3,%rax
> 0x000055555587fcd9 <+68>: sub %rdx,%rax
> 0x000055555587fcdc <+71>: shl $0x3,%rax
> 0x000055555587fce0 <+75>: add %rcx,%rax
> 0x000055555587fce3 <+78>: mov 0x10(%rbp),%rcx
> 0x000055555587fce7 <+82>: mov 0x18(%rbp),%rbx
> ...
>
> So it looks like prstack.sp is updated with the move at +51, i.e. before
> the stack slot is initialized.
>
> We could write
>
> prstack.stack[prstack.sp] = e;
> prstack.sp += 1;
>
> Not sure how we then guarantee that e still in a register or the control
> stack at the second line.
>
> But my question was more whether MPS actually does call scan_prstack at
> "any moment" or if this is just a theoretical possibility for some
> possible future version of MPS.
I think it is "at any moment". At least I can't find anything in the
docs hinting at something else.
Which probably means that we can't wholy trust stack points. They may be
off.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-27 9:15 ` Helmut Eller
2024-05-27 9:47 ` Gerd Möllmann
@ 2024-05-27 11:45 ` Eli Zaretskii
2024-05-27 12:39 ` Helmut Eller
1 sibling, 1 reply; 22+ messages in thread
From: Eli Zaretskii @ 2024-05-27 11:45 UTC (permalink / raw)
To: Helmut Eller; +Cc: gerd.moellmann, emacs-devel
> From: Helmut Eller <eller.helmut@gmail.com>
> Cc: Eli Zaretskii <eliz@gnu.org>, Emacs Devel <emacs-devel@gnu.org>
> Date: Mon, 27 May 2024 11:15:35 +0200
>
> We could write
>
> prstack.stack[prstack.sp] = e;
> prstack.sp += 1;
You could, but AFAIU it's equivalent to the original code.
A compiler is allowed to reorder code if doing so doesn't change the
outcome. So a valid translation of the above by the compiler would be
something like
temp = prstack.sp;
prstack.sp += 1;
prstack.stack[temp] = e;
> Not sure how we then guarantee that e still in a register or the control
> stack at the second line.
>
> But my question was more whether MPS actually does call scan_prstack at
> "any moment" or if this is just a theoretical possibility for some
> possible future version of MPS.
Why is all this order important, can you elaborate? Neither MPS nor
we can rely on the order in which the generated code does this stuff,
AFAIU.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-27 11:45 ` Eli Zaretskii
@ 2024-05-27 12:39 ` Helmut Eller
2024-05-27 13:12 ` Eli Zaretskii
0 siblings, 1 reply; 22+ messages in thread
From: Helmut Eller @ 2024-05-27 12:39 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gerd.moellmann, emacs-devel
On Mon, May 27 2024, Eli Zaretskii wrote:
>> But my question was more whether MPS actually does call scan_prstack at
>> "any moment" or if this is just a theoretical possibility for some
>> possible future version of MPS.
>
> Why is all this order important, can you elaborate? Neither MPS nor
> we can rely on the order in which the generated code does this stuff,
> AFAIU.
It is important because scan_prstack only scans the region
prstack.stack[0..prstack.sp] and because scan_prstack runs (potentially)
concurrent to print_stack_push.
If print_stack_push increments prstack.sp before initializing
prstack.stack[prstack.sp], then scan_prstack may read the old value out
of that slot.
That a compiler will "rewrite"
prstack.stack[prstack.sp] = e;
prstack.sp += 1;
to
prstack.sp += 1;
prstack.stack[prstack.sp - 1] = e;
seems very unlikely the me. But granted, compilers are known to do
unhelpful things in the name of optimization.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-27 12:39 ` Helmut Eller
@ 2024-05-27 13:12 ` Eli Zaretskii
2024-05-27 14:15 ` Helmut Eller
0 siblings, 1 reply; 22+ messages in thread
From: Eli Zaretskii @ 2024-05-27 13:12 UTC (permalink / raw)
To: Helmut Eller; +Cc: gerd.moellmann, emacs-devel
> From: Helmut Eller <eller.helmut@gmail.com>
> Cc: gerd.moellmann@gmail.com, emacs-devel@gnu.org
> Date: Mon, 27 May 2024 14:39:37 +0200
>
> On Mon, May 27 2024, Eli Zaretskii wrote:
>
> >> But my question was more whether MPS actually does call scan_prstack at
> >> "any moment" or if this is just a theoretical possibility for some
> >> possible future version of MPS.
> >
> > Why is all this order important, can you elaborate? Neither MPS nor
> > we can rely on the order in which the generated code does this stuff,
> > AFAIU.
>
> It is important because scan_prstack only scans the region
> prstack.stack[0..prstack.sp] and because scan_prstack runs (potentially)
> concurrent to print_stack_push.
>
> If print_stack_push increments prstack.sp before initializing
> prstack.stack[prstack.sp], then scan_prstack may read the old value out
> of that slot.
If we need to make sure that "prstack.stack[prstack.sp++] = e;" is
done atomically, maybe we can use the __atomic builtins (see the node
"__atomic Builtins" in the GCC manual).
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-27 13:12 ` Eli Zaretskii
@ 2024-05-27 14:15 ` Helmut Eller
2024-05-27 14:37 ` Mattias Engdegård
2024-05-27 14:43 ` Po Lu
0 siblings, 2 replies; 22+ messages in thread
From: Helmut Eller @ 2024-05-27 14:15 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gerd.moellmann, emacs-devel
On Mon, May 27 2024, Eli Zaretskii wrote:
>> If print_stack_push increments prstack.sp before initializing
>> prstack.stack[prstack.sp], then scan_prstack may read the old value out
>> of that slot.
>
> If we need to make sure that "prstack.stack[prstack.sp++] = e;" is
> done atomically, maybe we can use the __atomic builtins (see the node
> "__atomic Builtins" in the GCC manual).
Yes. I think
prstack.stack[prstack.sp] = e;
__atomic_store_n (&prstack.sp, prstack.sp + 1, __ATOMIC_SEQ_CST);
is quite sufficient.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-27 14:15 ` Helmut Eller
@ 2024-05-27 14:37 ` Mattias Engdegård
2024-05-27 14:54 ` Helmut Eller
2024-05-27 14:43 ` Po Lu
1 sibling, 1 reply; 22+ messages in thread
From: Mattias Engdegård @ 2024-05-27 14:37 UTC (permalink / raw)
To: Helmut Eller; +Cc: Eli Zaretskii, gerd.moellmann, emacs-devel
27 maj 2024 kl. 16.15 skrev Helmut Eller <eller.helmut@gmail.com>:
> prstack.stack[prstack.sp] = e;
> __atomic_store_n (&prstack.sp, prstack.sp + 1, __ATOMIC_SEQ_CST);
Surely that is a severe overkill when all we need is a compiler barrier?
Or have I misunderstood the context the scanners are called in?
Shouldn't they have the same view of memory as the mutator?
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-27 14:37 ` Mattias Engdegård
@ 2024-05-27 14:54 ` Helmut Eller
0 siblings, 0 replies; 22+ messages in thread
From: Helmut Eller @ 2024-05-27 14:54 UTC (permalink / raw)
To: Mattias Engdegård; +Cc: Eli Zaretskii, gerd.moellmann, emacs-devel
On Mon, May 27 2024, Mattias Engdegård wrote:
> 27 maj 2024 kl. 16.15 skrev Helmut Eller <eller.helmut@gmail.com>:
>
>> prstack.stack[prstack.sp] = e;
>> __atomic_store_n (&prstack.sp, prstack.sp + 1, __ATOMIC_SEQ_CST);
>
> Surely that is a severe overkill when all we need is a compiler barrier?
> Or have I misunderstood the context the scanners are called in?
> Shouldn't they have the same view of memory as the mutator?
The __atomic_store_n mainly prevents the compiler from reordering
instructions. The generated code uses xchg in one version and mov in
the other. I doubt that it makes any difference to the hardware, but
using __atomic_store_n documents a subtle point.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-27 14:15 ` Helmut Eller
2024-05-27 14:37 ` Mattias Engdegård
@ 2024-05-27 14:43 ` Po Lu
2024-05-27 15:08 ` Helmut Eller
1 sibling, 1 reply; 22+ messages in thread
From: Po Lu @ 2024-05-27 14:43 UTC (permalink / raw)
To: Helmut Eller; +Cc: Eli Zaretskii, gerd.moellmann, emacs-devel
Helmut Eller <eller.helmut@gmail.com> writes:
> Yes. I think
>
> prstack.stack[prstack.sp] = e;
> __atomic_store_n (&prstack.sp, prstack.sp + 1, __ATOMIC_SEQ_CST);
>
> is quite sufficient.
How so? This doesn't guarantee that MPS cannot pause the thread after E
is saved into prstack but before prstack.sp is incremented, or that E
will remain on the control stack or in the register file until it is.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-27 14:43 ` Po Lu
@ 2024-05-27 15:08 ` Helmut Eller
0 siblings, 0 replies; 22+ messages in thread
From: Helmut Eller @ 2024-05-27 15:08 UTC (permalink / raw)
To: Po Lu; +Cc: Eli Zaretskii, gerd.moellmann, emacs-devel
On Mon, May 27 2024, Po Lu wrote:
> Helmut Eller <eller.helmut@gmail.com> writes:
>
>> Yes. I think
>>
>> prstack.stack[prstack.sp] = e;
>> __atomic_store_n (&prstack.sp, prstack.sp + 1, __ATOMIC_SEQ_CST);
>>
>> is quite sufficient.
>
> How so? This doesn't guarantee that MPS cannot pause the thread after E
> is saved into prstack but before prstack.sp is incremented,
Right. But we are sure that prstack.sp is not incremented before E is
saved. And scan_prstack doesn't care what is beyond prstack.sp.
> or that E
> will remain on the control stack or in the register file until it is.
Yes. But that's another issue. That could be solved by making
print_stack_push a non-inline function that takes a reference to E as
argument.
^ permalink raw reply [flat|nested] 22+ messages in thread
* Re: MPS prstack
2024-05-27 7:27 ` Helmut Eller
2024-05-27 8:43 ` Gerd Möllmann
@ 2024-05-27 11:34 ` Eli Zaretskii
1 sibling, 0 replies; 22+ messages in thread
From: Eli Zaretskii @ 2024-05-27 11:34 UTC (permalink / raw)
To: Helmut Eller; +Cc: gerd.moellmann, emacs-devel
> From: Helmut Eller <eller.helmut@gmail.com>
> Cc: Eli Zaretskii <eliz@gnu.org>, Emacs Devel <emacs-devel@gnu.org>
> Date: Mon, 27 May 2024 09:27:31 +0200
>
> Somewhat related: I wonder if this line in print_stack_push is safe:
>
> prstack.stack[prstack.sp++] = e;
>
> This is not an atomic operation and prstack.sp gets updated before the
> new stack slot is initialized.
Are you sure? I think the above assigns e to
prstack.stack[prstack.sp], and then increments prstack.sp. What you
describe is this instead:
prstack.stack[++prstack.sp] = e;
By analogy with the original code above, what does the following do?
char *s;
*s++ = 'a';
AFAIU, it stores 'a' in the address pointed by s and then increments
s.
^ permalink raw reply [flat|nested] 22+ messages in thread
end of thread, other threads:[~2024-05-27 15:08 UTC | newest]
Thread overview: 22+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-20 17:54 MPS prstack Helmut Eller
2024-05-20 18:21 ` Gerd Möllmann
2024-05-20 18:32 ` Helmut Eller
2024-05-21 3:30 ` Gerd Möllmann
2024-05-22 16:27 ` Helmut Eller
2024-05-22 17:55 ` Gerd Möllmann
2024-05-24 14:17 ` Helmut Eller
2024-05-24 14:27 ` Gerd Möllmann
2024-05-25 13:45 ` Gerd Möllmann
2024-05-27 7:27 ` Helmut Eller
2024-05-27 8:43 ` Gerd Möllmann
2024-05-27 9:15 ` Helmut Eller
2024-05-27 9:47 ` Gerd Möllmann
2024-05-27 11:45 ` Eli Zaretskii
2024-05-27 12:39 ` Helmut Eller
2024-05-27 13:12 ` Eli Zaretskii
2024-05-27 14:15 ` Helmut Eller
2024-05-27 14:37 ` Mattias Engdegård
2024-05-27 14:54 ` Helmut Eller
2024-05-27 14:43 ` Po Lu
2024-05-27 15:08 ` Helmut Eller
2024-05-27 11:34 ` Eli Zaretskii
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.