Subject: bug#78898: Make read/readevalloop reentrant

From: Stefan Monnier <[email-masked]>
Date: Tue, 22 Jul 2025 14:40:50 -0400

> The memory leak aspect is more observation than alarm.  The leak is only
> safe because the stack is implemented as a global static variable.  Getting
> rid of that property means either freeing the stack at the end of the
> initial entry to read, or allocating the read_entry stack from the garbage
> collected heap.

BTW memory that's not returned to the OS but that Emacs can reuse later
is generally not considered as a leak.  E.g., most `malloc`
implementations have the property of (virtually) never bothering to
return freed memory to the OS.

>> `read0` must be re-entrant because the \N{CHARNAME} notation makes us call
>> out to Lisp and possibly load some files (for the char names).

Oh, right, I'd forgotten about this one.   I seem to remember bugs
caused by this (or something similar where we lazily load some Unicode
table).  It's particularly tricky because this Lisp code is only ever
run at most once per session, so the "test coverage" is very poor.

> read-from-string is called from the pdump loader when an eln library is
> initialized.  An occurrence of that notation must be either very unlikely
> or carefully orchestrated by the pdump loader.

Yup: the \N{CHARNAME} notation cannot occur too early in the build.
And we know it won't occur at all in the (non-bootstrap) dump because
the \N{CHARNAME} notation is never used in the `.elc` or `.eln` files
we generate (because `print.c` never generates it).

> Right, all the more reason to have well-defined benchmarking. That's why I
> stated it the way I did: "time spent in lread.c".  I'm not sure how Stefan
> was measuring the performance of the reader.

I'd suggest you simply concatenate a bunch of `.elc` files, until you
get something "large enough" to make the timing easy to measure.
Then measure the time to read that file (put the content inside
a buffer, wrap it inside a pair of `(...)`, then (benchmark-run
(read))`).

[ Back before the pdump code was written, we considered a much simpler
  solution of saving the contents of the obarray into a big `.eld` file as
  a kind of "dump", i.e. basically using one big `.elc` file instead of
  the current `.pdmp`.
  It's easy to make it work (much easier than the pdump code), but it's
  significantly slower.  ]

> I will hazard a guess that the performance of the reader is more noticeable
> when the code being loaded is already compiled.

Yes, we don't care about the speed of reading `.el` files nearly as
much as the speed to read `.elc` or `.eld` files.

        Stefan