static void
allocate_string_data (struct Lisp_String *s,
- EMACS_INT nchars, EMACS_INT nbytes, bool clearit)
+ EMACS_INT nchars, EMACS_INT nbytes, bool clearit,
+ bool immovable)
{
sdata *data;
struct sblock *b;
MALLOC_BLOCK_INPUT;
- if (nbytes > LARGE_STRING_BYTES)
+ if (nbytes > LARGE_STRING_BYTES || immovable)
{
size_t size = FLEXSIZEOF (struct sblock, data, needed);
}
else
{
- allocate_string_data (XSTRING (string), nchars, new_nbytes, false);
+ allocate_string_data (XSTRING (string), nchars, new_nbytes, false, false);
unsigned char *new_data = SDATA (string);
new_charaddr = new_data + cidx_byte;
memcpy (new_charaddr + new_clen, data + cidx_byte + clen,
s = allocate_string ();
s->u.s.intervals = NULL;
- allocate_string_data (s, nchars, nbytes, clearit);
+ allocate_string_data (s, nchars, nbytes, clearit, false);
XSETSTRING (string, s);
string_chars_consed += nbytes;
return string;
return make_string (buf, length);
}
+/* Pin a unibyte string in place so that it won't move during GC. */
+void
+pin_string (Lisp_Object string)
+{
+ eassert (STRINGP (string) && !STRING_MULTIBYTE (string));
+ struct Lisp_String *s = XSTRING (string);
+ ptrdiff_t size = STRING_BYTES (s);
+ unsigned char *data = s->u.s.data;
+
+ if (!(size > LARGE_STRING_BYTES
+ || PURE_P (data) || pdumper_object_p (data)
+ || s->u.s.size_byte == -3))
+ {
+ eassert (s->u.s.size_byte == -1);
+ sdata *old_sdata = SDATA_OF_STRING (s);
+ allocate_string_data (s, size, size, false, true);
+ memcpy (s->u.s.data, data, size);
+ old_sdata->string = NULL;
+ SDATA_NBYTES (old_sdata) = size;
+ }
+ s->u.s.size_byte = -3;
+}
+
\f
/***********************************************************************
Float Allocation
&& FIXNATP (args[COMPILED_STACK_DEPTH])))
error ("Invalid byte-code object");
+ pin_string (args[COMPILED_BYTECODE]); // Bytecode must be immovable.
+
/* We used to purecopy everything here, if purify-flag was set. This worked
OK for Emacs-23, but with Emacs-24's lexical binding code, it can be
dangerous, since make-byte-code is used during execution to build
memcpy (vec, objp, nbytes);
for (i = 0; i < size; i++)
vec->contents[i] = purecopy (vec->contents[i]);
+ // Byte code strings must be pinned.
+ if (COMPILEDP (obj) && size >= 2 && STRINGP (vec->contents[1])
+ && !STRING_MULTIBYTE (vec->contents[1]))
+ pin_string (vec->contents[1]);
XSETVECTOR (obj, vec);
}
else if (BARE_SYMBOL_P (obj))
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);
}
#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 ();
exit:
+ eassert (SDATA (bytestr) == bytestr_data);
+
/* Binds and unbinds are supposed to be compiled balanced. */
if (SPECPDL_INDEX () != count)
{
struct
{
ptrdiff_t size; /* MSB is used as the markbit. */
- ptrdiff_t size_byte; /* Set to -1 for unibyte strings. */
+ ptrdiff_t size_byte; /* Set to -1 for unibyte strings,
+ -2 for data in rodata,
+ -3 for immovable unibyte strings. */
INTERVAL intervals; /* Text properties in this string. */
unsigned char *data;
} s;
Qfilenamep, string);
}
+/* True if STR is immovable (whose data won't move during GC). */
+INLINE bool
+string_immovable_p (Lisp_Object str)
+{
+ return XSTRING (str)->u.s.size_byte == -3;
+}
+
/* A regular vector is just a header plus an array of Lisp_Objects. */
struct Lisp_Vector
ptrdiff_t, ptrdiff_t, bool);
extern Lisp_Object make_pure_string (const char *, ptrdiff_t, ptrdiff_t, bool);
extern Lisp_Object make_pure_c_string (const char *, ptrdiff_t);
+extern void pin_string (Lisp_Object string);
/* Make a string allocated in pure space, use STR as string data. */
&& FIXNATP (AREF (tmp, COMPILED_STACK_DEPTH))))
invalid_syntax ("Invalid byte-code object", readcharfun);
- if (STRINGP (AREF (tmp, COMPILED_BYTECODE))
- && STRING_MULTIBYTE (AREF (tmp, COMPILED_BYTECODE)))
+ if (STRINGP (AREF (tmp, COMPILED_BYTECODE)))
{
- /* BYTESTR must have been produced by Emacs 20.2 or earlier
- because it produced a raw 8-bit string for byte-code and
- now such a byte-code string is loaded as multibyte with
- raw 8-bit characters converted to multibyte form.
- Convert them back to the original unibyte form. */
- ASET (tmp, COMPILED_BYTECODE,
- Fstring_as_unibyte (AREF (tmp, COMPILED_BYTECODE)));
+ if (STRING_MULTIBYTE (AREF (tmp, COMPILED_BYTECODE)))
+ {
+ /* BYTESTR must have been produced by Emacs 20.2 or earlier
+ because it produced a raw 8-bit string for byte-code and
+ now such a byte-code string is loaded as multibyte with
+ raw 8-bit characters converted to multibyte form.
+ Convert them back to the original unibyte form. */
+ ASET (tmp, COMPILED_BYTECODE,
+ Fstring_as_unibyte (AREF (tmp, COMPILED_BYTECODE)));
+ }
+ // Bytecode must be immovable.
+ pin_string (AREF (tmp, COMPILED_BYTECODE));
}
XSETPVECTYPE (vec, PVEC_COMPILED);
static dump_off
dump_string (struct dump_context *ctx, const struct Lisp_String *string)
{
-#if CHECK_STRUCTS && !defined (HASH_Lisp_String_348C2B2FDB)
+#if CHECK_STRUCTS && !defined (HASH_Lisp_String_C2CAF90352)
# error "Lisp_String changed. See CHECK_STRUCTS comment in config.h."
#endif
/* If we have text properties, write them _after_ the string so that
we seldom write to string data and never relocate it, so lumping
it together at the end of the dump saves on COW faults.
- If, however, the string's size_byte field is -1, the string data
+ If, however, the string's size_byte field is -2, the string data
is actually a pointer to Emacs data segment, so we can do even
better by emitting a relocation instead of bothering to copy the
string data. */