diff options
| author | Dmitry Antipov | 2014-09-09 07:44:06 +0400 |
|---|---|---|
| committer | Dmitry Antipov | 2014-09-09 07:44:06 +0400 |
| commit | c7dfea947eba1980fe3a23ad13f04dd40c6c0d68 (patch) | |
| tree | 3927b309d9773c54a06d7590e0dd6017a8c3bfc8 /src | |
| parent | 80465f41d7fc67d40f0a233504e295b127ad2c6b (diff) | |
| download | emacs-c7dfea947eba1980fe3a23ad13f04dd40c6c0d68.tar.gz emacs-c7dfea947eba1980fe3a23ad13f04dd40c6c0d68.zip | |
Add macros to allocate temporary Lisp objects with alloca.
Respect MAX_ALLOCA and fall back to regular GC for large objects.
* character.h (parse_str_as_multibyte): Move prototype to ...
* lisp.h (parse_str_as_multibyte): ... here.
(struct Lisp_Cons): Add GCALIGNED attribute if supported.
(scoped_cons, scoped_list2, build_local_vector, build_local_string):
New macros.
(scoped_cons_init, pointer_valid_for_lisp_object, local_vector_init)
(local_string_init): New functions.
* alloc.c (verify_alloca) [ENABLE_CHECKING]: New function.
(init_alloc_once): Call it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 12 | ||||
| -rw-r--r-- | src/alloc.c | 27 | ||||
| -rw-r--r-- | src/character.h | 2 | ||||
| -rw-r--r-- | src/lisp.h | 122 |
4 files changed, 158 insertions, 5 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index a01c753161c..d1e8314b172 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -5,6 +5,18 @@ | |||
| 5 | (x_delete_terminal): Do not close X connection fd (Bug#18403). | 5 | (x_delete_terminal): Do not close X connection fd (Bug#18403). |
| 6 | Add eassert and mark dpyinfo as dead only if it was alive. | 6 | Add eassert and mark dpyinfo as dead only if it was alive. |
| 7 | 7 | ||
| 8 | Add macros to allocate temporary Lisp objects with alloca. | ||
| 9 | Respect MAX_ALLOCA and fall back to regular GC for large objects. | ||
| 10 | * character.h (parse_str_as_multibyte): Move prototype to ... | ||
| 11 | * lisp.h (parse_str_as_multibyte): ... here. | ||
| 12 | (struct Lisp_Cons): Add GCALIGNED attribute if supported. | ||
| 13 | (scoped_cons, scoped_list2, build_local_vector, build_local_string): | ||
| 14 | New macros. | ||
| 15 | (scoped_cons_init, pointer_valid_for_lisp_object, local_vector_init) | ||
| 16 | (local_string_init): New functions. | ||
| 17 | * alloc.c (verify_alloca) [ENABLE_CHECKING]: New function. | ||
| 18 | (init_alloc_once): Call it. | ||
| 19 | |||
| 8 | 2014-09-08 Eli Zaretskii <eliz@gnu.org> | 20 | 2014-09-08 Eli Zaretskii <eliz@gnu.org> |
| 9 | 21 | ||
| 10 | * dispnew.c (prepare_desired_row): When MODE_LINE_P is zero, | 22 | * dispnew.c (prepare_desired_row): When MODE_LINE_P is zero, |
diff --git a/src/alloc.c b/src/alloc.c index 31b0644c285..13043d6d9d7 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -7117,8 +7117,29 @@ die (const char *msg, const char *file, int line) | |||
| 7117 | file, line, msg); | 7117 | file, line, msg); |
| 7118 | terminate_due_to_signal (SIGABRT, INT_MAX); | 7118 | terminate_due_to_signal (SIGABRT, INT_MAX); |
| 7119 | } | 7119 | } |
| 7120 | #endif | 7120 | |
| 7121 | 7121 | /* Stress alloca with inconveniently sized requests and check | |
| 7122 | whether all allocated areas may be used for Lisp_Object. */ | ||
| 7123 | |||
| 7124 | NO_INLINE static void | ||
| 7125 | verify_alloca (void) | ||
| 7126 | { | ||
| 7127 | int i; | ||
| 7128 | enum { ALLOCA_CHECK_MAX = 256 }; | ||
| 7129 | /* Start from size of the smallest Lisp object. */ | ||
| 7130 | for (i = sizeof (struct Lisp_Cons); i <= ALLOCA_CHECK_MAX; i++) | ||
| 7131 | { | ||
| 7132 | char *ptr = alloca (i); | ||
| 7133 | eassert (pointer_valid_for_lisp_object (ptr)); | ||
| 7134 | } | ||
| 7135 | } | ||
| 7136 | |||
| 7137 | #else /* not ENABLE_CHECKING */ | ||
| 7138 | |||
| 7139 | #define verify_alloca() ((void) 0) | ||
| 7140 | |||
| 7141 | #endif /* ENABLE_CHECKING */ | ||
| 7142 | |||
| 7122 | /* Initialization. */ | 7143 | /* Initialization. */ |
| 7123 | 7144 | ||
| 7124 | void | 7145 | void |
| @@ -7128,6 +7149,8 @@ init_alloc_once (void) | |||
| 7128 | purebeg = PUREBEG; | 7149 | purebeg = PUREBEG; |
| 7129 | pure_size = PURESIZE; | 7150 | pure_size = PURESIZE; |
| 7130 | 7151 | ||
| 7152 | verify_alloca (); | ||
| 7153 | |||
| 7131 | #if GC_MARK_STACK || defined GC_MALLOC_CHECK | 7154 | #if GC_MARK_STACK || defined GC_MALLOC_CHECK |
| 7132 | mem_init (); | 7155 | mem_init (); |
| 7133 | Vdead = make_pure_string ("DEAD", 4, 4, 0); | 7156 | Vdead = make_pure_string ("DEAD", 4, 4, 0); |
diff --git a/src/character.h b/src/character.h index 66cd4e47ef8..624f4fff3f0 100644 --- a/src/character.h +++ b/src/character.h | |||
| @@ -644,8 +644,6 @@ extern int string_char (const unsigned char *, | |||
| 644 | const unsigned char **, int *); | 644 | const unsigned char **, int *); |
| 645 | 645 | ||
| 646 | extern int translate_char (Lisp_Object, int c); | 646 | extern int translate_char (Lisp_Object, int c); |
| 647 | extern void parse_str_as_multibyte (const unsigned char *, | ||
| 648 | ptrdiff_t, ptrdiff_t *, ptrdiff_t *); | ||
| 649 | extern ptrdiff_t count_size_as_multibyte (const unsigned char *, ptrdiff_t); | 647 | extern ptrdiff_t count_size_as_multibyte (const unsigned char *, ptrdiff_t); |
| 650 | extern ptrdiff_t str_as_multibyte (unsigned char *, ptrdiff_t, ptrdiff_t, | 648 | extern ptrdiff_t str_as_multibyte (unsigned char *, ptrdiff_t, ptrdiff_t, |
| 651 | ptrdiff_t *); | 649 | ptrdiff_t *); |
diff --git a/src/lisp.h b/src/lisp.h index 15c459c9fdb..a89e80729cd 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -298,6 +298,13 @@ error !; | |||
| 298 | # endif | 298 | # endif |
| 299 | #endif | 299 | #endif |
| 300 | 300 | ||
| 301 | /* Stolen from gnulib. */ | ||
| 302 | #if (__GNUC__ || __HP_cc || __HP_aCC || __IBMC__ \ | ||
| 303 | || __IBMCPP__ || __ICC || 0x5110 <= __SUNPRO_C) | ||
| 304 | #define GCALIGNED __attribute__ ((aligned (GCALIGNMENT))) | ||
| 305 | #else | ||
| 306 | #define GCALIGNED /* empty */ | ||
| 307 | #endif | ||
| 301 | 308 | ||
| 302 | /* Some operations are so commonly executed that they are implemented | 309 | /* Some operations are so commonly executed that they are implemented |
| 303 | as macros, not functions, because otherwise runtime performance would | 310 | as macros, not functions, because otherwise runtime performance would |
| @@ -1016,7 +1023,7 @@ LISP_MACRO_DEFUN_VOID (CHECK_TYPE, | |||
| 1016 | 1023 | ||
| 1017 | typedef struct interval *INTERVAL; | 1024 | typedef struct interval *INTERVAL; |
| 1018 | 1025 | ||
| 1019 | struct Lisp_Cons | 1026 | struct GCALIGNED Lisp_Cons |
| 1020 | { | 1027 | { |
| 1021 | /* Car of this cons cell. */ | 1028 | /* Car of this cons cell. */ |
| 1022 | Lisp_Object car; | 1029 | Lisp_Object car; |
| @@ -3622,6 +3629,10 @@ extern void syms_of_xsettings (void); | |||
| 3622 | /* Defined in vm-limit.c. */ | 3629 | /* Defined in vm-limit.c. */ |
| 3623 | extern void memory_warnings (void *, void (*warnfun) (const char *)); | 3630 | extern void memory_warnings (void *, void (*warnfun) (const char *)); |
| 3624 | 3631 | ||
| 3632 | /* Defined in character.c. */ | ||
| 3633 | extern void parse_str_as_multibyte (const unsigned char *, ptrdiff_t, | ||
| 3634 | ptrdiff_t *, ptrdiff_t *); | ||
| 3635 | |||
| 3625 | /* Defined in alloc.c. */ | 3636 | /* Defined in alloc.c. */ |
| 3626 | extern void check_pure_size (void); | 3637 | extern void check_pure_size (void); |
| 3627 | extern void free_misc (Lisp_Object); | 3638 | extern void free_misc (Lisp_Object); |
| @@ -4535,6 +4546,115 @@ extern void *record_xmalloc (size_t) ATTRIBUTE_ALLOC_SIZE ((1)); | |||
| 4535 | memory_full (SIZE_MAX); \ | 4546 | memory_full (SIZE_MAX); \ |
| 4536 | } while (false) | 4547 | } while (false) |
| 4537 | 4548 | ||
| 4549 | /* Use the following functions to allocate temporary (function- | ||
| 4550 | or block-scoped) conses, vectors, and strings. These objects | ||
| 4551 | are not managed by GC, and passing them out of their scope | ||
| 4552 | most likely causes an immediate crash at next GC. */ | ||
| 4553 | |||
| 4554 | #if (__GNUC__ || __HP_cc || __HP_aCC || __IBMC__ \ | ||
| 4555 | || __IBMCPP__ || __ICC || 0x5110 <= __SUNPRO_C) | ||
| 4556 | |||
| 4557 | /* Allocate temporary block-scoped cons. This version assumes | ||
| 4558 | that stack-allocated Lisp_Cons is always aligned properly. */ | ||
| 4559 | |||
| 4560 | #define scoped_cons(car, cdr) \ | ||
| 4561 | make_lisp_ptr (&((struct Lisp_Cons) { car, { cdr } }), Lisp_Cons) | ||
| 4562 | |||
| 4563 | #else /* not __GNUC__ etc... */ | ||
| 4564 | |||
| 4565 | /* Helper function for an alternate scoped cons, see below. */ | ||
| 4566 | |||
| 4567 | INLINE Lisp_Object | ||
| 4568 | scoped_cons_init (void *ptr, Lisp_Object x, Lisp_Object y) | ||
| 4569 | { | ||
| 4570 | struct Lisp_Cons *c = (struct Lisp_Cons *) | ||
| 4571 | (((uintptr_t) ptr + (GCALIGNMENT - 1)) & ~(GCALIGNMENT - 1)); | ||
| 4572 | c->car = x; | ||
| 4573 | c->u.cdr = y; | ||
| 4574 | return make_lisp_ptr (c, Lisp_Cons); | ||
| 4575 | } | ||
| 4576 | |||
| 4577 | /* This version uses explicit alignment. */ | ||
| 4578 | |||
| 4579 | #define scoped_cons(car, cdr) \ | ||
| 4580 | scoped_cons_init ((char[sizeof (struct Lisp_Cons) \ | ||
| 4581 | + (GCALIGNMENT - 1)]) {}, (car), (cdr)) | ||
| 4582 | |||
| 4583 | #endif /* __GNUC__ etc... */ | ||
| 4584 | |||
| 4585 | /* Convenient utility macro similar to list2. */ | ||
| 4586 | |||
| 4587 | #define scoped_list2(x, y) scoped_cons (x, scoped_cons (y, Qnil)) | ||
| 4588 | |||
| 4589 | /* True if Lisp_Object may be placed at P. Used only | ||
| 4590 | under ENABLE_CHECKING and optimized away otherwise. */ | ||
| 4591 | |||
| 4592 | INLINE bool | ||
| 4593 | pointer_valid_for_lisp_object (void *p) | ||
| 4594 | { | ||
| 4595 | uintptr_t v = (uintptr_t) p; | ||
| 4596 | return !(USE_LSB_TAG ? (v & ~VALMASK) : v >> VALBITS); | ||
| 4597 | } | ||
| 4598 | |||
| 4599 | /* Helper function for build_local_vector, see below. */ | ||
| 4600 | |||
| 4601 | INLINE Lisp_Object | ||
| 4602 | local_vector_init (uintptr_t addr, ptrdiff_t length, Lisp_Object init) | ||
| 4603 | { | ||
| 4604 | ptrdiff_t i; | ||
| 4605 | struct Lisp_Vector *v = (struct Lisp_Vector *) addr; | ||
| 4606 | |||
| 4607 | eassert (pointer_valid_for_lisp_object (v)); | ||
| 4608 | v->header.size = length; | ||
| 4609 | for (i = 0; i < length; i++) | ||
| 4610 | v->contents[i] = init; | ||
| 4611 | return make_lisp_ptr (v, Lisp_Vectorlike); | ||
| 4612 | } | ||
| 4613 | |||
| 4614 | /* If size permits, create temporary function-scoped vector OBJ of | ||
| 4615 | length SIZE, with each element being INIT. Otherwise create | ||
| 4616 | regular GC-managed vector. */ | ||
| 4617 | |||
| 4618 | #define build_local_vector(obj, size, init) \ | ||
| 4619 | (MAX_ALLOCA < (size) * word_size + header_size \ | ||
| 4620 | ? obj = Fmake_vector (make_number (size), (init)) \ | ||
| 4621 | : (obj = XIL ((uintptr_t) alloca \ | ||
| 4622 | ((size) * word_size + header_size)), \ | ||
| 4623 | obj = local_vector_init ((uintptr_t) XLI (obj), (size), (init)))) | ||
| 4624 | |||
| 4625 | /* Helper function for build_local_string, see below. */ | ||
| 4626 | |||
| 4627 | INLINE Lisp_Object | ||
| 4628 | local_string_init (uintptr_t addr, const char *data, ptrdiff_t size) | ||
| 4629 | { | ||
| 4630 | ptrdiff_t nchars, nbytes; | ||
| 4631 | struct Lisp_String *s = (struct Lisp_String *) addr; | ||
| 4632 | |||
| 4633 | eassert (pointer_valid_for_lisp_object (s)); | ||
| 4634 | parse_str_as_multibyte ((const unsigned char *) data, | ||
| 4635 | size, &nchars, &nbytes); | ||
| 4636 | s->data = (unsigned char *) (addr + sizeof *s); | ||
| 4637 | s->intervals = NULL; | ||
| 4638 | memcpy (s->data, data, size); | ||
| 4639 | s->data[size] = '\0'; | ||
| 4640 | if (size == nchars || size != nbytes) | ||
| 4641 | s->size = size, s->size_byte = -1; | ||
| 4642 | else | ||
| 4643 | s->size = nchars, s->size_byte = nbytes; | ||
| 4644 | return make_lisp_ptr (s, Lisp_String); | ||
| 4645 | } | ||
| 4646 | |||
| 4647 | /* If size permits, create temporary function-scoped string OBJ | ||
| 4648 | with contents DATA of length NBYTES. Otherwise create regular | ||
| 4649 | GC-managed string. */ | ||
| 4650 | |||
| 4651 | #define build_local_string(obj, data, nbytes) \ | ||
| 4652 | (MAX_ALLOCA < (nbytes) + sizeof (struct Lisp_String) \ | ||
| 4653 | ? obj = make_string ((data), (nbytes)) \ | ||
| 4654 | : (obj = XIL ((uintptr_t) alloca \ | ||
| 4655 | ((nbytes) + sizeof (struct Lisp_String))), \ | ||
| 4656 | obj = local_string_init ((uintptr_t) XLI (obj), data, nbytes))) | ||
| 4657 | |||
| 4538 | /* Loop over all tails of a list, checking for cycles. | 4658 | /* Loop over all tails of a list, checking for cycles. |
| 4539 | FIXME: Make tortoise and n internal declarations. | 4659 | FIXME: Make tortoise and n internal declarations. |
| 4540 | FIXME: Unroll the loop body so we don't need `n'. */ | 4660 | FIXME: Unroll the loop body so we don't need `n'. */ |