aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2014-09-09 23:38:38 -0700
committerPaul Eggert2014-09-09 23:38:38 -0700
commit11e28ab08d44c1fc40e3e4dc728c14c521b3879d (patch)
treefd5f541d44d9d3d6383f2064c9e45c684b73d6cf /src
parentc98d0ea46197545b899b463c1ba9ff2fea8e8c6e (diff)
downloademacs-11e28ab08d44c1fc40e3e4dc728c14c521b3879d.tar.gz
emacs-11e28ab08d44c1fc40e3e4dc728c14c521b3879d.zip
Improve the experimental local and scoped allocation.
* configure.ac (HAVE_STRUCT_ATTRIBUTE_ALIGNED) (HAVE_STATEMENT_EXPRESSIONS): New configure-time checks. * src/alloc.c (local_string_init, local_vector_init): New functions, defined if USE_LOCAL_ALLOCATORS. Mostly, these are moved here from lisp.h, as it's not clear it's worth making them inline. * src/lisp.h (USE_STACK_LISP_OBJECTS): Default to false. (GCALIGNED): Depend on HAVE_STRUCT_ATTRIBUTE_ALIGNED and USE_STACK_LISP_OBJECTS, not on a laundry list. (local_string_init, local_vector_init): New decls. (union Aligned_Cons): New type. (scoped_cons): Use it. Give up on the char trick, as it's a too much of a maintenance hassle; if someone wants this speedup they'll just need to convince their compiler to align properly. Conversely, use the speedup if struct Lisp_Cons happens to be aligned even without a directive. Better yet, help it along by using union Aligned_Cons rather than struct Lisp_Cons. (pointer_valid_for_lisp_object): Remove. This check is not necessary, since make_lisp_ptr is already doing it. All uses removed. (local_vector_init, local_string_init): Move to alloc.c. (build_local_vector): Remove this awkward macro, replacing with ... (make_local_vector): New macro, which acts more like a function. Use statement expressions and use __COUNTER__ to avoid macro capture. Fall back on functions if these features are not supported. (build_local_string, make_local_string): Likewise.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog27
-rw-r--r--src/alloc.c42
-rw-r--r--src/lisp.h225
3 files changed, 168 insertions, 126 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index b94ac53051a..b98d4eef355 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,30 @@
12014-09-10 Paul Eggert <eggert@cs.ucla.edu>
2
3 Improve the experimental local and scoped allocation.
4 * alloc.c (local_string_init, local_vector_init):
5 New functions, defined if USE_LOCAL_ALLOCATORS.
6 Mostly, these are moved here from lisp.h, as it's not
7 clear it's worth making them inline.
8 * lisp.h (USE_STACK_LISP_OBJECTS): Default to false.
9 (GCALIGNED): Depend on HAVE_STRUCT_ATTRIBUTE_ALIGNED and
10 USE_STACK_LISP_OBJECTS, not on a laundry list.
11 (local_string_init, local_vector_init): New decls.
12 (union Aligned_Cons): New type.
13 (scoped_cons): Use it. Give up on the char trick, as it's a too
14 much of a maintenance hassle; if someone wants this speedup
15 they'll just need to convince their compiler to align properly.
16 Conversely, use the speedup if struct Lisp_Cons happens to
17 be aligned even without a directive. Better yet, help it along
18 by using union Aligned_Cons rather than struct Lisp_Cons.
19 (pointer_valid_for_lisp_object): Remove. This check is not
20 necessary, since make_lisp_ptr is already doing it. All uses removed.
21 (local_vector_init, local_string_init): Move to alloc.c.
22 (build_local_vector): Remove this awkward macro, replacing with ...
23 (make_local_vector): New macro, which acts more like a function.
24 Use statement expressions and use __COUNTER__ to avoid macro
25 capture. Fall back on functions if these features are not supported.
26 (build_local_string, make_local_string): Likewise.
27
12014-09-09 Dmitry Antipov <dmantipov@yandex.ru> 282014-09-09 Dmitry Antipov <dmantipov@yandex.ru>
2 29
3 * xterm.c (x_term_init): Consolidate duplicated code. 30 * xterm.c (x_term_init): Consolidate duplicated code.
diff --git a/src/alloc.c b/src/alloc.c
index 5c7ce31cad8..714827f6ae3 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -2226,6 +2226,32 @@ make_string (const char *contents, ptrdiff_t nbytes)
2226 return val; 2226 return val;
2227} 2227}
2228 2228
2229#ifdef USE_LOCAL_ALLOCATORS
2230
2231/* Initialize the string S from DATA and SIZE. S must be followed by
2232 SIZE + 1 bytes of memory that can be used. Return S tagged as a
2233 Lisp object. */
2234
2235Lisp_Object
2236local_string_init (struct Lisp_String *s, char const *data, ptrdiff_t size)
2237{
2238 unsigned char *data_copy = (unsigned char *) (s + 1);
2239 parse_str_as_multibyte ((unsigned char const *) data,
2240 size, &s->size, &s->size_byte);
2241 if (size == s->size || size != s->size_byte)
2242 {
2243 s->size = size;
2244 s->size_byte = -1;
2245 }
2246 s->intervals = NULL;
2247 s->data = data_copy;
2248 memcpy (data_copy, data, size);
2249 data_copy[size] = '\0';
2250 return make_lisp_ptr (s, Lisp_String);
2251}
2252
2253#endif
2254
2229 2255
2230/* Make an unibyte string from LENGTH bytes at CONTENTS. */ 2256/* Make an unibyte string from LENGTH bytes at CONTENTS. */
2231 2257
@@ -3288,6 +3314,22 @@ See also the function `vector'. */)
3288 return vector; 3314 return vector;
3289} 3315}
3290 3316
3317#ifdef USE_LOCAL_ALLOCATORS
3318
3319/* Initialize V with LENGTH objects each with value INIT,
3320 and return it tagged as a Lisp Object. */
3321
3322INLINE Lisp_Object
3323local_vector_init (struct Lisp_Vector *v, ptrdiff_t length, Lisp_Object init)
3324{
3325 v->header.size = length;
3326 for (ptrdiff_t i = 0; i < length; i++)
3327 v->contents[i] = init;
3328 return make_lisp_ptr (v, Lisp_Vectorlike);
3329}
3330
3331#endif
3332
3291 3333
3292DEFUN ("vector", Fvector, Svector, 0, MANY, 0, 3334DEFUN ("vector", Fvector, Svector, 0, MANY, 0,
3293 doc: /* Return a newly created vector with specified arguments as elements. 3335 doc: /* Return a newly created vector with specified arguments as elements.
diff --git a/src/lisp.h b/src/lisp.h
index cbb4c30bea1..3c7eb44b36d 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -298,12 +298,14 @@ error !;
298# endif 298# endif
299#endif 299#endif
300 300
301/* Stolen from gnulib. */ 301#ifndef USE_STACK_LISP_OBJECTS
302#if (__GNUC__ || __HP_cc || __HP_aCC || __IBMC__ \ 302# define USE_STACK_LISP_OBJECTS false
303 || __IBMCPP__ || __ICC || 0x5110 <= __SUNPRO_C) 303#endif
304#define GCALIGNED __attribute__ ((aligned (GCALIGNMENT))) 304
305#if defined HAVE_STRUCT_ATTRIBUTE_ALIGNED && USE_STACK_LISP_OBJECTS
306# define GCALIGNED __attribute__ ((aligned (GCALIGNMENT)))
305#else 307#else
306#define GCALIGNED /* empty */ 308# define GCALIGNED /* empty */
307#endif 309#endif
308 310
309/* Some operations are so commonly executed that they are implemented 311/* Some operations are so commonly executed that they are implemented
@@ -3685,6 +3687,8 @@ extern Lisp_Object make_uninit_bool_vector (EMACS_INT);
3685extern Lisp_Object bool_vector_fill (Lisp_Object, Lisp_Object); 3687extern Lisp_Object bool_vector_fill (Lisp_Object, Lisp_Object);
3686extern _Noreturn void string_overflow (void); 3688extern _Noreturn void string_overflow (void);
3687extern Lisp_Object make_string (const char *, ptrdiff_t); 3689extern Lisp_Object make_string (const char *, ptrdiff_t);
3690extern Lisp_Object local_string_init (struct Lisp_String *, char const *,
3691 ptrdiff_t);
3688extern Lisp_Object make_formatted_string (char *, const char *, ...) 3692extern Lisp_Object make_formatted_string (char *, const char *, ...)
3689 ATTRIBUTE_FORMAT_PRINTF (2, 3); 3693 ATTRIBUTE_FORMAT_PRINTF (2, 3);
3690extern Lisp_Object make_unibyte_string (const char *, ptrdiff_t); 3694extern Lisp_Object make_unibyte_string (const char *, ptrdiff_t);
@@ -3773,6 +3777,8 @@ extern struct Lisp_Hash_Table *allocate_hash_table (void);
3773extern struct window *allocate_window (void); 3777extern struct window *allocate_window (void);
3774extern struct frame *allocate_frame (void); 3778extern struct frame *allocate_frame (void);
3775extern struct Lisp_Process *allocate_process (void); 3779extern struct Lisp_Process *allocate_process (void);
3780extern Lisp_Object local_vector_init (struct Lisp_Vector *, ptrdiff_t,
3781 Lisp_Object);
3776extern struct terminal *allocate_terminal (void); 3782extern struct terminal *allocate_terminal (void);
3777extern bool gc_in_progress; 3783extern bool gc_in_progress;
3778extern bool abort_on_gc; 3784extern bool abort_on_gc;
@@ -4546,142 +4552,109 @@ extern void *record_xmalloc (size_t) ATTRIBUTE_ALLOC_SIZE ((1));
4546 memory_full (SIZE_MAX); \ 4552 memory_full (SIZE_MAX); \
4547 } while (false) 4553 } while (false)
4548 4554
4549/* This feature is experimental and requires very careful debugging.
4550 Brave user should compile with CPPFLAGS='-DUSE_STACK_LISP_OBJECTS'
4551 to get into the game. */
4552
4553#ifdef USE_STACK_LISP_OBJECTS
4554
4555/* Use the following functions to allocate temporary (function-
4556 or block-scoped) conses, vectors, and strings. These objects
4557 are not managed by GC, and passing them out of their scope
4558 most likely causes an immediate crash at next GC. */
4559 4555
4560#if (__GNUC__ || __HP_cc || __HP_aCC || __IBMC__ \ 4556/* If USE_STACK_LISP_OBJECTS, define macros that and functions that
4561 || __IBMCPP__ || __ICC || 0x5110 <= __SUNPRO_C) 4557 allocate block-scoped conses and function-scoped vectors and
4558 strings. These objects are not managed by the garbage collector,
4559 so they are dangerous: passing them out of their scope (e.g., to
4560 user code) results in undefined behavior. Conversely, they have
4561 better performance because GC is not involved.
4562 4562
4563/* Allocate temporary block-scoped cons. This version assumes 4563 This feature is experimental and requires careful debugging.
4564 that stack-allocated Lisp_Cons is always aligned properly. */ 4564 Brave users can compile with CPPFLAGS='-DUSE_STACK_LISP_OBJECTS'
4565 4565 to get into the game. */
4566#define scoped_cons(car, cdr) \
4567 make_lisp_ptr (&((struct Lisp_Cons) { car, { cdr } }), Lisp_Cons)
4568
4569#else /* not __GNUC__ etc... */
4570 4566
4571/* Helper function for an alternate scoped cons, see below. */ 4567/* A struct Lisp_Cons inside a union that is no larger and may be
4568 better-aligned. */
4572 4569
4573INLINE Lisp_Object 4570union Aligned_Cons
4574scoped_cons_init (void *ptr, Lisp_Object x, Lisp_Object y)
4575{ 4571{
4576 struct Lisp_Cons *c = (struct Lisp_Cons *) 4572 struct Lisp_Cons s;
4577 (((uintptr_t) ptr + (GCALIGNMENT - 1)) & ~(GCALIGNMENT - 1)); 4573 double d; intmax_t i; void *p;
4578 c->car = x; 4574};
4579 c->u.cdr = y; 4575verify (sizeof (struct Lisp_Cons) == sizeof (union Aligned_Cons));
4580 return make_lisp_ptr (c, Lisp_Cons);
4581}
4582 4576
4583/* This version uses explicit alignment. */ 4577/* Allocate a block-scoped cons. */
4584 4578
4585#define scoped_cons(car, cdr) \ 4579#define scoped_cons(car, cdr) \
4586 scoped_cons_init ((char[sizeof (struct Lisp_Cons) \ 4580 ((USE_STACK_LISP_OBJECTS \
4587 + (GCALIGNMENT - 1)]) {}, (car), (cdr)) 4581 && alignof (union Aligned_Cons) % GCALIGNMENT == 0) \
4588 4582 ? make_lisp_ptr (&((union Aligned_Cons) {{car, {cdr}}}).s, Lisp_Cons) \
4589#endif /* __GNUC__ etc... */ 4583 : Fcons (car, cdr))
4590 4584
4591/* Convenient utility macros similar to listX functions. */ 4585/* Convenient utility macros similar to listX functions. */
4592 4586
4593#define scoped_list1(x) scoped_cons (x, Qnil) 4587#if USE_STACK_LISP_OBJECTS
4594#define scoped_list2(x, y) scoped_cons (x, scoped_cons (y, Qnil)) 4588# define scoped_list1(x) scoped_cons (x, Qnil)
4595#define scoped_list3(x, y, z) \ 4589# define scoped_list2(x, y) scoped_cons (x, scoped_list1 (y))
4596 scoped_cons (x, scoped_cons (y, scoped_cons (z, Qnil))) 4590# define scoped_list3(x, y, z) scoped_cons (x, scoped_list2 (y, z))
4597 4591#else
4598/* True if Lisp_Object may be placed at P. Used only 4592# define scoped_list1(x) list1 (x)
4599 under ENABLE_CHECKING and optimized away otherwise. */ 4593# define scoped_list2(x, y) list2 (x, y)
4600 4594# define scoped_list3(x, y, z) list3 (x, y, z)
4601INLINE bool 4595#endif
4602pointer_valid_for_lisp_object (void *p)
4603{
4604 uintptr_t v = (uintptr_t) p;
4605 return !(USE_LSB_TAG ? (v & ~VALMASK) : v >> VALBITS);
4606}
4607
4608/* Helper function for build_local_vector, see below. */
4609
4610INLINE Lisp_Object
4611local_vector_init (uintptr_t addr, ptrdiff_t length, Lisp_Object init)
4612{
4613 ptrdiff_t i;
4614 struct Lisp_Vector *v = (struct Lisp_Vector *) addr;
4615
4616 eassert (pointer_valid_for_lisp_object (v));
4617 v->header.size = length;
4618 for (i = 0; i < length; i++)
4619 v->contents[i] = init;
4620 return make_lisp_ptr (v, Lisp_Vectorlike);
4621}
4622
4623/* If size permits, create temporary function-scoped vector OBJ of
4624 length SIZE, with each element being INIT. Otherwise create
4625 regular GC-managed vector. */
4626
4627#define build_local_vector(obj, size, init) \
4628 (MAX_ALLOCA < (size) * word_size + header_size \
4629 ? obj = Fmake_vector (make_number (size), (init)) \
4630 : (obj = XIL ((uintptr_t) alloca \
4631 ((size) * word_size + header_size)), \
4632 obj = local_vector_init ((uintptr_t) XLI (obj), (size), (init))))
4633
4634/* Helper function for make_local_string, see below. */
4635
4636INLINE Lisp_Object
4637local_string_init (uintptr_t addr, const char *data, ptrdiff_t size)
4638{
4639 ptrdiff_t nchars, nbytes;
4640 struct Lisp_String *s = (struct Lisp_String *) addr;
4641
4642 eassert (pointer_valid_for_lisp_object (s));
4643 parse_str_as_multibyte ((const unsigned char *) data,
4644 size, &nchars, &nbytes);
4645 s->data = (unsigned char *) (addr + sizeof *s);
4646 s->intervals = NULL;
4647 memcpy (s->data, data, size);
4648 s->data[size] = '\0';
4649 if (size == nchars || size != nbytes)
4650 s->size = size, s->size_byte = -1;
4651 else
4652 s->size = nchars, s->size_byte = nbytes;
4653 return make_lisp_ptr (s, Lisp_String);
4654}
4655
4656/* If size permits, create temporary function-scoped string OBJ
4657 with contents DATA of length NBYTES. Otherwise create regular
4658 GC-managed string. */
4659
4660#define make_local_string(obj, data, nbytes) \
4661 (MAX_ALLOCA < (nbytes) + sizeof (struct Lisp_String) \
4662 ? obj = make_string ((data), (nbytes)) \
4663 : (obj = XIL ((uintptr_t) alloca \
4664 ((nbytes) + sizeof (struct Lisp_String))), \
4665 obj = local_string_init ((uintptr_t) XLI (obj), data, nbytes)))
4666
4667/* We want an interface similar to make_string and build_string, right? */
4668 4596
4669#define build_local_string(obj, data) \ 4597#if USE_STACK_LISP_OBJECTS && HAVE_STATEMENT_EXPRESSIONS && defined __COUNTER__
4670 make_local_string (obj, data, strlen (data)) 4598
4599# define USE_LOCAL_ALLOCATORS
4600
4601/* Return a function-scoped vector of length SIZE, with each element
4602 being INIT. */
4603
4604# define make_local_vector(size, init) \
4605 make_local_vector_n (size, init, __COUNTER__)
4606# define make_local_vector_n(size_arg, init_arg, n) \
4607 ({ \
4608 ptrdiff_t size##n = size_arg; \
4609 Lisp_Object init##n = init_arg; \
4610 Lisp_Object vec##n; \
4611 if (size##n <= (MAX_ALLOCA - header_size) / word_size) \
4612 { \
4613 void *ptr##n = alloca (size##n * word_size + header_size); \
4614 vec##n = local_vector_init (ptr##n, size##n, init##n); \
4615 } \
4616 else \
4617 vec##n = Fmake_vector (make_number (size##n), init##n); \
4618 vec##n; \
4619 })
4620
4621/* Return a function-scoped string with contents DATA and length NBYTES. */
4622
4623# define make_local_string(data, nbytes) \
4624 make_local_string (data, nbytes, __COUNTER__)
4625# define make_local_string_n(data_arg, nbytes_arg, n) \
4626 ({ \
4627 char const *data##n = data_arg; \
4628 ptrdiff_t nbytes##n = nbytes_arg; \
4629 Lisp_Object string##n; \
4630 if (nbytes##n <= MAX_ALLOCA - sizeof (struct Lisp_String) - 1) \
4631 { \
4632 struct Lisp_String *ptr##n \
4633 = alloca (sizeof (struct Lisp_String) + 1 + nbytes); \
4634 string##n = local_string_init (ptr##n, data##n, nbytes##n); \
4635 } \
4636 else \
4637 string##n = make_string (data##n, nbytes##n); \
4638 string##n; \
4639 })
4640
4641/* Return a function-scoped string with contents DATA. */
4642
4643# define build_local_string(data) build_local_string_n (data, __COUNTER__)
4644# define build_local_string_n(data_arg, n) \
4645 ({ \
4646 char const *data##n = data_arg; \
4647 make_local_string (data##n, strlen (data##n)); \
4648 })
4671 4649
4672#else /* not USE_STACK_LISP_OBJECTS */ 4650#else
4673 4651
4674#define scoped_cons(x, y) Fcons ((x), (y)) 4652/* Safer but slower implementations. */
4675#define scoped_list1(x) list1 (x) 4653# define make_local_vector(size, init) Fmake_vector (make_number (size), init)
4676#define scoped_list2(x, y) list2 ((x), (y)) 4654# define make_local_string(data, nbytes) make_string (data, nbytes)
4677#define scoped_list3(x, y, z) list3 ((x), (y), (z)) 4655# define build_local_string(data) build_string (data)
4678#define build_local_vector(obj, size, init) \ 4656#endif
4679 (obj = Fmake_vector (make_number ((size), (init))))
4680#define make_local_string(obj, data, nbytes) \
4681 (obj = make_string ((data), (nbytes)))
4682#define build_local_string(obj, data) (obj = build_string (data))
4683 4657
4684#endif /* USE_STACK_LISP_OBJECTS */
4685 4658
4686/* Loop over all tails of a list, checking for cycles. 4659/* Loop over all tails of a list, checking for cycles.
4687 FIXME: Make tortoise and n internal declarations. 4660 FIXME: Make tortoise and n internal declarations.