mirror of
git://git.sv.gnu.org/emacs.git
synced 2025-12-05 22:20:24 -08:00
Re-port to 32-bit systems without alignment primitives
* configure.ac (ALIGNOF_INT, ALIGNOF_LONG, ALIGNOF_LONG_LONG): New variables. (emacs_cv_alignas_unavailable): Define if alignas and structure alignment primitives are unavailable. In such an environment, the MSB tagging scheme must be enabled, as must the GNU malloc. * msdos/sed2v2.inp: Adjust correspondingly. * src/alloc.c (union emacs_align_type): Remove types which contain flexible array members. The address of a field subsequent to an aggregate with flexible array members cannot validly be taken. (mark_memory) [!USE_LSB_TAG && !WIDE_EMACS_INT]: Strip type bits before scanning memory. * src/emacs.c (main): * src/eval.c (Fautoload_do_load): * src/fns.c (Frequire): Rename a number of illogically named fields. * src/lisp.h (ALIGNOF_EMACS_INT): Define to the natural alignment of EMACS_INT. (IDEAL_GCALIGNMENT): New macro. (USE_LSB_TAG): Disable if no alignment specifiers are available, WIDE_EMACS_INT is undefined, and the natural alignment of EMACS_INT falls short of LSB tagging's requirements. (gflags): Rename illogically named fields and don't define them as bitfields, which runs afoul of certain compiler issues. (will_dump_p, will_bootstrap_p, will_dump_with_pdumper_p) (dumped_with_pdumper_p): Adjust accordingly. * src/pdumper.c (VM_SUPPORTED): Define to 0 when !USE_LSB_TAG. It is better to read dump files into the heap by hand than to be supplied with an address that is not representable. (_dump_object_start_pseudovector): Rename to dump_object_start_pseudovector, to avoid encroaching on reserved names. (START_DUMP_PVEC): Adjust correspondingly. (dump_mmap_contiguous_vm): Preserve errno around failure cleanup. (dump_bitset_bit_set_p): Work around certain compiler issues. (pdumper_load) [!USE_LSB_TAG]: Reject dump file allocations that are not representable as Lisp_Objects. Tested on i386-unknown-solaris2.10, sparc-sun-solaris2.10.
This commit is contained in:
parent
57cef07710
commit
a5f8ce9f1e
8 changed files with 193 additions and 100 deletions
77
configure.ac
77
configure.ac
|
|
@ -3218,8 +3218,68 @@ AC_CACHE_CHECK(
|
||||||
fi])
|
fi])
|
||||||
doug_lea_malloc=$emacs_cv_var_doug_lea_malloc
|
doug_lea_malloc=$emacs_cv_var_doug_lea_malloc
|
||||||
|
|
||||||
|
AC_CHECK_ALIGNOF([int])
|
||||||
|
AC_CHECK_ALIGNOF([long])
|
||||||
|
AC_CHECK_ALIGNOF([long long])
|
||||||
|
AC_CHECK_SIZEOF([long])
|
||||||
|
|
||||||
|
AC_CACHE_CHECK([for struct alignment],
|
||||||
|
[emacs_cv_struct_alignment],
|
||||||
|
[AC_COMPILE_IFELSE(
|
||||||
|
[AC_LANG_PROGRAM([[#include <stddef.h>
|
||||||
|
struct s { char c; } __attribute__ ((aligned (8)));
|
||||||
|
struct t { char c; struct s s; };
|
||||||
|
char verify[offsetof (struct t, s) == 8 ? 1 : -1];
|
||||||
|
]])],
|
||||||
|
[emacs_cv_struct_alignment=yes],
|
||||||
|
[emacs_cv_struct_alignment=no])])
|
||||||
|
if test "$emacs_cv_struct_alignment" = yes; then
|
||||||
|
AC_DEFINE([HAVE_STRUCT_ATTRIBUTE_ALIGNED], [1],
|
||||||
|
[Define to 1 if 'struct __attribute__ ((aligned (N)))' aligns the
|
||||||
|
structure to an N-byte boundary.])
|
||||||
|
fi
|
||||||
|
|
||||||
system_malloc=yes
|
system_malloc=yes
|
||||||
|
|
||||||
|
# If it appears as if the system malloc can't be trusted to return
|
||||||
|
# adequately positioned memory, enable the GNU malloc, which more
|
||||||
|
# consistently provides allocations at low addresses, as is required for
|
||||||
|
# the pdumper to load dump files at a representable location.
|
||||||
|
AS_IF([test "$with_pdumper" = "yes" && test "$with_wide_int" != "yes"],
|
||||||
|
AC_CHECK_HEADERS([stdalign.h])
|
||||||
|
[AC_CACHE_CHECK([whether alignas is required yet unavailable],
|
||||||
|
[emacs_cv_alignas_unavailable],
|
||||||
|
[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
|
||||||
|
#ifdef HAVE_STDALIGN_H
|
||||||
|
#include <stdalign.h>
|
||||||
|
#endif
|
||||||
|
#include <limits.h>
|
||||||
|
]], [[
|
||||||
|
#define IDEAL_GCALIGNMENT 8
|
||||||
|
#if INTPTR_MAX <= INT_MAX && !defined WIDE_EMACS_INT
|
||||||
|
# define ALIGNOF_EMACS_INT ALIGNOF_INT
|
||||||
|
# elif INTPTR_MAX <= LONG_MAX && !defined WIDE_EMACS_INT
|
||||||
|
# define ALIGNOF_EMACS_INT ALIGNOF_LONG
|
||||||
|
# elif INTPTR_MAX <= LLONG_MAX
|
||||||
|
# define ALIGNOF_EMACS_INT ALIGNOF_LONG_LONG
|
||||||
|
# else
|
||||||
|
# error "INTPTR_MAX too large"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (ALIGNOF_EMACS_INT < IDEAL_GCALIGNMENT && !defined alignas \
|
||||||
|
&& !defined HAVE_STRUCT_ATTRIBUTE_ALIGNED \
|
||||||
|
&& !defined __alignas_is_defined \
|
||||||
|
&& __STDC_VERSION__ < 202311 && __cplusplus < 201103)
|
||||||
|
#error "!USE_LSB_TAG required"
|
||||||
|
#endif
|
||||||
|
]])], [emacs_cv_alignas_unavailable=no],
|
||||||
|
[emacs_cv_alignas_unavailable=yes])])
|
||||||
|
AS_IF([test "$emacs_cv_alignas_unavailable" = "yes"],
|
||||||
|
[system_malloc=no
|
||||||
|
AC_MSG_WARN([The GNU memory manager will be enabled as your system
|
||||||
|
does not guarantee that the portable dumper can allocate memory at a suitably
|
||||||
|
low address.])])])
|
||||||
|
|
||||||
dnl This must be before the test of $ac_cv_func_sbrk below.
|
dnl This must be before the test of $ac_cv_func_sbrk below.
|
||||||
AC_CHECK_FUNCS_ONCE([sbrk])
|
AC_CHECK_FUNCS_ONCE([sbrk])
|
||||||
|
|
||||||
|
|
@ -5823,7 +5883,6 @@ AC_SUBST([HAVE_LIBSECCOMP])
|
||||||
AC_SUBST([LIBSECCOMP_LIBS])
|
AC_SUBST([LIBSECCOMP_LIBS])
|
||||||
AC_SUBST([LIBSECCOMP_CFLAGS])
|
AC_SUBST([LIBSECCOMP_CFLAGS])
|
||||||
|
|
||||||
AC_CHECK_SIZEOF([long])
|
|
||||||
SIZEOF_LONG="$ac_cv_sizeof_long"
|
SIZEOF_LONG="$ac_cv_sizeof_long"
|
||||||
AC_SUBST([SIZEOF_LONG])
|
AC_SUBST([SIZEOF_LONG])
|
||||||
|
|
||||||
|
|
@ -7186,22 +7245,6 @@ else
|
||||||
fi
|
fi
|
||||||
AC_SUBST([LIBXMENU])
|
AC_SUBST([LIBXMENU])
|
||||||
|
|
||||||
AC_CACHE_CHECK([for struct alignment],
|
|
||||||
[emacs_cv_struct_alignment],
|
|
||||||
[AC_COMPILE_IFELSE(
|
|
||||||
[AC_LANG_PROGRAM([[#include <stddef.h>
|
|
||||||
struct s { char c; } __attribute__ ((aligned (8)));
|
|
||||||
struct t { char c; struct s s; };
|
|
||||||
char verify[offsetof (struct t, s) == 8 ? 1 : -1];
|
|
||||||
]])],
|
|
||||||
[emacs_cv_struct_alignment=yes],
|
|
||||||
[emacs_cv_struct_alignment=no])])
|
|
||||||
if test "$emacs_cv_struct_alignment" = yes; then
|
|
||||||
AC_DEFINE([HAVE_STRUCT_ATTRIBUTE_ALIGNED], [1],
|
|
||||||
[Define to 1 if 'struct __attribute__ ((aligned (N)))' aligns the
|
|
||||||
structure to an N-byte boundary.])
|
|
||||||
fi
|
|
||||||
|
|
||||||
AC_C_RESTRICT
|
AC_C_RESTRICT
|
||||||
AC_C_TYPEOF
|
AC_C_TYPEOF
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -140,6 +140,9 @@ s/^#undef HAVE_DECL_STRTOIMAX *$/#define HAVE_DECL_STRTOIMAX 1/
|
||||||
s/^#undef HAVE_PDUMPER *$/#define HAVE_PDUMPER 1/
|
s/^#undef HAVE_PDUMPER *$/#define HAVE_PDUMPER 1/
|
||||||
s/^#undef HAVE_STRTOLL *$/#define HAVE_STRTOLL 1/
|
s/^#undef HAVE_STRTOLL *$/#define HAVE_STRTOLL 1/
|
||||||
s/^#undef HAVE_STRTOULL *$/#define HAVE_STRTOULL 1/
|
s/^#undef HAVE_STRTOULL *$/#define HAVE_STRTOULL 1/
|
||||||
|
s/^#undef ALIGNOF_INT *$/s/^.*$/#define ALIGNOF_INT 4/
|
||||||
|
s/^#undef ALIGNOF_LONG *$/s/^.*$/#define ALIGNOF_LONG 4/
|
||||||
|
s/^#undef ALIGNOF_LONG_LONG *$/s/^.*$/#define ALIGNOF_LONG_LONG 4/
|
||||||
/^#undef HAVE_STRUCT_DIRENT_D_TYPE *$/c\
|
/^#undef HAVE_STRUCT_DIRENT_D_TYPE *$/c\
|
||||||
#if __DJGPP__ + (__DJGPP_MINOR__ >= 5) >= 3\
|
#if __DJGPP__ + (__DJGPP_MINOR__ >= 5) >= 3\
|
||||||
#define HAVE_STRUCT_DIRENT_D_TYPE 1/\
|
#define HAVE_STRUCT_DIRENT_D_TYPE 1/\
|
||||||
|
|
|
||||||
22
src/alloc.c
22
src/alloc.c
|
|
@ -150,8 +150,6 @@ union emacs_align_type
|
||||||
{
|
{
|
||||||
struct frame frame;
|
struct frame frame;
|
||||||
struct Lisp_Bignum Lisp_Bignum;
|
struct Lisp_Bignum Lisp_Bignum;
|
||||||
struct Lisp_Bool_Vector Lisp_Bool_Vector;
|
|
||||||
struct Lisp_Char_Table Lisp_Char_Table;
|
|
||||||
struct Lisp_CondVar Lisp_CondVar;
|
struct Lisp_CondVar Lisp_CondVar;
|
||||||
struct Lisp_Finalizer Lisp_Finalizer;
|
struct Lisp_Finalizer Lisp_Finalizer;
|
||||||
struct Lisp_Float Lisp_Float;
|
struct Lisp_Float Lisp_Float;
|
||||||
|
|
@ -160,21 +158,25 @@ union emacs_align_type
|
||||||
struct Lisp_Misc_Ptr Lisp_Misc_Ptr;
|
struct Lisp_Misc_Ptr Lisp_Misc_Ptr;
|
||||||
struct Lisp_Mutex Lisp_Mutex;
|
struct Lisp_Mutex Lisp_Mutex;
|
||||||
struct Lisp_Overlay Lisp_Overlay;
|
struct Lisp_Overlay Lisp_Overlay;
|
||||||
struct Lisp_Sub_Char_Table Lisp_Sub_Char_Table;
|
|
||||||
struct Lisp_Subr Lisp_Subr;
|
struct Lisp_Subr Lisp_Subr;
|
||||||
struct Lisp_Sqlite Lisp_Sqlite;
|
struct Lisp_Sqlite Lisp_Sqlite;
|
||||||
struct Lisp_User_Ptr Lisp_User_Ptr;
|
struct Lisp_User_Ptr Lisp_User_Ptr;
|
||||||
struct Lisp_Vector Lisp_Vector;
|
|
||||||
struct terminal terminal;
|
struct terminal terminal;
|
||||||
struct thread_state thread_state;
|
struct thread_state thread_state;
|
||||||
struct window window;
|
struct window window;
|
||||||
|
|
||||||
/* Omit the following since they would require including process.h
|
/* Omit the following since they would require including process.h
|
||||||
etc. In practice their alignments never exceed that of the
|
etc, or because they are defined with flexible array members, which
|
||||||
structs already listed. */
|
are rejected by some C99 compilers when this union subsequently
|
||||||
|
appears in an `alignof' expression. In practice their alignments
|
||||||
|
never exceed that of the structs already listed. */
|
||||||
#if 0
|
#if 0
|
||||||
|
struct Lisp_Bool_Vector Lisp_Bool_Vector;
|
||||||
|
struct Lisp_Char_Table Lisp_Char_Table;
|
||||||
|
struct Lisp_Sub_Char_Table Lisp_Sub_Char_Table;
|
||||||
struct Lisp_Module_Function Lisp_Module_Function;
|
struct Lisp_Module_Function Lisp_Module_Function;
|
||||||
struct Lisp_Process Lisp_Process;
|
struct Lisp_Process Lisp_Process;
|
||||||
|
struct Lisp_Vector Lisp_Vector;
|
||||||
struct save_window_data save_window_data;
|
struct save_window_data save_window_data;
|
||||||
struct scroll_bar scroll_bar;
|
struct scroll_bar scroll_bar;
|
||||||
struct xwidget_view xwidget_view;
|
struct xwidget_view xwidget_view;
|
||||||
|
|
@ -5167,14 +5169,20 @@ mark_memory (void const *start, void const *end)
|
||||||
for (pp = start; (void const *) pp < end; pp += GC_POINTER_ALIGNMENT)
|
for (pp = start; (void const *) pp < end; pp += GC_POINTER_ALIGNMENT)
|
||||||
{
|
{
|
||||||
void *p = *(void *const *) pp;
|
void *p = *(void *const *) pp;
|
||||||
|
intptr_t ip;
|
||||||
|
|
||||||
|
#if !USE_LSB_TAG && !defined WIDE_EMACS_INT
|
||||||
|
ip = (intptr_t) p;
|
||||||
|
mark_maybe_pointer ((void *) (ip & VALMASK), false);
|
||||||
|
#else /* USE_LSB_TAG || WIDE_EMACS_INT */
|
||||||
mark_maybe_pointer (p, false);
|
mark_maybe_pointer (p, false);
|
||||||
|
#endif /* USE_LSB_TAG || WIDE_EMACS_INT */
|
||||||
|
|
||||||
/* Unmask any struct Lisp_Symbol pointer that make_lisp_symbol
|
/* Unmask any struct Lisp_Symbol pointer that make_lisp_symbol
|
||||||
previously disguised by adding the address of 'lispsym'.
|
previously disguised by adding the address of 'lispsym'.
|
||||||
On a host with 32-bit pointers and 64-bit Lisp_Objects,
|
On a host with 32-bit pointers and 64-bit Lisp_Objects,
|
||||||
a Lisp_Object might be split into registers saved into
|
a Lisp_Object might be split into registers saved into
|
||||||
non-adjacent words and P might be the low-order word's value. */
|
non-adjacent words and P might be the low-order word's value. */
|
||||||
intptr_t ip;
|
|
||||||
ckd_add (&ip, (intptr_t) p, (intptr_t) lispsym);
|
ckd_add (&ip, (intptr_t) p, (intptr_t) lispsym);
|
||||||
mark_maybe_pointer ((void *) ip, true);
|
mark_maybe_pointer ((void *) ip, true);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
12
src/emacs.c
12
src/emacs.c
|
|
@ -1311,13 +1311,11 @@ android_emacs_init (int argc, char **argv, char *dump_file)
|
||||||
if (!initialized && temacs)
|
if (!initialized && temacs)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_PDUMPER
|
#ifdef HAVE_PDUMPER
|
||||||
if (strcmp (temacs, "pdump") == 0 ||
|
if (!strcmp (temacs, "pdump") || !strcmp (temacs, "pbootstrap"))
|
||||||
strcmp (temacs, "pbootstrap") == 0)
|
gflags.will_dump_with_pdumper = true;
|
||||||
gflags.will_dump_with_pdumper_ = true;
|
if (!strcmp (temacs, "pbootstrap"))
|
||||||
if (strcmp (temacs, "pbootstrap") == 0)
|
gflags.will_bootstrap = true;
|
||||||
gflags.will_bootstrap_ = true;
|
gflags.will_dump = will_dump_with_pdumper_p ();
|
||||||
gflags.will_dump_ =
|
|
||||||
will_dump_with_pdumper_p ();
|
|
||||||
if (will_dump_p ())
|
if (will_dump_p ())
|
||||||
dump_mode = temacs;
|
dump_mode = temacs;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -2389,7 +2389,7 @@ it defines a macro. */)
|
||||||
{
|
{
|
||||||
/* Avoid landing here recursively while outputting the
|
/* Avoid landing here recursively while outputting the
|
||||||
backtrace from the error. */
|
backtrace from the error. */
|
||||||
gflags.will_dump_ = false;
|
gflags.will_dump = false;
|
||||||
error ("Attempt to autoload %s while preparing to dump",
|
error ("Attempt to autoload %s while preparing to dump",
|
||||||
SDATA (SYMBOL_NAME (funname)));
|
SDATA (SYMBOL_NAME (funname)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3780,7 +3780,7 @@ FILENAME are suppressed. */)
|
||||||
{
|
{
|
||||||
/* Avoid landing here recursively while outputting the
|
/* Avoid landing here recursively while outputting the
|
||||||
backtrace from the error. */
|
backtrace from the error. */
|
||||||
gflags.will_dump_ = false;
|
gflags.will_dump = false;
|
||||||
error ("(require %s) while preparing to dump",
|
error ("(require %s) while preparing to dump",
|
||||||
SDATA (SYMBOL_NAME (feature)));
|
SDATA (SYMBOL_NAME (feature)));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
34
src/lisp.h
34
src/lisp.h
|
|
@ -89,18 +89,21 @@ DEFINE_GDB_SYMBOL_END (GCTYPEBITS)
|
||||||
typedef int EMACS_INT;
|
typedef int EMACS_INT;
|
||||||
typedef unsigned int EMACS_UINT;
|
typedef unsigned int EMACS_UINT;
|
||||||
enum { EMACS_INT_WIDTH = INT_WIDTH, EMACS_UINT_WIDTH = UINT_WIDTH };
|
enum { EMACS_INT_WIDTH = INT_WIDTH, EMACS_UINT_WIDTH = UINT_WIDTH };
|
||||||
|
# define ALIGNOF_EMACS_INT ALIGNOF_INT
|
||||||
# define EMACS_INT_MAX INT_MAX
|
# define EMACS_INT_MAX INT_MAX
|
||||||
# define pI ""
|
# define pI ""
|
||||||
# elif INTPTR_MAX <= LONG_MAX && !defined WIDE_EMACS_INT
|
# elif INTPTR_MAX <= LONG_MAX && !defined WIDE_EMACS_INT
|
||||||
typedef long int EMACS_INT;
|
typedef long int EMACS_INT;
|
||||||
typedef unsigned long EMACS_UINT;
|
typedef unsigned long EMACS_UINT;
|
||||||
enum { EMACS_INT_WIDTH = LONG_WIDTH, EMACS_UINT_WIDTH = ULONG_WIDTH };
|
enum { EMACS_INT_WIDTH = LONG_WIDTH, EMACS_UINT_WIDTH = ULONG_WIDTH };
|
||||||
|
# define ALIGNOF_EMACS_INT ALIGNOF_LONG
|
||||||
# define EMACS_INT_MAX LONG_MAX
|
# define EMACS_INT_MAX LONG_MAX
|
||||||
# define pI "l"
|
# define pI "l"
|
||||||
# elif INTPTR_MAX <= LLONG_MAX
|
# elif INTPTR_MAX <= LLONG_MAX
|
||||||
typedef long long int EMACS_INT;
|
typedef long long int EMACS_INT;
|
||||||
typedef unsigned long long int EMACS_UINT;
|
typedef unsigned long long int EMACS_UINT;
|
||||||
enum { EMACS_INT_WIDTH = LLONG_WIDTH, EMACS_UINT_WIDTH = ULLONG_WIDTH };
|
enum { EMACS_INT_WIDTH = LLONG_WIDTH, EMACS_UINT_WIDTH = ULLONG_WIDTH };
|
||||||
|
# define ALIGNOF_EMACS_INT ALIGNOF_LONG_LONG
|
||||||
# define EMACS_INT_MAX LLONG_MAX
|
# define EMACS_INT_MAX LLONG_MAX
|
||||||
/* MinGW supports %lld only if __USE_MINGW_ANSI_STDIO is non-zero,
|
/* MinGW supports %lld only if __USE_MINGW_ANSI_STDIO is non-zero,
|
||||||
which is arranged by config.h, and (for mingw.org) if GCC is 6.0 or
|
which is arranged by config.h, and (for mingw.org) if GCC is 6.0 or
|
||||||
|
|
@ -237,13 +240,26 @@ DEFINE_GDB_SYMBOL_END (INTTYPEBITS)
|
||||||
expression involving VAL_MAX. */
|
expression involving VAL_MAX. */
|
||||||
#define VAL_MAX (EMACS_INT_MAX >> (GCTYPEBITS - 1))
|
#define VAL_MAX (EMACS_INT_MAX >> (GCTYPEBITS - 1))
|
||||||
|
|
||||||
|
/* The alignment ideally required of objects subject to garbage
|
||||||
|
collection. (In the sense that it would be ideal for such an
|
||||||
|
alignment to be available to enable LSB tagging.) */
|
||||||
|
#define IDEAL_GCALIGNMENT 8
|
||||||
|
|
||||||
/* Whether the least-significant bits of an EMACS_INT contain the tag.
|
/* Whether the least-significant bits of an EMACS_INT contain the tag.
|
||||||
On hosts where pointers-as-ints do not exceed VAL_MAX / 2, USE_LSB_TAG is:
|
On hosts where pointers-as-ints do not exceed VAL_MAX / 2, USE_LSB_TAG is:
|
||||||
a. unnecessary, because the top bits of an EMACS_INT are unused, and
|
a. unnecessary, because the top bits of an EMACS_INT are unused, and
|
||||||
b. slower, because it typically requires extra masking.
|
b. slower, because it typically requires extra masking.
|
||||||
So, USE_LSB_TAG is true only on hosts where it might be useful. */
|
So, USE_LSB_TAG is true only on hosts where it might be useful. */
|
||||||
DEFINE_GDB_SYMBOL_BEGIN (bool, USE_LSB_TAG)
|
DEFINE_GDB_SYMBOL_BEGIN (bool, USE_LSB_TAG)
|
||||||
|
#if (ALIGNOF_EMACS_INT < IDEAL_GCALIGNMENT && !defined alignas \
|
||||||
|
&& !defined WIDE_EMACS_INT \
|
||||||
|
&& !defined HAVE_STRUCT_ATTRIBUTE_ALIGNED \
|
||||||
|
&& !defined __alignas_is_defined \
|
||||||
|
&& __STDC_VERSION__ < 202311 && __cplusplus < 201103)
|
||||||
|
#define USE_LSB_TAG 0
|
||||||
|
#else /* EMACS_INT_WIDTH >= GCALIGNMENT || defined alignas ... */
|
||||||
#define USE_LSB_TAG (VAL_MAX / 2 < INTPTR_MAX)
|
#define USE_LSB_TAG (VAL_MAX / 2 < INTPTR_MAX)
|
||||||
|
#endif /* EMACS_INT_WIDTH >= GCALIGNMENT || defined alignas ... */
|
||||||
DEFINE_GDB_SYMBOL_END (USE_LSB_TAG)
|
DEFINE_GDB_SYMBOL_END (USE_LSB_TAG)
|
||||||
|
|
||||||
/* Mask for the value (as opposed to the type bits) of a Lisp object. */
|
/* Mask for the value (as opposed to the type bits) of a Lisp object. */
|
||||||
|
|
@ -262,7 +278,7 @@ DEFINE_GDB_SYMBOL_END (VALMASK)
|
||||||
USE_LSB_TAG, 1 otherwise. It must be a literal integer constant,
|
USE_LSB_TAG, 1 otherwise. It must be a literal integer constant,
|
||||||
for older versions of GCC (through at least 4.9). */
|
for older versions of GCC (through at least 4.9). */
|
||||||
#if USE_LSB_TAG
|
#if USE_LSB_TAG
|
||||||
# define GCALIGNMENT 8
|
# define GCALIGNMENT IDEAL_GCALIGNMENT
|
||||||
# if GCALIGNMENT != 1 << GCTYPEBITS
|
# if GCALIGNMENT != 1 << GCTYPEBITS
|
||||||
# error "GCALIGNMENT and GCTYPEBITS are inconsistent"
|
# error "GCALIGNMENT and GCTYPEBITS are inconsistent"
|
||||||
# endif
|
# endif
|
||||||
|
|
@ -629,15 +645,15 @@ extern bool initialized;
|
||||||
extern struct gflags
|
extern struct gflags
|
||||||
{
|
{
|
||||||
/* True means this Emacs instance was born to dump. */
|
/* True means this Emacs instance was born to dump. */
|
||||||
bool will_dump_ : 1;
|
bool will_dump;
|
||||||
bool will_bootstrap_ : 1;
|
bool will_bootstrap;
|
||||||
#ifdef HAVE_PDUMPER
|
#ifdef HAVE_PDUMPER
|
||||||
/* Set in an Emacs process that will likely dump with pdumper; all
|
/* Set in an Emacs process that will likely dump with pdumper; all
|
||||||
Emacs processes may dump with pdumper, however. */
|
Emacs processes may dump with pdumper, however. */
|
||||||
bool will_dump_with_pdumper_ : 1;
|
bool will_dump_with_pdumper;
|
||||||
/* Set in an Emacs process that has been restored from a portable
|
/* Set in an Emacs process that has been restored from a portable
|
||||||
dump. */
|
dump. */
|
||||||
bool dumped_with_pdumper_ : 1;
|
bool dumped_with_pdumper;
|
||||||
#endif
|
#endif
|
||||||
} gflags;
|
} gflags;
|
||||||
|
|
||||||
|
|
@ -645,7 +661,7 @@ INLINE bool
|
||||||
will_dump_p (void)
|
will_dump_p (void)
|
||||||
{
|
{
|
||||||
#if HAVE_PDUMPER
|
#if HAVE_PDUMPER
|
||||||
return gflags.will_dump_;
|
return gflags.will_dump;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -655,7 +671,7 @@ INLINE bool
|
||||||
will_bootstrap_p (void)
|
will_bootstrap_p (void)
|
||||||
{
|
{
|
||||||
#if HAVE_PDUMPER
|
#if HAVE_PDUMPER
|
||||||
return gflags.will_bootstrap_;
|
return gflags.will_bootstrap;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -665,7 +681,7 @@ INLINE bool
|
||||||
will_dump_with_pdumper_p (void)
|
will_dump_with_pdumper_p (void)
|
||||||
{
|
{
|
||||||
#if HAVE_PDUMPER
|
#if HAVE_PDUMPER
|
||||||
return gflags.will_dump_with_pdumper_;
|
return gflags.will_dump_with_pdumper;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -675,7 +691,7 @@ INLINE bool
|
||||||
dumped_with_pdumper_p (void)
|
dumped_with_pdumper_p (void)
|
||||||
{
|
{
|
||||||
#if HAVE_PDUMPER
|
#if HAVE_PDUMPER
|
||||||
return gflags.dumped_with_pdumper_;
|
return gflags.dumped_with_pdumper;
|
||||||
#else
|
#else
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
141
src/pdumper.c
141
src/pdumper.c
|
|
@ -77,7 +77,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
|
||||||
#define VM_POSIX 1
|
#define VM_POSIX 1
|
||||||
#define VM_MS_WINDOWS 2
|
#define VM_MS_WINDOWS 2
|
||||||
|
|
||||||
#if defined (HAVE_MMAP) && defined (MAP_FIXED)
|
#if !USE_LSB_TAG
|
||||||
|
# define VM_SUPPORTED 0
|
||||||
|
#elif defined (HAVE_MMAP) && defined (MAP_FIXED)
|
||||||
# define VM_SUPPORTED VM_POSIX
|
# define VM_SUPPORTED VM_POSIX
|
||||||
# if !defined (MAP_POPULATE) && defined (MAP_PREFAULT_READ)
|
# if !defined (MAP_POPULATE) && defined (MAP_PREFAULT_READ)
|
||||||
# define MAP_POPULATE MAP_PREFAULT_READ
|
# define MAP_POPULATE MAP_PREFAULT_READ
|
||||||
|
|
@ -1964,9 +1966,9 @@ dump_field_emacs_ptr (struct dump_context *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_dump_object_start_pseudovector (struct dump_context *ctx,
|
dump_object_start_pseudovector (struct dump_context *ctx,
|
||||||
union vectorlike_header *out_hdr,
|
union vectorlike_header *out_hdr,
|
||||||
const union vectorlike_header *in_hdr)
|
const union vectorlike_header *in_hdr)
|
||||||
{
|
{
|
||||||
eassert (in_hdr->size & PSEUDOVECTOR_FLAG);
|
eassert (in_hdr->size & PSEUDOVECTOR_FLAG);
|
||||||
ptrdiff_t vec_size = vectorlike_nbytes (in_hdr);
|
ptrdiff_t vec_size = vectorlike_nbytes (in_hdr);
|
||||||
|
|
@ -1976,9 +1978,9 @@ _dump_object_start_pseudovector (struct dump_context *ctx,
|
||||||
|
|
||||||
/* Need a macro for alloca. */
|
/* Need a macro for alloca. */
|
||||||
#define START_DUMP_PVEC(ctx, hdr, type, out) \
|
#define START_DUMP_PVEC(ctx, hdr, type, out) \
|
||||||
const union vectorlike_header *_in_hdr = (hdr); \
|
const union vectorlike_header *in_hdr = (hdr); \
|
||||||
type *out = alloca (vectorlike_nbytes (_in_hdr)); \
|
type *out = alloca (vectorlike_nbytes (in_hdr)); \
|
||||||
_dump_object_start_pseudovector (ctx, &out->header, _in_hdr)
|
dump_object_start_pseudovector (ctx, &out->header, in_hdr)
|
||||||
|
|
||||||
static dump_off
|
static dump_off
|
||||||
finish_dump_pvec (struct dump_context *ctx,
|
finish_dump_pvec (struct dump_context *ctx,
|
||||||
|
|
@ -3994,14 +3996,14 @@ dump_do_fixup (struct dump_context *ctx,
|
||||||
Lisp_Object fixup,
|
Lisp_Object fixup,
|
||||||
Lisp_Object prev_fixup)
|
Lisp_Object prev_fixup)
|
||||||
{
|
{
|
||||||
enum dump_fixup_type type =
|
enum dump_fixup_type type
|
||||||
(enum dump_fixup_type) XFIXNUM (dump_pop (&fixup));
|
= (enum dump_fixup_type) XFIXNUM (dump_pop (&fixup));
|
||||||
dump_off dump_fixup_offset = dump_off_from_lisp (dump_pop (&fixup));
|
dump_off dump_fixup_offset = dump_off_from_lisp (dump_pop (&fixup));
|
||||||
#ifdef ENABLE_CHECKING
|
#ifdef ENABLE_CHECKING
|
||||||
if (!NILP (prev_fixup))
|
if (!NILP (prev_fixup))
|
||||||
{
|
{
|
||||||
dump_off prev_dump_fixup_offset =
|
dump_off prev_dump_fixup_offset
|
||||||
dump_off_from_lisp (XCAR (XCDR (prev_fixup)));
|
= dump_off_from_lisp (XCAR (XCDR (prev_fixup)));
|
||||||
eassert (dump_fixup_offset - prev_dump_fixup_offset
|
eassert (dump_fixup_offset - prev_dump_fixup_offset
|
||||||
>= sizeof (void *));
|
>= sizeof (void *));
|
||||||
}
|
}
|
||||||
|
|
@ -4618,23 +4620,8 @@ dump_anonymous_allocate_posix (void *base,
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Perform anonymous memory allocation. */
|
/* Undo the effect of `dump_reserve_address_space'. */
|
||||||
static void *
|
|
||||||
dump_anonymous_allocate (void *base,
|
|
||||||
const size_t size,
|
|
||||||
enum dump_memory_protection protection)
|
|
||||||
{
|
|
||||||
#if VM_SUPPORTED == VM_POSIX
|
|
||||||
return dump_anonymous_allocate_posix (base, size, protection);
|
|
||||||
#elif VM_SUPPORTED == VM_MS_WINDOWS
|
|
||||||
return dump_anonymous_allocate_w32 (base, size, protection);
|
|
||||||
#else
|
|
||||||
errno = ENOSYS;
|
|
||||||
return NULL;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Undo the effect of dump_reserve_address_space(). */
|
|
||||||
static void
|
static void
|
||||||
dump_anonymous_release (void *addr, size_t size)
|
dump_anonymous_release (void *addr, size_t size)
|
||||||
{
|
{
|
||||||
|
|
@ -4653,6 +4640,26 @@ dump_anonymous_release (void *addr, size_t size)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Perform anonymous memory allocation. */
|
||||||
|
static void *
|
||||||
|
dump_anonymous_allocate (void *base,
|
||||||
|
const size_t size,
|
||||||
|
enum dump_memory_protection protection)
|
||||||
|
{
|
||||||
|
void *val;
|
||||||
|
|
||||||
|
#if VM_SUPPORTED == VM_POSIX
|
||||||
|
val = dump_anonymous_allocate_posix (base, size, protection);
|
||||||
|
#elif VM_SUPPORTED == VM_MS_WINDOWS
|
||||||
|
val = dump_anonymous_allocate_w32 (base, size, protection);
|
||||||
|
#else
|
||||||
|
errno = ENOSYS;
|
||||||
|
val = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
#if VM_SUPPORTED == VM_MS_WINDOWS
|
#if VM_SUPPORTED == VM_MS_WINDOWS
|
||||||
static void *
|
static void *
|
||||||
dump_map_file_w32 (void *base, int fd, off_t offset, size_t size,
|
dump_map_file_w32 (void *base, int fd, off_t offset, size_t size,
|
||||||
|
|
@ -4824,20 +4831,20 @@ static void
|
||||||
dump_discard_mem (void *mem, size_t size)
|
dump_discard_mem (void *mem, size_t size)
|
||||||
{
|
{
|
||||||
#if VM_SUPPORTED == VM_MS_WINDOWS
|
#if VM_SUPPORTED == VM_MS_WINDOWS
|
||||||
/* Discard COWed pages. */
|
/* Discard COWed pages. */
|
||||||
(void) VirtualFree (mem, size, MEM_DECOMMIT);
|
(void) VirtualFree (mem, size, MEM_DECOMMIT);
|
||||||
/* Release the commit charge for the mapping. */
|
/* Release the commit charge for the mapping. */
|
||||||
DWORD old_prot;
|
DWORD old_prot;
|
||||||
(void) VirtualProtect (mem, size, PAGE_NOACCESS, &old_prot);
|
(void) VirtualProtect (mem, size, PAGE_NOACCESS, &old_prot);
|
||||||
#elif VM_SUPPORTED == VM_POSIX
|
#elif VM_SUPPORTED == VM_POSIX
|
||||||
# ifdef HAVE_POSIX_MADVISE
|
# ifdef HAVE_POSIX_MADVISE
|
||||||
/* Discard COWed pages. */
|
/* Discard COWed pages. */
|
||||||
(void) posix_madvise (mem, size, POSIX_MADV_DONTNEED);
|
(void) posix_madvise (mem, size, POSIX_MADV_DONTNEED);
|
||||||
# elif defined HAVE_MADVISE
|
# elif defined HAVE_MADVISE
|
||||||
(void) madvise (mem, size, MADV_DONTNEED);
|
(void) madvise (mem, size, MADV_DONTNEED);
|
||||||
#endif
|
#endif
|
||||||
/* Release the commit charge for the mapping. */
|
/* Release the commit charge for the mapping. */
|
||||||
(void) mprotect (mem, size, PROT_NONE);
|
(void) mprotect (mem, size, PROT_NONE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4959,21 +4966,23 @@ dump_mmap_release_vm (struct dump_memory_map *map)
|
||||||
static bool
|
static bool
|
||||||
needs_mmap_retry_p (void)
|
needs_mmap_retry_p (void)
|
||||||
{
|
{
|
||||||
#if defined CYGWIN || VM_SUPPORTED == VM_MS_WINDOWS || defined _AIX
|
#if defined CYGWIN || VM_SUPPORTED == VM_MS_WINDOWS \
|
||||||
|
|| defined _AIX
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else /* !CYGWIN && VM_SUPPORTED != VM_MS_WINDOWS && !_AIX */
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif /* !CYGWIN && VM_SUPPORTED != VM_MS_WINDOWS && !_AIX */
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps,
|
dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps,
|
||||||
size_t total_size)
|
size_t total_size)
|
||||||
{
|
{
|
||||||
|
int save_errno;
|
||||||
bool ret = false;
|
bool ret = false;
|
||||||
void *resv = NULL;
|
void *resv = NULL;
|
||||||
bool retry = false;
|
bool retry = false;
|
||||||
const bool need_retry = needs_mmap_retry_p ();
|
bool need_retry = needs_mmap_retry_p ();
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|
@ -4986,11 +4995,10 @@ dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps,
|
||||||
}
|
}
|
||||||
|
|
||||||
eassert (resv == NULL);
|
eassert (resv == NULL);
|
||||||
resv = dump_anonymous_allocate (NULL,
|
resv = dump_anonymous_allocate (NULL, total_size,
|
||||||
total_size,
|
|
||||||
DUMP_MEMORY_ACCESS_NONE);
|
DUMP_MEMORY_ACCESS_NONE);
|
||||||
if (!resv)
|
if (!resv)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
char *mem = resv;
|
char *mem = resv;
|
||||||
|
|
||||||
|
|
@ -5039,6 +5047,7 @@ dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps,
|
||||||
ret = true;
|
ret = true;
|
||||||
resv = NULL;
|
resv = NULL;
|
||||||
out:
|
out:
|
||||||
|
save_errno = errno;
|
||||||
if (resv)
|
if (resv)
|
||||||
dump_anonymous_release (resv, total_size);
|
dump_anonymous_release (resv, total_size);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
|
|
@ -5051,6 +5060,7 @@ dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps,
|
||||||
dump_mmap_release (&maps[i]);
|
dump_mmap_release (&maps[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
errno = save_errno;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5058,8 +5068,8 @@ dump_mmap_contiguous_vm (struct dump_memory_map *maps, int nr_maps,
|
||||||
|
|
||||||
Each dump_memory_map structure describes how to fill the
|
Each dump_memory_map structure describes how to fill the
|
||||||
corresponding range of memory. On input, all members except MAPPING
|
corresponding range of memory. On input, all members except MAPPING
|
||||||
are valid. On output, MAPPING contains the location of the given
|
are valid. On output, MAPPING contains the location of the given
|
||||||
chunk of memory. The MAPPING for MAPS[N] is MAPS[N-1].mapping +
|
chunk of memory. The MAPPING for MAPS[N] is MAPS[N-1].mapping +
|
||||||
MAPS[N-1].size.
|
MAPS[N-1].size.
|
||||||
|
|
||||||
Each mapping SIZE must be a multiple of the system page size except
|
Each mapping SIZE must be a multiple of the system page size except
|
||||||
|
|
@ -5085,8 +5095,10 @@ dump_mmap_contiguous (struct dump_memory_map *maps, int nr_maps)
|
||||||
total_size += maps[i].spec.size;
|
total_size += maps[i].spec.size;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (VM_SUPPORTED ? dump_mmap_contiguous_vm : dump_mmap_contiguous_heap)
|
if (VM_SUPPORTED)
|
||||||
(maps, nr_maps, total_size);
|
return dump_mmap_contiguous_vm (maps, nr_maps, total_size);
|
||||||
|
else
|
||||||
|
return dump_mmap_contiguous_heap (maps, nr_maps, total_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef uint_fast32_t dump_bitset_word;
|
typedef uint_fast32_t dump_bitset_word;
|
||||||
|
|
@ -5129,7 +5141,7 @@ dump_bitset_bit_set_p (const struct dump_bitset *bitset,
|
||||||
{
|
{
|
||||||
dump_bitset_word bit = 1;
|
dump_bitset_word bit = 1;
|
||||||
bit <<= bit_number % DUMP_BITSET_WORD_WIDTH;
|
bit <<= bit_number % DUMP_BITSET_WORD_WIDTH;
|
||||||
return *dump_bitset__bit_slot (bitset, bit_number) & bit;
|
return (*dump_bitset__bit_slot (bitset, bit_number) & bit) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -5548,8 +5560,8 @@ dump_do_dump_relocation (const uintptr_t dump_base,
|
||||||
struct bignum_reload_info reload_info;
|
struct bignum_reload_info reload_info;
|
||||||
static_assert (sizeof (reload_info) <= sizeof (*bignum_val (bignum)));
|
static_assert (sizeof (reload_info) <= sizeof (*bignum_val (bignum)));
|
||||||
memcpy (&reload_info, bignum_val (bignum), sizeof (reload_info));
|
memcpy (&reload_info, bignum_val (bignum), sizeof (reload_info));
|
||||||
const mp_limb_t *limbs =
|
const mp_limb_t *limbs = dump_ptr (dump_base,
|
||||||
dump_ptr (dump_base, reload_info.data_location);
|
reload_info.data_location);
|
||||||
mpz_roinit_n (bignum->value, limbs, reload_info.nlimbs);
|
mpz_roinit_n (bignum->value, limbs, reload_info.nlimbs);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -5790,15 +5802,29 @@ pdumper_load (const char *dump_filename, char *argv0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err = PDUMPER_LOAD_ERROR;
|
err = PDUMPER_LOAD_ERROR;
|
||||||
mark_bits_needed =
|
dump_base = (uintptr_t) sections[DS_HOT].mapping;
|
||||||
divide_round_up (header->discardable_start, DUMP_ALIGNMENT);
|
|
||||||
|
#if !USE_LSB_TAG
|
||||||
|
/* The dump may have been mapped at a location that does not admit of
|
||||||
|
representation as Lisp_Objects. Abort in this case. */
|
||||||
|
if ((dump_base + dump_size) & ~VALMASK)
|
||||||
|
{
|
||||||
|
fprintf (stderr,
|
||||||
|
"Failed to load dump file: 0x%p+0x%p & 0x%p != 0\n",
|
||||||
|
(void *) dump_base, (void *) dump_size,
|
||||||
|
(void *) (uintptr_t) VALMASK);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
#endif /* !USE_LSB_TAG */
|
||||||
|
|
||||||
|
mark_bits_needed
|
||||||
|
= divide_round_up (header->discardable_start, DUMP_ALIGNMENT);
|
||||||
if (!dump_bitsets_init (mark_bits, mark_bits_needed))
|
if (!dump_bitsets_init (mark_bits, mark_bits_needed))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
/* Point of no return. */
|
/* Point of no return. */
|
||||||
err = PDUMPER_LOAD_SUCCESS;
|
err = PDUMPER_LOAD_SUCCESS;
|
||||||
dump_base = (uintptr_t) sections[DS_HOT].mapping;
|
gflags.dumped_with_pdumper = true;
|
||||||
gflags.dumped_with_pdumper_ = true;
|
|
||||||
dump_private.header = *header;
|
dump_private.header = *header;
|
||||||
dump_private.mark_bits = mark_bits[0];
|
dump_private.mark_bits = mark_bits[0];
|
||||||
dump_private.last_mark_bits = mark_bits[1];
|
dump_private.last_mark_bits = mark_bits[1];
|
||||||
|
|
@ -5815,8 +5841,8 @@ pdumper_load (const char *dump_filename, char *argv0)
|
||||||
Lisp_Object hashes = zero_vector;
|
Lisp_Object hashes = zero_vector;
|
||||||
if (header->hash_list)
|
if (header->hash_list)
|
||||||
{
|
{
|
||||||
struct Lisp_Vector *hash_tables =
|
struct Lisp_Vector *hash_tables
|
||||||
(struct Lisp_Vector *) (dump_base + header->hash_list);
|
= (struct Lisp_Vector *) (dump_base + header->hash_list);
|
||||||
hashes = make_lisp_ptr (hash_tables, Lisp_Vectorlike);
|
hashes = make_lisp_ptr (hash_tables, Lisp_Vectorlike);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5852,7 +5878,6 @@ pdumper_load (const char *dump_filename, char *argv0)
|
||||||
dump_mmap_release (§ions[i]);
|
dump_mmap_release (§ions[i]);
|
||||||
if (dump_fd >= 0)
|
if (dump_fd >= 0)
|
||||||
emacs_close (dump_fd);
|
emacs_close (dump_fd);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue