summaryrefslogtreecommitdiff
path: root/src/bytecode.c
diff options
context:
space:
mode:
authorMattias EngdegÄrd <mattiase@acm.org>2021-12-31 17:24:31 +0100
committerMattias EngdegÄrd <mattiase@acm.org>2022-01-24 11:41:46 +0100
commit65caf5b205d22f76bb4ec85cfe597b621a83afb3 (patch)
tree8a4b71295d56f76ad0fee6c4471aa036c6e7e226 /src/bytecode.c
parentce1de3a8d9723305f48fd4527fbceaff3cec50ba (diff)
downloademacs-65caf5b205d22f76bb4ec85cfe597b621a83afb3.tar.gz
emacs-65caf5b205d22f76bb4ec85cfe597b621a83afb3.tar.bz2
emacs-65caf5b205d22f76bb4ec85cfe597b621a83afb3.zip
Pin bytecode strings to avoid copy at call time
Avoid making a copy (in the interpreter C stack frame) of the bytecode string by making sure it won't be moved by the GC. This is done by reallocating it to the heap normally only used for large strings, which isn't compacted. This requires that we retain an explicit reference to the bytecode string object (`bytestr`) lest it be GCed away should all other references vanish during execution. We allocate an extra stack slot for that, as we already do for the constant vector object. * src/alloc.c (allocate_string_data): Add `immovable` argument. (resize_string_data, make_clear_multibyte_string): Use it. (pin_string): New. * src/pdumper.c (dump_string): Fix incorrect comment. Update hash for Lisp_String (only comments changed, not contents). * src/lread.c (read1): * src/alloc.c (Fmake_byte_code, purecopy): * src/bytecode.c (Fbyte_code): Pin bytecode on object creation. (exec_byte_code): Don't copy bytecode. Retain `bytestr` explicitly. * src/lisp.h (Lisp_String): Explain special size_byte values. (string_immovable_p): New.
Diffstat (limited to 'src/bytecode.c')
-rw-r--r--src/bytecode.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/src/bytecode.c b/src/bytecode.c
index 37da0858ab4..0d0a28cd0bb 100644
--- a/src/bytecode.c
+++ b/src/bytecode.c
@@ -331,6 +331,7 @@ If the third argument is incorrect, Emacs may crash. */)
the original unibyte form. */
bytestr = Fstring_as_unibyte (bytestr);
}
+ pin_string (bytestr); // Bytecode must be immovable.
return exec_byte_code (bytestr, vector, maxdepth, Qnil, 0, NULL);
}
@@ -358,22 +359,28 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
#endif
eassert (!STRING_MULTIBYTE (bytestr));
+ eassert (string_immovable_p (bytestr));
ptrdiff_t const_length = ASIZE (vector);
ptrdiff_t bytestr_length = SCHARS (bytestr);
Lisp_Object *vectorp = XVECTOR (vector)->contents;
unsigned char quitcounter = 1;
- EMACS_INT stack_items = XFIXNAT (maxdepth) + 1;
+ /* Allocate two more slots than required, because... */
+ EMACS_INT stack_items = XFIXNAT (maxdepth) + 2;
USE_SAFE_ALLOCA;
void *alloc;
- SAFE_ALLOCA_LISP_EXTRA (alloc, stack_items, bytestr_length);
+ SAFE_ALLOCA_LISP (alloc, stack_items);
Lisp_Object *stack_base = alloc;
- Lisp_Object *top = stack_base;
- *top = vector; /* Ensure VECTOR survives GC (Bug#33014). */
- Lisp_Object *stack_lim = stack_base + stack_items;
- unsigned char const *bytestr_data = memcpy (stack_lim,
- SDATA (bytestr), bytestr_length);
+ /* ... we plonk BYTESTR and VECTOR there to ensure that they survive
+ GC (bug#33014), since these variables aren't used directly beyond
+ the interpreter prologue and wouldn't be found in the stack frame
+ otherwise. */
+ stack_base[0] = bytestr;
+ stack_base[1] = vector;
+ Lisp_Object *top = stack_base + 1;
+ Lisp_Object *stack_lim = top + stack_items;
+ unsigned char const *bytestr_data = SDATA (bytestr);
unsigned char const *pc = bytestr_data;
ptrdiff_t count = SPECPDL_INDEX ();
@@ -1564,6 +1571,8 @@ exec_byte_code (Lisp_Object bytestr, Lisp_Object vector, Lisp_Object maxdepth,
exit:
+ eassert (SDATA (bytestr) == bytestr_data);
+
/* Binds and unbinds are supposed to be compiled balanced. */
if (SPECPDL_INDEX () != count)
{