diff options
| author | Paul Eggert | 2014-09-09 23:38:38 -0700 |
|---|---|---|
| committer | Paul Eggert | 2014-09-09 23:38:38 -0700 |
| commit | 11e28ab08d44c1fc40e3e4dc728c14c521b3879d (patch) | |
| tree | fd5f541d44d9d3d6383f2064c9e45c684b73d6cf /src | |
| parent | c98d0ea46197545b899b463c1ba9ff2fea8e8c6e (diff) | |
| download | emacs-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/ChangeLog | 27 | ||||
| -rw-r--r-- | src/alloc.c | 42 | ||||
| -rw-r--r-- | src/lisp.h | 225 |
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 @@ | |||
| 1 | 2014-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 | |||
| 1 | 2014-09-09 Dmitry Antipov <dmantipov@yandex.ru> | 28 | 2014-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 | |||
| 2235 | Lisp_Object | ||
| 2236 | local_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 | |||
| 3322 | INLINE Lisp_Object | ||
| 3323 | local_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 | ||
| 3292 | DEFUN ("vector", Fvector, Svector, 0, MANY, 0, | 3334 | DEFUN ("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); | |||
| 3685 | extern Lisp_Object bool_vector_fill (Lisp_Object, Lisp_Object); | 3687 | extern Lisp_Object bool_vector_fill (Lisp_Object, Lisp_Object); |
| 3686 | extern _Noreturn void string_overflow (void); | 3688 | extern _Noreturn void string_overflow (void); |
| 3687 | extern Lisp_Object make_string (const char *, ptrdiff_t); | 3689 | extern Lisp_Object make_string (const char *, ptrdiff_t); |
| 3690 | extern Lisp_Object local_string_init (struct Lisp_String *, char const *, | ||
| 3691 | ptrdiff_t); | ||
| 3688 | extern Lisp_Object make_formatted_string (char *, const char *, ...) | 3692 | extern Lisp_Object make_formatted_string (char *, const char *, ...) |
| 3689 | ATTRIBUTE_FORMAT_PRINTF (2, 3); | 3693 | ATTRIBUTE_FORMAT_PRINTF (2, 3); |
| 3690 | extern Lisp_Object make_unibyte_string (const char *, ptrdiff_t); | 3694 | extern Lisp_Object make_unibyte_string (const char *, ptrdiff_t); |
| @@ -3773,6 +3777,8 @@ extern struct Lisp_Hash_Table *allocate_hash_table (void); | |||
| 3773 | extern struct window *allocate_window (void); | 3777 | extern struct window *allocate_window (void); |
| 3774 | extern struct frame *allocate_frame (void); | 3778 | extern struct frame *allocate_frame (void); |
| 3775 | extern struct Lisp_Process *allocate_process (void); | 3779 | extern struct Lisp_Process *allocate_process (void); |
| 3780 | extern Lisp_Object local_vector_init (struct Lisp_Vector *, ptrdiff_t, | ||
| 3781 | Lisp_Object); | ||
| 3776 | extern struct terminal *allocate_terminal (void); | 3782 | extern struct terminal *allocate_terminal (void); |
| 3777 | extern bool gc_in_progress; | 3783 | extern bool gc_in_progress; |
| 3778 | extern bool abort_on_gc; | 3784 | extern 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 | ||
| 4573 | INLINE Lisp_Object | 4570 | union Aligned_Cons |
| 4574 | scoped_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; | 4575 | verify (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) | |
| 4601 | INLINE bool | 4595 | #endif |
| 4602 | pointer_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 | |||
| 4610 | INLINE Lisp_Object | ||
| 4611 | local_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 | |||
| 4636 | INLINE Lisp_Object | ||
| 4637 | local_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. |