Change object marking routines to minimize stack usage.

This change moves a few cold paths from mark_object to NO_INLINE
functions and adjusts symbol marking loop.  According to GCC 4.8.2
-Wstack-usage, this reduces mark_object's stack usage from 80 to
48 bytes on a 64-bit system.  For a long byte-force-recompile runs,
stack usage at the mark phase is reduced up to 28%.  Surprisingly,
it also gains up to 3% in speed (with default '-O2 -g3' flags).
* alloc.c (mark_compiled, mark_localized_symbol): New functions,
refactored out from ...
(mark_object): ... adjusted user.  Also mark symbols in a tight
inner loop.
(mark_face_cache): Add NO_INLINE.
This commit is contained in:
Dmitry Antipov 2014-06-08 19:06:03 +04:00
parent 36cf8493af
commit 83f1450065
2 changed files with 59 additions and 39 deletions

View file

@ -1,3 +1,18 @@
2014-06-08 Dmitry Antipov <dmantipov@yandex.ru>
Change object marking routines to minimize stack usage.
This change moves a few cold paths from mark_object to NO_INLINE
functions and adjusts symbol marking loop. According to GCC 4.8.2
-Wstack-usage, this reduces mark_object's stack usage from 80 to
48 bytes on a 64-bit system. For a long byte-force-recompile runs,
stack usage at the mark phase is reduced up to 28%. Surprisingly,
it also gains up to 3% in speed (with default '-O2 -g3' flags).
* alloc.c (mark_compiled, mark_localized_symbol): New functions,
refactored out from ...
(mark_object): ... adjusted user. Also mark symbols in a tight
inner loop.
(mark_face_cache): Add NO_INLINE.
2014-06-08 Eli Zaretskii <eliz@gnu.org>
* sysdep.c (reset_sys_modes): Use cursorX, not curX, as the latter

View file

@ -5974,6 +5974,19 @@ mark_char_table (struct Lisp_Vector *ptr)
}
}
NO_INLINE /* To reduce stack depth in mark_object. */
static Lisp_Object
mark_compiled (struct Lisp_Vector *ptr)
{
int i, size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK;
VECTOR_MARK (ptr);
for (i = 0; i < size; i++)
if (i != COMPILED_CONSTANTS)
mark_object (ptr->contents[i]);
return size > COMPILED_CONSTANTS ? ptr->contents[COMPILED_CONSTANTS] : Qnil;
}
/* Mark the chain of overlays starting at PTR. */
static void
@ -6014,6 +6027,7 @@ mark_buffer (struct buffer *buffer)
/* Mark Lisp faces in the face cache C. */
NO_INLINE /* To reduce stack depth in mark_object. */
static void
mark_face_cache (struct face_cache *c)
{
@ -6036,6 +6050,24 @@ mark_face_cache (struct face_cache *c)
}
}
NO_INLINE /* To reduce stack depth in mark_object. */
static void
mark_localized_symbol (struct Lisp_Symbol *ptr)
{
struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (ptr);
Lisp_Object where = blv->where;
/* If the value is set up for a killed buffer or deleted
frame, restore it's global binding. If the value is
forwarded to a C variable, either it's not a Lisp_Object
var, or it's staticpro'd already. */
if ((BUFFERP (where) && !BUFFER_LIVE_P (XBUFFER (where)))
|| (FRAMEP (where) && !FRAME_LIVE_P (XFRAME (where))))
swap_in_global_binding (ptr);
mark_object (blv->where);
mark_object (blv->valcell);
mark_object (blv->defcell);
}
/* Remove killed buffers or items whose car is a killed buffer from
LIST, and mark other items. Return changed LIST, which is marked. */
@ -6180,22 +6212,13 @@ mark_object (Lisp_Object arg)
break;
case PVEC_COMPILED:
{ /* We could treat this just like a vector, but it is better
to save the COMPILED_CONSTANTS element for last and avoid
recursion there. */
int size = ptr->header.size & PSEUDOVECTOR_SIZE_MASK;
int i;
VECTOR_MARK (ptr);
for (i = 0; i < size; i++)
if (i != COMPILED_CONSTANTS)
mark_object (ptr->contents[i]);
if (size > COMPILED_CONSTANTS)
{
obj = ptr->contents[COMPILED_CONSTANTS];
goto loop;
}
}
/* Although we could treat this just like a vector, mark_compiled
returns the COMPILED_CONSTANTS element, which is marked at the
next iteration of goto-loop here. This is done to avoid a few
recursive calls to mark_object. */
obj = mark_compiled (ptr);
if (!NILP (obj))
goto loop;
break;
case PVEC_FRAME:
@ -6283,8 +6306,7 @@ mark_object (Lisp_Object arg)
case Lisp_Symbol:
{
register struct Lisp_Symbol *ptr = XSYMBOL (obj);
struct Lisp_Symbol *ptrx;
nextsym:
if (ptr->gcmarkbit)
break;
CHECK_ALLOCATED_AND_LIVE (live_symbol_p);
@ -6304,21 +6326,8 @@ mark_object (Lisp_Object arg)
break;
}
case SYMBOL_LOCALIZED:
{
struct Lisp_Buffer_Local_Value *blv = SYMBOL_BLV (ptr);
Lisp_Object where = blv->where;
/* If the value is set up for a killed buffer or deleted
frame, restore it's global binding. If the value is
forwarded to a C variable, either it's not a Lisp_Object
var, or it's staticpro'd already. */
if ((BUFFERP (where) && !BUFFER_LIVE_P (XBUFFER (where)))
|| (FRAMEP (where) && !FRAME_LIVE_P (XFRAME (where))))
swap_in_global_binding (ptr);
mark_object (blv->where);
mark_object (blv->valcell);
mark_object (blv->defcell);
break;
}
mark_localized_symbol (ptr);
break;
case SYMBOL_FORWARDED:
/* If the value is forwarded to a buffer or keyboard field,
these are marked when we see the corresponding object.
@ -6330,14 +6339,10 @@ mark_object (Lisp_Object arg)
if (!PURE_POINTER_P (XSTRING (ptr->name)))
MARK_STRING (XSTRING (ptr->name));
MARK_INTERVAL_TREE (string_intervals (ptr->name));
/* Inner loop to mark next symbol in this bucket, if any. */
ptr = ptr->next;
if (ptr)
{
ptrx = ptr; /* Use of ptrx avoids compiler bug on Sun. */
XSETSYMBOL (obj, ptrx);
goto loop;
}
goto nextsym;
}
break;