1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-01-25 05:52:42 -08:00

Use protected roots for constants in data section

This commit is contained in:
Helmut Eller 2025-12-15 08:27:34 +01:00
parent e0517ecbe6
commit bb0fef9e47
4 changed files with 211 additions and 21 deletions

View file

@ -551,6 +551,14 @@ typedef struct {
gcc_jit_rvalue *r_val;
} reloc_array_t;
#if defined HAVE_MPS && defined USE_PROTECTED_ROOTS
struct gc_root_area
{
Lisp_Object comp_unit;
Lisp_Object data_relocs[FLEXIBLE_ARRAY_MEMBER];
};
#endif
/* C side of the compiler context. */
typedef struct {
@ -2885,6 +2893,22 @@ emit_static_object (const char *name, Lisp_Object obj)
#pragma GCC diagnostic pop
static EMACS_INT
declare_serialized_constants (Lisp_Object container,
const char *text_symbol)
{
Lisp_Object tem = CALLNI (comp-data-container-l, container);
Lisp_Object constants = Fvconcat (1, &tem);
/* Emit the printed representation of the constants as a C string.
*/
emit_static_object (text_symbol, constants);
Lisp_Object idx = CALLNI (comp-data-container-idx, container);
Lisp_Object nconstants = CALLNI (hash-table-count, idx);
return XFIXNUM (nconstants);
}
/* Emit code/global variables for a constants vector.
CONTAINER is a comp-data-container Lisp struct from comp.el that
@ -2911,16 +2935,7 @@ static reloc_array_t
declare_imported_data_relocs (Lisp_Object container, const char *code_symbol,
const char *text_symbol, EMACS_INT *nconstants)
{
Lisp_Object tem = CALLNI (comp-data-container-l, container);
Lisp_Object constants = Fvconcat (1, &tem);
/* Emit the printed representation of the constants as a C string. */
emit_static_object (text_symbol, constants);
*nconstants = XFIXNUM (CALLNI (hash-table-count,
CALLNI (comp-data-container-idx,
container)));
*nconstants = declare_serialized_constants (container, text_symbol);
#ifdef USE_POINTER_TO_CONSTANTS
/* Lisp_Object *CODE_SYMBOL[1] */
EMACS_INT len = 1;
@ -2943,15 +2958,70 @@ declare_imported_data_relocs (Lisp_Object container, const char *code_symbol,
};
}
#if defined HAVE_MPS && defined USE_PROTECTED_ROOTS
static reloc_array_t
declare_gc_root_area (EMACS_INT n_data_relocs)
{
gcc_jit_type *d_relocs_type
= gcc_jit_context_new_array_type (comp.ctxt, NULL,
comp.lisp_obj_type,
n_data_relocs);
gcc_jit_field *comp_unit = gcc_jit_context_new_field (
comp.ctxt, NULL,
gcc_jit_type_get_aligned (comp.lisp_obj_type, getpagesize ()),
"comp_unit");
gcc_jit_field *d_relocs
= gcc_jit_context_new_field (comp.ctxt, NULL, d_relocs_type,
"data_relocs");
gcc_jit_field *fields[] = { comp_unit, d_relocs };
gcc_jit_struct *gc_root_area_struct
= gcc_jit_context_new_struct_type (comp.ctxt, NULL,
"gc_root_area",
ARRAYELTS (fields), fields);
gcc_jit_lvalue *gc_root_area_lval
= gcc_jit_context_new_global (comp.ctxt, NULL,
GCC_JIT_GLOBAL_INTERNAL,
gcc_jit_struct_as_type (
gc_root_area_struct),
"gc_root_area");
gcc_jit_rvalue *gc_root_area
= gcc_jit_lvalue_as_rvalue (gc_root_area_lval);
gcc_jit_rvalue *d_relocs_rval
= gcc_jit_rvalue_access_field (gc_root_area, NULL, d_relocs);
reloc_array_t result = { n_data_relocs, d_relocs_rval };
gcc_jit_rvalue *addr_rval =
gcc_jit_lvalue_get_address (gc_root_area_lval, NULL);
gcc_jit_function *get_addr_fun
= gcc_jit_context_new_function (comp.ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
gcc_jit_rvalue_get_type(addr_rval),
"gc_root_area_addr", 0, NULL, false);
gcc_jit_block *block =
gcc_jit_function_new_block(get_addr_fun, NULL);
gcc_jit_block_end_with_return (block, NULL, addr_rval);
return result;
}
#endif
static void
declare_imported_data (void)
{
#if defined HAVE_MPS && defined USE_PROTECTED_ROOTS
comp.n_data_relocs
= declare_serialized_constants (CALLNI (comp-ctxt-d-default,
Vcomp_ctxt),
TEXT_DATA_RELOC_SYM);
comp.data_relocs =
declare_gc_root_area (comp.n_data_relocs);
#else
/* Imported objects. */
comp.data_relocs =
declare_imported_data_relocs (CALLNI (comp-ctxt-d-default, Vcomp_ctxt),
DATA_RELOC_SYM,
TEXT_DATA_RELOC_SYM,
&comp.n_data_relocs);
#endif
comp.data_relocs_ephemeral =
declare_imported_data_relocs (CALLNI (comp-ctxt-d-ephemeral, Vcomp_ctxt),
DATA_RELOC_EPHEMERAL_SYM,
@ -3087,12 +3157,14 @@ emit_ctxt_code (void)
comp.bool_ptr_type,
F_SYMBOLS_WITH_POS_ENABLED_RELOC_SYM));
#if !(defined HAVE_MPS && defined USE_PROTECTED_ROOTS)
gcc_jit_context_new_global (
comp.ctxt,
NULL,
GCC_JIT_GLOBAL_EXPORTED,
comp.lisp_obj_type,
COMP_UNIT_SYM);
#endif
declare_imported_data ();
@ -5301,6 +5373,16 @@ load_static_obj (struct Lisp_Native_Comp_Unit *comp_u, const char *name)
}
#if defined HAVE_MPS && defined USE_PROTECTED_ROOTS
static struct gc_root_area *
find_gc_root_area (dynlib_handle_ptr handle)
{
struct gc_root_area *(*fun) (void)
= dynlib_sym (handle, "gc_root_area_addr");
return fun ? fun () : NULL;
}
#endif
/* Return false when something is wrong or true otherwise. */
static bool
@ -5308,7 +5390,12 @@ check_comp_unit_relocs (struct Lisp_Native_Comp_Unit *comp_u)
{
#ifndef USE_POINTER_TO_CONSTANTS
dynlib_handle_ptr handle = comp_u->handle;
#if defined HAVE_MPS && defined USE_PROTECTED_ROOTS
struct gc_root_area *gc_root_area = find_gc_root_area (handle);
Lisp_Object *data_relocs = gc_root_area->data_relocs;
#else
Lisp_Object *data_relocs = dynlib_sym (handle, DATA_RELOC_SYM);
#endif
EMACS_INT d_vec_len = XFIXNUM (Flength (comp_u->data_vec));
@ -5340,8 +5427,13 @@ unset_cu_load_ongoing (Lisp_Object comp_u)
*ROOT an MPS root for VEC, if one is needed. */
static void
#ifdef USE_POINTER_TO_CONSTANTS
setup_constants (comp_data_vector_t vec, Lisp_Object constants,
size_t *n, ptrdiff_t *pin)
size_t *n , ptrdiff_t *pin)
#else
setup_constants (comp_data_vector_t vec, Lisp_Object constants,
size_t *n)
#endif
{
*n = ASIZE (constants);
Lisp_Object *contents = XVECTOR (constants)->contents;
@ -5361,7 +5453,13 @@ setup_constants (comp_data_vector_t vec, Lisp_Object constants,
*pin = IGC_NO_PIN;
}
#else
memcpy (vec, contents, *n * sizeof *contents);
if (*n > 0)
{
#if defined HAVE_MPS && defined USE_PROTECTED_ROOTS
igc_root_create_n (vec, *n);
#endif
memcpy (vec, contents, *n * sizeof *contents);
}
#endif
}
@ -5374,10 +5472,18 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump,
Lisp_Object comp_u_lisp_obj;
XSETNATIVE_COMP_UNIT (comp_u_lisp_obj, comp_u);
#if defined HAVE_MPS && defined USE_PROTECTED_ROOTS
struct gc_root_area *gc_root_area = find_gc_root_area (handle);
if (!gc_root_area)
xsignal1 (Qnative_lisp_file_inconsistent, comp_u->file);
Lisp_Object *saved_cu = &gc_root_area->comp_unit;
#else
Lisp_Object *saved_cu = dynlib_sym (handle, COMP_UNIT_SYM);
if (!saved_cu)
xsignal1 (Qnative_lisp_file_inconsistent, comp_u->file);
#endif
comp_u->loaded_once = !NILP (*saved_cu);
comp_u->data_eph_relocs = dynlib_sym (handle, DATA_RELOC_EPHEMERAL_SYM);
/* While resurrecting from an image dump loading more than once the
@ -5399,7 +5505,7 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump,
}
else
{
#ifdef HAVE_MPS
#if defined HAVE_MPS && defined USE_POINTER_TO_CONSTANTS
comp_u->comp_unit = saved_cu;
comp_u->comp_unit_pin = igc_pin (comp_u);
comp_u->data_vec_pin = -1;
@ -5422,9 +5528,13 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump,
= dynlib_sym (handle,
late_load ? "late_top_level_run" : "top_level_run");
#if defined HAVE_MPS && defined USE_PROTECTED_ROOTS
comp_u->data_relocs = gc_root_area->data_relocs;
#else
/* Always set data_imp_relocs pointer in the compilation unit (in can be
used in 'dump_do_dump_relocation'). */
comp_u->data_relocs = dynlib_sym (handle, DATA_RELOC_SYM);
#endif
if (!comp_u->loaded_once)
{
@ -5464,8 +5574,28 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump,
USE_POINTER_TO_CONSTANTS, store a pointer to the contents of
the Lisp vector read, otherwise copy Lisp objects to the vector
created in the data segment. */
#ifdef USE_POINTER_TO_CONSTANTS
setup_constants (comp_u->data_relocs, comp_u->data_vec,
&comp_u->n_data_relocs, &comp_u->data_vec_pin);
#elif defined HAVE_MPS && defined USE_PROTECTED_ROOTS
{
size_t n = ASIZE (comp_u->data_vec);
Lisp_Object *contents = XVECTOR (comp_u->data_vec)->contents;
Lisp_Object *start = &gc_root_area->comp_unit;
igc_root_protected_n (1 + n, start);
memcpy (gc_root_area->data_relocs, contents, n * sizeof *contents);
{ /* probably not needed */
comp_u->n_data_relocs = n;
comp_u->data_relocs = gc_root_area->data_relocs;
/* data_vec doesn't seem to be needed any longer and we
could probably do: comp_u->data_vec = Qnil;
*/
}
}
#else
setup_constants (comp_u->data_relocs, comp_u->data_vec,
&comp_u->n_data_relocs);
#endif
}
if (!loading_dump)
@ -5475,9 +5605,14 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump,
eassert (NILP (comp_u->data_eph_vec));
comp_u->data_eph_vec
= load_static_obj (comp_u, TEXT_DATA_RELOC_EPHEMERAL_SYM);
#if defined HAVE_MPS && defined USE_POINTER_TO_CONSTANTS
setup_constants (comp_u->data_eph_relocs, comp_u->data_eph_vec,
&comp_u->n_data_eph_relocs,
&comp_u->data_eph_vec_pin);
#else
setup_constants (comp_u->data_eph_relocs, comp_u->data_eph_vec,
&comp_u->n_data_eph_relocs);
#endif
}
/* Executing this will perform all the expected environment
@ -5487,10 +5622,14 @@ load_comp_unit (struct Lisp_Native_Comp_Unit *comp_u, bool loading_dump,
if (!recursive_load)
{
# ifdef HAVE_MPS
# if defined HAVE_MPS && defined USE_POINTER_TO_CONSTANTS
igc_maybe_unpin (XVECTOR (comp_u->data_eph_vec)->contents,
&comp_u->data_eph_vec_pin);
# endif
#if defined HAVE_MPS && defined USE_PROTECTED_ROOTS
if (comp_u->n_data_eph_relocs > 0)
igc_destroy_root_with_start (comp_u->data_eph_relocs);
#endif
/* No longer needed after top-level code has run. Let the
vector be GC'd. */
comp_u->data_eph_vec = Qnil;
@ -5513,15 +5652,25 @@ unload_comp_unit (struct Lisp_Native_Comp_Unit *cu)
if (cu->handle == NULL)
return;
# ifdef HAVE_MPS
# if defined HAVE_MPS && defined USE_POINTER_TO_CONSTANTS
igc_unpin_comp_unit (cu);
# endif
# if defined HAVE_MPS && defined USE_PROTECTED_ROOTS
struct gc_root_area *gc_root_area = find_gc_root_area (cu->handle);
Lisp_Object *saved_cu = &gc_root_area->comp_unit;
# else
Lisp_Object *saved_cu = dynlib_sym (cu->handle, COMP_UNIT_SYM);
# endif
Lisp_Object this_cu;
XSETNATIVE_COMP_UNIT (this_cu, cu);
if (EQ (this_cu, *saved_cu))
*saved_cu = Qnil;
{
# if defined HAVE_MPS && defined USE_PROTECTED_ROOTS
igc_destroy_root_with_start (gc_root_area);
#endif
*saved_cu = Qnil;
}
dynlib_close (cu->handle);
}
@ -5692,7 +5841,7 @@ LATE-LOAD has to be non-nil when loading for deferred compilation. */)
struct Lisp_Native_Comp_Unit *comp_u = allocate_native_comp_unit ();
Lisp_Object encoded_filename = ENCODE_FILE (filename);
#ifdef HAVE_MPS
#if defined HAVE_MPS && defined USE_POINTER_TO_CONSTANTS
igc_init_pin (&comp_u->data_vec_pin);
igc_init_pin (&comp_u->data_eph_vec_pin);
igc_init_pin (&comp_u->comp_unit_pin);

View file

@ -60,7 +60,11 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
latency of incremental GC. */
#ifdef HAVE_MPS
#define USE_POINTER_TO_CONSTANTS 1
# if 0
# define USE_POINTER_TO_CONSTANTS 1
# else
# define USE_PROTECTED_ROOTS 1
# endif
#endif
#ifdef USE_POINTER_TO_CONSTANTS
@ -69,6 +73,15 @@ typedef Lisp_Object **comp_data_vector_t;
typedef Lisp_Object *comp_data_vector_t;
#endif
#ifndef HAVE_MPS
# ifdef USE_POINTER_TO_CONSTANTS
# error "!HAVE_MPS && USE_POINTER_TO_CONSTANTS"
# endif
# ifdef USE_PROTECTED_ROOTS
# error "!HAVE_MPS && USE_POINTER_TO_CONSTANTS"
# endif
#endif
struct Lisp_Native_Comp_Unit
{
struct vectorlike_header header;
@ -103,9 +116,11 @@ struct Lisp_Native_Comp_Unit
/* STUFF WE DO NOT DUMP!! */
#if !(defined HAVE_MPS && defined USE_PROTECTED_ROOTS)
/* Pointer into the data segment where the compilation unit is
stored (COMP_UNIT_SYM), and an exact root for it. */
Lisp_Object *comp_unit;
#endif
/* Pointers into data segment where constant vectors are found. */
comp_data_vector_t data_relocs;
@ -116,10 +131,12 @@ struct Lisp_Native_Comp_Unit
size_t n_data_relocs;
size_t n_data_eph_relocs;
#if defined HAVE_MPS && defined USE_POINTER_TO_CONSTANTS
/* Pins */
ptrdiff_t data_vec_pin;
ptrdiff_t data_eph_vec_pin;
ptrdiff_t comp_unit_pin;
#endif
bool loaded_once;
bool load_ongoing;

View file

@ -175,8 +175,8 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
# ifndef HASH_terminal_4E8E555B40
# error "struct terminal changed"
# endif
# ifndef HASH_Lisp_Native_Comp_Unit_876BE72D27
# error "struct Lisp_Native_Comp_Unit changed"
# ifndef HASH_Lisp_Native_Comp_Unit_0BDAB1A94D
# warning "struct Lisp_Native_Comp_Unit changed"
# endif
# ifndef HASH_pvec_type_1C9DBCD69F
# error "enum pvec_type changed"
@ -1133,7 +1133,10 @@ set_state (enum igc_state state)
break;
case IGC_STATE_DEAD:
igc_postmortem ();
/* old_state == IGC_STATE_DEAD if an assertion in
mps_arena_postmortem fails. */
if (old_state != IGC_STATE_DEAD)
igc_postmortem ();
terminate_due_to_signal (SIGABRT, INT_MAX);
break;
}
@ -3237,6 +3240,22 @@ igc_root_create_n (Lisp_Object start[], size_t n)
return root_create_exact_n (start, n);
}
void *
igc_root_protected_n (size_t n, Lisp_Object start[n])
{
igc_assert (start != NULL);
igc_assert (n > 0);
void *end = start + n;
mps_root_t root;
mps_res_t res
= mps_root_create_area (&root, global_igc->arena,
mps_rank_exact (), MPS_RM_PROT, start,
end, scan_exact, NULL);
IGC_CHECK_RES (res);
return register_root (global_igc, root, start, end, false,
"protected-n");
}
static igc_root_list *
root_find (void *start)
{
@ -3300,6 +3319,7 @@ igc_init_pin (ptrdiff_t *pin)
*pin = IGC_NO_PIN;
}
#ifdef USE_POINTER_TO_CONSTANTS
void
igc_unpin_comp_unit (struct Lisp_Native_Comp_Unit *cu)
{
@ -3309,6 +3329,7 @@ igc_unpin_comp_unit (struct Lisp_Native_Comp_Unit *cu)
igc_maybe_unpin (XVECTOR (cu->data_eph_vec)->contents, &cu->data_eph_vec_pin);
igc_maybe_unpin (cu, &cu->comp_unit_pin);
}
#endif
static mps_res_t
create_weak_ap (mps_ap_t *ap, struct igc_thread *t, bool weak)
@ -3817,7 +3838,9 @@ finalize_comp_unit (struct Lisp_Native_Comp_Unit *u)
unload_comp_unit (u);
u->data_eph_relocs = NULL;
u->data_relocs = NULL;
#ifndef USE_PROTECTED_ROOTS
u->comp_unit = NULL;
#endif
}
static void

View file

@ -171,6 +171,7 @@ struct igc_root_list *igc_root_create_exact_ptr (void *var_addr);
struct igc_root_list *igc_root_create_ambig (void *start, void *end,
const char *debug_name);
void *igc_root_create_n (Lisp_Object start[], size_t n);
void *igc_root_protected_n (size_t n, Lisp_Object start[n]);
void igc_destroy_root_with_start (void *start);
size_t igc_header_size (void);
char *igc_dump_finish_obj (void *client, enum igc_obj_type type,