diff options
Diffstat (limited to 'src/alloc.c')
| -rw-r--r-- | src/alloc.c | 520 |
1 files changed, 66 insertions, 454 deletions
diff --git a/src/alloc.c b/src/alloc.c index 642cccc97c6..a9df5ca885f 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -33,7 +33,6 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 33 | #include "bignum.h" | 33 | #include "bignum.h" |
| 34 | #include "dispextern.h" | 34 | #include "dispextern.h" |
| 35 | #include "intervals.h" | 35 | #include "intervals.h" |
| 36 | #include "puresize.h" | ||
| 37 | #include "sysstdio.h" | 36 | #include "sysstdio.h" |
| 38 | #include "systime.h" | 37 | #include "systime.h" |
| 39 | #include "character.h" | 38 | #include "character.h" |
| @@ -380,33 +379,6 @@ static char *spare_memory[7]; | |||
| 380 | 379 | ||
| 381 | #define SPARE_MEMORY (1 << 14) | 380 | #define SPARE_MEMORY (1 << 14) |
| 382 | 381 | ||
| 383 | /* Initialize it to a nonzero value to force it into data space | ||
| 384 | (rather than bss space). That way unexec will remap it into text | ||
| 385 | space (pure), on some systems. We have not implemented the | ||
| 386 | remapping on more recent systems because this is less important | ||
| 387 | nowadays than in the days of small memories and timesharing. */ | ||
| 388 | |||
| 389 | EMACS_INT pure[(PURESIZE + sizeof (EMACS_INT) - 1) / sizeof (EMACS_INT)] = {1,}; | ||
| 390 | #define PUREBEG (char *) pure | ||
| 391 | |||
| 392 | /* Pointer to the pure area, and its size. */ | ||
| 393 | |||
| 394 | static char *purebeg; | ||
| 395 | static ptrdiff_t pure_size; | ||
| 396 | |||
| 397 | /* Number of bytes of pure storage used before pure storage overflowed. | ||
| 398 | If this is non-zero, this implies that an overflow occurred. */ | ||
| 399 | |||
| 400 | static ptrdiff_t pure_bytes_used_before_overflow; | ||
| 401 | |||
| 402 | /* Index in pure at which next pure Lisp object will be allocated.. */ | ||
| 403 | |||
| 404 | static ptrdiff_t pure_bytes_used_lisp; | ||
| 405 | |||
| 406 | /* Number of bytes allocated for non-Lisp objects in pure storage. */ | ||
| 407 | |||
| 408 | static ptrdiff_t pure_bytes_used_non_lisp; | ||
| 409 | |||
| 410 | /* If positive, garbage collection is inhibited. Otherwise, zero. */ | 382 | /* If positive, garbage collection is inhibited. Otherwise, zero. */ |
| 411 | 383 | ||
| 412 | intptr_t garbage_collection_inhibited; | 384 | intptr_t garbage_collection_inhibited; |
| @@ -457,7 +429,6 @@ static struct Lisp_Vector *allocate_clear_vector (ptrdiff_t, bool); | |||
| 457 | static void unchain_finalizer (struct Lisp_Finalizer *); | 429 | static void unchain_finalizer (struct Lisp_Finalizer *); |
| 458 | static void mark_terminals (void); | 430 | static void mark_terminals (void); |
| 459 | static void gc_sweep (void); | 431 | static void gc_sweep (void); |
| 460 | static Lisp_Object make_pure_vector (ptrdiff_t); | ||
| 461 | static void mark_buffer (struct buffer *); | 432 | static void mark_buffer (struct buffer *); |
| 462 | 433 | ||
| 463 | #if !defined REL_ALLOC || defined SYSTEM_MALLOC | 434 | #if !defined REL_ALLOC || defined SYSTEM_MALLOC |
| @@ -578,15 +549,13 @@ Lisp_Object const *staticvec[NSTATICS]; | |||
| 578 | 549 | ||
| 579 | int staticidx; | 550 | int staticidx; |
| 580 | 551 | ||
| 581 | static void *pure_alloc (size_t, int); | 552 | #ifndef HAVE_ALIGNED_ALLOC |
| 582 | |||
| 583 | /* Return PTR rounded up to the next multiple of ALIGNMENT. */ | ||
| 584 | |||
| 585 | static void * | 553 | static void * |
| 586 | pointer_align (void *ptr, int alignment) | 554 | pointer_align (void *ptr, int alignment) |
| 587 | { | 555 | { |
| 588 | return (void *) ROUNDUP ((uintptr_t) ptr, alignment); | 556 | return (void *) ROUNDUP ((uintptr_t) ptr, alignment); |
| 589 | } | 557 | } |
| 558 | #endif | ||
| 590 | 559 | ||
| 591 | /* Extract the pointer hidden within O. */ | 560 | /* Extract the pointer hidden within O. */ |
| 592 | 561 | ||
| @@ -1720,12 +1689,30 @@ static ptrdiff_t const STRING_BYTES_MAX = | |||
| 1720 | 1689 | ||
| 1721 | /* Initialize string allocation. Called from init_alloc_once. */ | 1690 | /* Initialize string allocation. Called from init_alloc_once. */ |
| 1722 | 1691 | ||
| 1692 | static struct Lisp_String *allocate_string (void); | ||
| 1693 | static void | ||
| 1694 | allocate_string_data (struct Lisp_String *s, | ||
| 1695 | EMACS_INT nchars, EMACS_INT nbytes, bool clearit, | ||
| 1696 | bool immovable); | ||
| 1697 | |||
| 1723 | static void | 1698 | static void |
| 1724 | init_strings (void) | 1699 | init_strings (void) |
| 1725 | { | 1700 | { |
| 1726 | empty_unibyte_string = make_pure_string ("", 0, 0, 0); | 1701 | /* String allocation code will return one of 'empty_*ibyte_string' |
| 1702 | when asked to construct a new 0-length string, so in order to build | ||
| 1703 | those special cases, we have to do it "by hand". */ | ||
| 1704 | struct Lisp_String *ems = allocate_string (); | ||
| 1705 | struct Lisp_String *eus = allocate_string (); | ||
| 1706 | ems->u.s.intervals = NULL; | ||
| 1707 | eus->u.s.intervals = NULL; | ||
| 1708 | allocate_string_data (ems, 0, 0, false, false); | ||
| 1709 | allocate_string_data (eus, 0, 0, false, false); | ||
| 1710 | /* We can't use 'STRING_SET_UNIBYTE' because this one includes a hack | ||
| 1711 | * to redirect its arg to 'empty_unibyte_string' when nbytes == 0. */ | ||
| 1712 | eus->u.s.size_byte = -1; | ||
| 1713 | XSETSTRING (empty_multibyte_string, ems); | ||
| 1714 | XSETSTRING (empty_unibyte_string, eus); | ||
| 1727 | staticpro (&empty_unibyte_string); | 1715 | staticpro (&empty_unibyte_string); |
| 1728 | empty_multibyte_string = make_pure_string ("", 0, 0, 1); | ||
| 1729 | staticpro (&empty_multibyte_string); | 1716 | staticpro (&empty_multibyte_string); |
| 1730 | } | 1717 | } |
| 1731 | 1718 | ||
| @@ -2924,17 +2911,16 @@ list5 (Lisp_Object arg1, Lisp_Object arg2, Lisp_Object arg3, Lisp_Object arg4, | |||
| 2924 | } | 2911 | } |
| 2925 | 2912 | ||
| 2926 | /* Make a list of COUNT Lisp_Objects, where ARG is the first one. | 2913 | /* Make a list of COUNT Lisp_Objects, where ARG is the first one. |
| 2927 | Use CONS to construct the pairs. AP has any remaining args. */ | 2914 | AP has any remaining args. */ |
| 2928 | static Lisp_Object | 2915 | static Lisp_Object |
| 2929 | cons_listn (ptrdiff_t count, Lisp_Object arg, | 2916 | cons_listn (ptrdiff_t count, Lisp_Object arg, va_list ap) |
| 2930 | Lisp_Object (*cons) (Lisp_Object, Lisp_Object), va_list ap) | ||
| 2931 | { | 2917 | { |
| 2932 | eassume (0 < count); | 2918 | eassume (0 < count); |
| 2933 | Lisp_Object val = cons (arg, Qnil); | 2919 | Lisp_Object val = Fcons (arg, Qnil); |
| 2934 | Lisp_Object tail = val; | 2920 | Lisp_Object tail = val; |
| 2935 | for (ptrdiff_t i = 1; i < count; i++) | 2921 | for (ptrdiff_t i = 1; i < count; i++) |
| 2936 | { | 2922 | { |
| 2937 | Lisp_Object elem = cons (va_arg (ap, Lisp_Object), Qnil); | 2923 | Lisp_Object elem = Fcons (va_arg (ap, Lisp_Object), Qnil); |
| 2938 | XSETCDR (tail, elem); | 2924 | XSETCDR (tail, elem); |
| 2939 | tail = elem; | 2925 | tail = elem; |
| 2940 | } | 2926 | } |
| @@ -2947,18 +2933,7 @@ listn (ptrdiff_t count, Lisp_Object arg1, ...) | |||
| 2947 | { | 2933 | { |
| 2948 | va_list ap; | 2934 | va_list ap; |
| 2949 | va_start (ap, arg1); | 2935 | va_start (ap, arg1); |
| 2950 | Lisp_Object val = cons_listn (count, arg1, Fcons, ap); | 2936 | Lisp_Object val = cons_listn (count, arg1, ap); |
| 2951 | va_end (ap); | ||
| 2952 | return val; | ||
| 2953 | } | ||
| 2954 | |||
| 2955 | /* Make a pure list of COUNT Lisp_Objects, where ARG1 is the first one. */ | ||
| 2956 | Lisp_Object | ||
| 2957 | pure_listn (ptrdiff_t count, Lisp_Object arg1, ...) | ||
| 2958 | { | ||
| 2959 | va_list ap; | ||
| 2960 | va_start (ap, arg1); | ||
| 2961 | Lisp_Object val = cons_listn (count, arg1, pure_cons, ap); | ||
| 2962 | va_end (ap); | 2937 | va_end (ap); |
| 2963 | return val; | 2938 | return val; |
| 2964 | } | 2939 | } |
| @@ -3139,7 +3114,7 @@ static ptrdiff_t last_inserted_vector_free_idx = VECTOR_FREE_LIST_ARRAY_SIZE; | |||
| 3139 | 3114 | ||
| 3140 | static struct large_vector *large_vectors; | 3115 | static struct large_vector *large_vectors; |
| 3141 | 3116 | ||
| 3142 | /* The only vector with 0 slots, allocated from pure space. */ | 3117 | /* The only vector with 0 slots. */ |
| 3143 | 3118 | ||
| 3144 | Lisp_Object zero_vector; | 3119 | Lisp_Object zero_vector; |
| 3145 | 3120 | ||
| @@ -3191,14 +3166,8 @@ allocate_vector_block (void) | |||
| 3191 | return block; | 3166 | return block; |
| 3192 | } | 3167 | } |
| 3193 | 3168 | ||
| 3194 | /* Called once to initialize vector allocation. */ | 3169 | static struct Lisp_Vector * |
| 3195 | 3170 | allocate_vector_from_block (ptrdiff_t nbytes); | |
| 3196 | static void | ||
| 3197 | init_vectors (void) | ||
| 3198 | { | ||
| 3199 | zero_vector = make_pure_vector (0); | ||
| 3200 | staticpro (&zero_vector); | ||
| 3201 | } | ||
| 3202 | 3171 | ||
| 3203 | /* Memory footprint in bytes of a pseudovector other than a bool-vector. */ | 3172 | /* Memory footprint in bytes of a pseudovector other than a bool-vector. */ |
| 3204 | static ptrdiff_t | 3173 | static ptrdiff_t |
| @@ -3211,6 +3180,31 @@ pseudovector_nbytes (const union vectorlike_header *hdr) | |||
| 3211 | return vroundup (header_size + word_size * nwords); | 3180 | return vroundup (header_size + word_size * nwords); |
| 3212 | } | 3181 | } |
| 3213 | 3182 | ||
| 3183 | /* Called once to initialize vector allocation. */ | ||
| 3184 | |||
| 3185 | static void | ||
| 3186 | init_vectors (void) | ||
| 3187 | { | ||
| 3188 | /* The normal vector allocation code refuses to allocate a 0-length vector | ||
| 3189 | because we use the first field of vectors internally when they're on | ||
| 3190 | the free list, so we can't put a zero-length vector on the free list. | ||
| 3191 | This is not a problem for 'zero_vector' since it's always reachable. | ||
| 3192 | An alternative approach would be to allocate zero_vector outside of the | ||
| 3193 | normal heap, e.g. as a static object, and then to "hide" it from the GC, | ||
| 3194 | for example by marking it by hand at the beginning of the GC and unmarking | ||
| 3195 | it by hand at the end. */ | ||
| 3196 | struct vector_block *block = allocate_vector_block (); | ||
| 3197 | struct Lisp_Vector *zv = (struct Lisp_Vector *)block->data; | ||
| 3198 | zv->header.size = 0; | ||
| 3199 | ssize_t nbytes = pseudovector_nbytes (&zv->header); | ||
| 3200 | ssize_t restbytes = VECTOR_BLOCK_BYTES - nbytes; | ||
| 3201 | eassert (restbytes % roundup_size == 0); | ||
| 3202 | setup_on_free_list (ADVANCE (zv, nbytes), restbytes); | ||
| 3203 | |||
| 3204 | zero_vector = make_lisp_ptr (zv, Lisp_Vectorlike); | ||
| 3205 | staticpro (&zero_vector); | ||
| 3206 | } | ||
| 3207 | |||
| 3214 | /* Allocate vector from a vector block. */ | 3208 | /* Allocate vector from a vector block. */ |
| 3215 | 3209 | ||
| 3216 | static struct Lisp_Vector * | 3210 | static struct Lisp_Vector * |
| @@ -5657,320 +5651,8 @@ hash_table_free_bytes (void *p, ptrdiff_t nbytes) | |||
| 5657 | } | 5651 | } |
| 5658 | 5652 | ||
| 5659 | 5653 | ||
| 5660 | /*********************************************************************** | ||
| 5661 | Pure Storage Management | ||
| 5662 | ***********************************************************************/ | ||
| 5663 | |||
| 5664 | /* Allocate room for SIZE bytes from pure Lisp storage and return a | ||
| 5665 | pointer to it. TYPE is the Lisp type for which the memory is | ||
| 5666 | allocated. TYPE < 0 means it's not used for a Lisp object, | ||
| 5667 | and that the result should have an alignment of -TYPE. | ||
| 5668 | |||
| 5669 | The bytes are initially zero. | ||
| 5670 | |||
| 5671 | If pure space is exhausted, allocate space from the heap. This is | ||
| 5672 | merely an expedient to let Emacs warn that pure space was exhausted | ||
| 5673 | and that Emacs should be rebuilt with a larger pure space. */ | ||
| 5674 | |||
| 5675 | static void * | ||
| 5676 | pure_alloc (size_t size, int type) | ||
| 5677 | { | ||
| 5678 | void *result; | ||
| 5679 | static bool pure_overflow_warned = false; | ||
| 5680 | |||
| 5681 | again: | ||
| 5682 | if (type >= 0) | ||
| 5683 | { | ||
| 5684 | /* Allocate space for a Lisp object from the beginning of the free | ||
| 5685 | space with taking account of alignment. */ | ||
| 5686 | result = pointer_align (purebeg + pure_bytes_used_lisp, LISP_ALIGNMENT); | ||
| 5687 | pure_bytes_used_lisp = ((char *)result - (char *)purebeg) + size; | ||
| 5688 | } | ||
| 5689 | else | ||
| 5690 | { | ||
| 5691 | /* Allocate space for a non-Lisp object from the end of the free | ||
| 5692 | space. */ | ||
| 5693 | ptrdiff_t unaligned_non_lisp = pure_bytes_used_non_lisp + size; | ||
| 5694 | char *unaligned = purebeg + pure_size - unaligned_non_lisp; | ||
| 5695 | int decr = (intptr_t) unaligned & (-1 - type); | ||
| 5696 | pure_bytes_used_non_lisp = unaligned_non_lisp + decr; | ||
| 5697 | result = unaligned - decr; | ||
| 5698 | } | ||
| 5699 | pure_bytes_used = pure_bytes_used_lisp + pure_bytes_used_non_lisp; | ||
| 5700 | |||
| 5701 | if (pure_bytes_used <= pure_size) | ||
| 5702 | return result; | ||
| 5703 | |||
| 5704 | if (!pure_overflow_warned) | ||
| 5705 | { | ||
| 5706 | message ("Pure Lisp storage overflowed"); | ||
| 5707 | pure_overflow_warned = true; | ||
| 5708 | } | ||
| 5709 | |||
| 5710 | /* Don't allocate a large amount here, | ||
| 5711 | because it might get mmap'd and then its address | ||
| 5712 | might not be usable. */ | ||
| 5713 | int small_amount = 10000; | ||
| 5714 | eassert (size <= small_amount - LISP_ALIGNMENT); | ||
| 5715 | purebeg = xzalloc (small_amount); | ||
| 5716 | pure_size = small_amount; | ||
| 5717 | pure_bytes_used_before_overflow += pure_bytes_used - size; | ||
| 5718 | pure_bytes_used = 0; | ||
| 5719 | pure_bytes_used_lisp = pure_bytes_used_non_lisp = 0; | ||
| 5720 | |||
| 5721 | /* Can't GC if pure storage overflowed because we can't determine | ||
| 5722 | if something is a pure object or not. */ | ||
| 5723 | garbage_collection_inhibited++; | ||
| 5724 | goto again; | ||
| 5725 | } | ||
| 5726 | |||
| 5727 | /* Print a warning if PURESIZE is too small. */ | ||
| 5728 | |||
| 5729 | void | ||
| 5730 | check_pure_size (void) | ||
| 5731 | { | ||
| 5732 | if (pure_bytes_used_before_overflow) | ||
| 5733 | message (("emacs:0:Pure Lisp storage overflow (approx. %jd" | ||
| 5734 | " bytes needed)"), | ||
| 5735 | pure_bytes_used + pure_bytes_used_before_overflow); | ||
| 5736 | } | ||
| 5737 | |||
| 5738 | /* Find the byte sequence {DATA[0], ..., DATA[NBYTES-1], '\0'} from | ||
| 5739 | the non-Lisp data pool of the pure storage, and return its start | ||
| 5740 | address. Return NULL if not found. */ | ||
| 5741 | |||
| 5742 | static char * | ||
| 5743 | find_string_data_in_pure (const char *data, ptrdiff_t nbytes) | ||
| 5744 | { | ||
| 5745 | int i; | ||
| 5746 | ptrdiff_t skip, bm_skip[256], last_char_skip, infinity, start, start_max; | ||
| 5747 | const unsigned char *p; | ||
| 5748 | char *non_lisp_beg; | ||
| 5749 | |||
| 5750 | if (pure_bytes_used_non_lisp <= nbytes) | ||
| 5751 | return NULL; | ||
| 5752 | |||
| 5753 | /* The Android GCC generates code like: | ||
| 5754 | |||
| 5755 | 0xa539e755 <+52>: lea 0x430(%esp),%esi | ||
| 5756 | => 0xa539e75c <+59>: movdqa %xmm0,0x0(%ebp) | ||
| 5757 | 0xa539e761 <+64>: add $0x10,%ebp | ||
| 5758 | |||
| 5759 | but data is not aligned appropriately, so a GP fault results. */ | ||
| 5760 | |||
| 5761 | #if defined __i386__ \ | ||
| 5762 | && defined HAVE_ANDROID \ | ||
| 5763 | && !defined ANDROID_STUBIFY \ | ||
| 5764 | && !defined (__clang__) | ||
| 5765 | if ((intptr_t) data & 15) | ||
| 5766 | return NULL; | ||
| 5767 | #endif | ||
| 5768 | |||
| 5769 | /* Set up the Boyer-Moore table. */ | ||
| 5770 | skip = nbytes + 1; | ||
| 5771 | for (i = 0; i < 256; i++) | ||
| 5772 | bm_skip[i] = skip; | ||
| 5773 | |||
| 5774 | p = (const unsigned char *) data; | ||
| 5775 | while (--skip > 0) | ||
| 5776 | bm_skip[*p++] = skip; | ||
| 5777 | |||
| 5778 | last_char_skip = bm_skip['\0']; | ||
| 5779 | |||
| 5780 | non_lisp_beg = purebeg + pure_size - pure_bytes_used_non_lisp; | ||
| 5781 | start_max = pure_bytes_used_non_lisp - (nbytes + 1); | ||
| 5782 | |||
| 5783 | /* See the comments in the function `boyer_moore' (search.c) for the | ||
| 5784 | use of `infinity'. */ | ||
| 5785 | infinity = pure_bytes_used_non_lisp + 1; | ||
| 5786 | bm_skip['\0'] = infinity; | ||
| 5787 | |||
| 5788 | p = (const unsigned char *) non_lisp_beg + nbytes; | ||
| 5789 | start = 0; | ||
| 5790 | do | ||
| 5791 | { | ||
| 5792 | /* Check the last character (== '\0'). */ | ||
| 5793 | do | ||
| 5794 | { | ||
| 5795 | start += bm_skip[*(p + start)]; | ||
| 5796 | } | ||
| 5797 | while (start <= start_max); | ||
| 5798 | |||
| 5799 | if (start < infinity) | ||
| 5800 | /* Couldn't find the last character. */ | ||
| 5801 | return NULL; | ||
| 5802 | |||
| 5803 | /* No less than `infinity' means we could find the last | ||
| 5804 | character at `p[start - infinity]'. */ | ||
| 5805 | start -= infinity; | ||
| 5806 | |||
| 5807 | /* Check the remaining characters. */ | ||
| 5808 | if (memcmp (data, non_lisp_beg + start, nbytes) == 0) | ||
| 5809 | /* Found. */ | ||
| 5810 | return non_lisp_beg + start; | ||
| 5811 | |||
| 5812 | start += last_char_skip; | ||
| 5813 | } | ||
| 5814 | while (start <= start_max); | ||
| 5815 | |||
| 5816 | return NULL; | ||
| 5817 | } | ||
| 5818 | |||
| 5819 | |||
| 5820 | /* Return a string allocated in pure space. DATA is a buffer holding | ||
| 5821 | NCHARS characters, and NBYTES bytes of string data. MULTIBYTE | ||
| 5822 | means make the result string multibyte. | ||
| 5823 | |||
| 5824 | Must get an error if pure storage is full, since if it cannot hold | ||
| 5825 | a large string it may be able to hold conses that point to that | ||
| 5826 | string; then the string is not protected from gc. */ | ||
| 5827 | |||
| 5828 | Lisp_Object | ||
| 5829 | make_pure_string (const char *data, | ||
| 5830 | ptrdiff_t nchars, ptrdiff_t nbytes, bool multibyte) | ||
| 5831 | { | ||
| 5832 | Lisp_Object string; | ||
| 5833 | struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String); | ||
| 5834 | s->u.s.data = (unsigned char *) find_string_data_in_pure (data, nbytes); | ||
| 5835 | if (s->u.s.data == NULL) | ||
| 5836 | { | ||
| 5837 | s->u.s.data = pure_alloc (nbytes + 1, -1); | ||
| 5838 | memcpy (s->u.s.data, data, nbytes); | ||
| 5839 | s->u.s.data[nbytes] = '\0'; | ||
| 5840 | } | ||
| 5841 | s->u.s.size = nchars; | ||
| 5842 | s->u.s.size_byte = multibyte ? nbytes : -1; | ||
| 5843 | s->u.s.intervals = NULL; | ||
| 5844 | XSETSTRING (string, s); | ||
| 5845 | return string; | ||
| 5846 | } | ||
| 5847 | |||
| 5848 | /* Return a string allocated in pure space. Do not | ||
| 5849 | allocate the string data, just point to DATA. */ | ||
| 5850 | |||
| 5851 | Lisp_Object | ||
| 5852 | make_pure_c_string (const char *data, ptrdiff_t nchars) | ||
| 5853 | { | ||
| 5854 | Lisp_Object string; | ||
| 5855 | struct Lisp_String *s = pure_alloc (sizeof *s, Lisp_String); | ||
| 5856 | s->u.s.size = nchars; | ||
| 5857 | s->u.s.size_byte = -2; | ||
| 5858 | s->u.s.data = (unsigned char *) data; | ||
| 5859 | s->u.s.intervals = NULL; | ||
| 5860 | XSETSTRING (string, s); | ||
| 5861 | return string; | ||
| 5862 | } | ||
| 5863 | |||
| 5864 | static Lisp_Object purecopy (Lisp_Object obj); | 5654 | static Lisp_Object purecopy (Lisp_Object obj); |
| 5865 | 5655 | ||
| 5866 | /* Return a cons allocated from pure space. Give it pure copies | ||
| 5867 | of CAR as car and CDR as cdr. */ | ||
| 5868 | |||
| 5869 | Lisp_Object | ||
| 5870 | pure_cons (Lisp_Object car, Lisp_Object cdr) | ||
| 5871 | { | ||
| 5872 | Lisp_Object new; | ||
| 5873 | struct Lisp_Cons *p = pure_alloc (sizeof *p, Lisp_Cons); | ||
| 5874 | XSETCONS (new, p); | ||
| 5875 | XSETCAR (new, purecopy (car)); | ||
| 5876 | XSETCDR (new, purecopy (cdr)); | ||
| 5877 | return new; | ||
| 5878 | } | ||
| 5879 | |||
| 5880 | |||
| 5881 | /* Value is a float object with value NUM allocated from pure space. */ | ||
| 5882 | |||
| 5883 | static Lisp_Object | ||
| 5884 | make_pure_float (double num) | ||
| 5885 | { | ||
| 5886 | Lisp_Object new; | ||
| 5887 | struct Lisp_Float *p = pure_alloc (sizeof *p, Lisp_Float); | ||
| 5888 | XSETFLOAT (new, p); | ||
| 5889 | XFLOAT_INIT (new, num); | ||
| 5890 | return new; | ||
| 5891 | } | ||
| 5892 | |||
| 5893 | /* Value is a bignum object with value VALUE allocated from pure | ||
| 5894 | space. */ | ||
| 5895 | |||
| 5896 | static Lisp_Object | ||
| 5897 | make_pure_bignum (Lisp_Object value) | ||
| 5898 | { | ||
| 5899 | mpz_t const *n = xbignum_val (value); | ||
| 5900 | size_t i, nlimbs = mpz_size (*n); | ||
| 5901 | size_t nbytes = nlimbs * sizeof (mp_limb_t); | ||
| 5902 | mp_limb_t *pure_limbs; | ||
| 5903 | mp_size_t new_size; | ||
| 5904 | |||
| 5905 | struct Lisp_Bignum *b = pure_alloc (sizeof *b, Lisp_Vectorlike); | ||
| 5906 | XSETPVECTYPESIZE (b, PVEC_BIGNUM, 0, VECSIZE (struct Lisp_Bignum)); | ||
| 5907 | |||
| 5908 | int limb_alignment = alignof (mp_limb_t); | ||
| 5909 | pure_limbs = pure_alloc (nbytes, - limb_alignment); | ||
| 5910 | for (i = 0; i < nlimbs; ++i) | ||
| 5911 | pure_limbs[i] = mpz_getlimbn (*n, i); | ||
| 5912 | |||
| 5913 | new_size = nlimbs; | ||
| 5914 | if (mpz_sgn (*n) < 0) | ||
| 5915 | new_size = -new_size; | ||
| 5916 | |||
| 5917 | mpz_roinit_n (b->value, pure_limbs, new_size); | ||
| 5918 | |||
| 5919 | return make_lisp_ptr (b, Lisp_Vectorlike); | ||
| 5920 | } | ||
| 5921 | |||
| 5922 | /* Return a vector with room for LEN Lisp_Objects allocated from | ||
| 5923 | pure space. */ | ||
| 5924 | |||
| 5925 | static Lisp_Object | ||
| 5926 | make_pure_vector (ptrdiff_t len) | ||
| 5927 | { | ||
| 5928 | Lisp_Object new; | ||
| 5929 | size_t size = header_size + len * word_size; | ||
| 5930 | struct Lisp_Vector *p = pure_alloc (size, Lisp_Vectorlike); | ||
| 5931 | XSETVECTOR (new, p); | ||
| 5932 | XVECTOR (new)->header.size = len; | ||
| 5933 | return new; | ||
| 5934 | } | ||
| 5935 | |||
| 5936 | /* Copy all contents and parameters of TABLE to a new table allocated | ||
| 5937 | from pure space, return the purified table. */ | ||
| 5938 | static struct Lisp_Hash_Table * | ||
| 5939 | purecopy_hash_table (struct Lisp_Hash_Table *table) | ||
| 5940 | { | ||
| 5941 | eassert (table->weakness == Weak_None); | ||
| 5942 | eassert (table->purecopy); | ||
| 5943 | |||
| 5944 | struct Lisp_Hash_Table *pure = pure_alloc (sizeof *pure, Lisp_Vectorlike); | ||
| 5945 | *pure = *table; | ||
| 5946 | pure->mutable = false; | ||
| 5947 | |||
| 5948 | if (table->table_size > 0) | ||
| 5949 | { | ||
| 5950 | ptrdiff_t hash_bytes = table->table_size * sizeof *table->hash; | ||
| 5951 | pure->hash = pure_alloc (hash_bytes, -(int)sizeof *table->hash); | ||
| 5952 | memcpy (pure->hash, table->hash, hash_bytes); | ||
| 5953 | |||
| 5954 | ptrdiff_t next_bytes = table->table_size * sizeof *table->next; | ||
| 5955 | pure->next = pure_alloc (next_bytes, -(int)sizeof *table->next); | ||
| 5956 | memcpy (pure->next, table->next, next_bytes); | ||
| 5957 | |||
| 5958 | ptrdiff_t nvalues = table->table_size * 2; | ||
| 5959 | ptrdiff_t kv_bytes = nvalues * sizeof *table->key_and_value; | ||
| 5960 | pure->key_and_value = pure_alloc (kv_bytes, | ||
| 5961 | -(int)sizeof *table->key_and_value); | ||
| 5962 | for (ptrdiff_t i = 0; i < nvalues; i++) | ||
| 5963 | pure->key_and_value[i] = purecopy (table->key_and_value[i]); | ||
| 5964 | |||
| 5965 | ptrdiff_t index_bytes = hash_table_index_size (table) | ||
| 5966 | * sizeof *table->index; | ||
| 5967 | pure->index = pure_alloc (index_bytes, -(int)sizeof *table->index); | ||
| 5968 | memcpy (pure->index, table->index, index_bytes); | ||
| 5969 | } | ||
| 5970 | |||
| 5971 | return pure; | ||
| 5972 | } | ||
| 5973 | |||
| 5974 | DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0, | 5656 | DEFUN ("purecopy", Fpurecopy, Spurecopy, 1, 1, 0, |
| 5975 | doc: /* Make a copy of object OBJ in pure storage. | 5657 | doc: /* Make a copy of object OBJ in pure storage. |
| 5976 | Recursively copies contents of vectors and cons cells. | 5658 | Recursively copies contents of vectors and cons cells. |
| @@ -5996,89 +5678,17 @@ static struct pinned_object | |||
| 5996 | static Lisp_Object | 5678 | static Lisp_Object |
| 5997 | purecopy (Lisp_Object obj) | 5679 | purecopy (Lisp_Object obj) |
| 5998 | { | 5680 | { |
| 5999 | if (FIXNUMP (obj) | 5681 | if (FIXNUMP (obj) || SUBRP (obj)) |
| 6000 | || (! SYMBOLP (obj) && PURE_P (XPNTR (obj))) | 5682 | return obj; /* No need to hash. */ |
| 6001 | || SUBRP (obj)) | ||
| 6002 | return obj; /* Already pure. */ | ||
| 6003 | |||
| 6004 | if (STRINGP (obj) && XSTRING (obj)->u.s.intervals) | ||
| 6005 | message_with_string ("Dropping text-properties while making string `%s' pure", | ||
| 6006 | obj, true); | ||
| 6007 | 5683 | ||
| 6008 | if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing. */ | 5684 | if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing. */ |
| 6009 | { | 5685 | { |
| 6010 | Lisp_Object tmp = Fgethash (obj, Vpurify_flag, Qnil); | 5686 | Lisp_Object tmp = Fgethash (obj, Vpurify_flag, Qnil); |
| 6011 | if (!NILP (tmp)) | 5687 | if (!NILP (tmp)) |
| 6012 | return tmp; | 5688 | return tmp; |
| 5689 | Fputhash (obj, obj, Vpurify_flag); | ||
| 6013 | } | 5690 | } |
| 6014 | 5691 | ||
| 6015 | if (CONSP (obj)) | ||
| 6016 | obj = pure_cons (XCAR (obj), XCDR (obj)); | ||
| 6017 | else if (FLOATP (obj)) | ||
| 6018 | obj = make_pure_float (XFLOAT_DATA (obj)); | ||
| 6019 | else if (STRINGP (obj)) | ||
| 6020 | obj = make_pure_string (SSDATA (obj), SCHARS (obj), | ||
| 6021 | SBYTES (obj), | ||
| 6022 | STRING_MULTIBYTE (obj)); | ||
| 6023 | else if (HASH_TABLE_P (obj)) | ||
| 6024 | { | ||
| 6025 | struct Lisp_Hash_Table *table = XHASH_TABLE (obj); | ||
| 6026 | /* Do not purify hash tables which haven't been defined with | ||
| 6027 | :purecopy as non-nil or are weak - they aren't guaranteed to | ||
| 6028 | not change. */ | ||
| 6029 | if (table->weakness != Weak_None || !table->purecopy) | ||
| 6030 | { | ||
| 6031 | /* Instead, add the hash table to the list of pinned objects, | ||
| 6032 | so that it will be marked during GC. */ | ||
| 6033 | struct pinned_object *o = xmalloc (sizeof *o); | ||
| 6034 | o->object = obj; | ||
| 6035 | o->next = pinned_objects; | ||
| 6036 | pinned_objects = o; | ||
| 6037 | return obj; /* Don't hash cons it. */ | ||
| 6038 | } | ||
| 6039 | |||
| 6040 | obj = make_lisp_hash_table (purecopy_hash_table (table)); | ||
| 6041 | } | ||
| 6042 | else if (CLOSUREP (obj) || VECTORP (obj) || RECORDP (obj)) | ||
| 6043 | { | ||
| 6044 | struct Lisp_Vector *objp = XVECTOR (obj); | ||
| 6045 | ptrdiff_t nbytes = vector_nbytes (objp); | ||
| 6046 | struct Lisp_Vector *vec = pure_alloc (nbytes, Lisp_Vectorlike); | ||
| 6047 | register ptrdiff_t i; | ||
| 6048 | ptrdiff_t size = ASIZE (obj); | ||
| 6049 | if (size & PSEUDOVECTOR_FLAG) | ||
| 6050 | size &= PSEUDOVECTOR_SIZE_MASK; | ||
| 6051 | memcpy (vec, objp, nbytes); | ||
| 6052 | for (i = 0; i < size; i++) | ||
| 6053 | vec->contents[i] = purecopy (vec->contents[i]); | ||
| 6054 | /* Byte code strings must be pinned. */ | ||
| 6055 | if (CLOSUREP (obj) && size >= 2 && STRINGP (vec->contents[1]) | ||
| 6056 | && !STRING_MULTIBYTE (vec->contents[1])) | ||
| 6057 | pin_string (vec->contents[1]); | ||
| 6058 | XSETVECTOR (obj, vec); | ||
| 6059 | } | ||
| 6060 | else if (BARE_SYMBOL_P (obj)) | ||
| 6061 | { | ||
| 6062 | if (!XBARE_SYMBOL (obj)->u.s.pinned && !c_symbol_p (XBARE_SYMBOL (obj))) | ||
| 6063 | { /* We can't purify them, but they appear in many pure objects. | ||
| 6064 | Mark them as `pinned' so we know to mark them at every GC cycle. */ | ||
| 6065 | XBARE_SYMBOL (obj)->u.s.pinned = true; | ||
| 6066 | symbol_block_pinned = symbol_block; | ||
| 6067 | } | ||
| 6068 | /* Don't hash-cons it. */ | ||
| 6069 | return obj; | ||
| 6070 | } | ||
| 6071 | else if (BIGNUMP (obj)) | ||
| 6072 | obj = make_pure_bignum (obj); | ||
| 6073 | else | ||
| 6074 | { | ||
| 6075 | AUTO_STRING (fmt, "Don't know how to purify: %S"); | ||
| 6076 | Fsignal (Qerror, list1 (CALLN (Fformat, fmt, obj))); | ||
| 6077 | } | ||
| 6078 | |||
| 6079 | if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing. */ | ||
| 6080 | Fputhash (obj, obj, Vpurify_flag); | ||
| 6081 | |||
| 6082 | return obj; | 5692 | return obj; |
| 6083 | } | 5693 | } |
| 6084 | 5694 | ||
| @@ -8093,8 +7703,6 @@ init_alloc_once (void) | |||
| 8093 | static void | 7703 | static void |
| 8094 | init_alloc_once_for_pdumper (void) | 7704 | init_alloc_once_for_pdumper (void) |
| 8095 | { | 7705 | { |
| 8096 | purebeg = PUREBEG; | ||
| 8097 | pure_size = PURESIZE; | ||
| 8098 | mem_init (); | 7706 | mem_init (); |
| 8099 | 7707 | ||
| 8100 | #ifdef DOUG_LEA_MALLOC | 7708 | #ifdef DOUG_LEA_MALLOC |
| @@ -8148,7 +7756,7 @@ If this portion is smaller than `gc-cons-threshold', this is ignored. */); | |||
| 8148 | Vgc_cons_percentage = make_float (0.1); | 7756 | Vgc_cons_percentage = make_float (0.1); |
| 8149 | 7757 | ||
| 8150 | DEFVAR_INT ("pure-bytes-used", pure_bytes_used, | 7758 | DEFVAR_INT ("pure-bytes-used", pure_bytes_used, |
| 8151 | doc: /* Number of bytes of shareable Lisp data allocated so far. */); | 7759 | doc: /* No longer used. */); |
| 8152 | 7760 | ||
| 8153 | DEFVAR_INT ("cons-cells-consed", cons_cells_consed, | 7761 | DEFVAR_INT ("cons-cells-consed", cons_cells_consed, |
| 8154 | doc: /* Number of cons cells that have been consed so far. */); | 7762 | doc: /* Number of cons cells that have been consed so far. */); |
| @@ -8174,9 +7782,13 @@ If this portion is smaller than `gc-cons-threshold', this is ignored. */); | |||
| 8174 | 7782 | ||
| 8175 | DEFVAR_LISP ("purify-flag", Vpurify_flag, | 7783 | DEFVAR_LISP ("purify-flag", Vpurify_flag, |
| 8176 | doc: /* Non-nil means loading Lisp code in order to dump an executable. | 7784 | doc: /* Non-nil means loading Lisp code in order to dump an executable. |
| 8177 | This means that certain objects should be allocated in shared (pure) space. | 7785 | This used to mean that certain objects should be allocated in shared (pure) |
| 8178 | It can also be set to a hash-table, in which case this table is used to | 7786 | space. It can also be set to a hash-table, in which case this table is used |
| 8179 | do hash-consing of the objects allocated to pure space. */); | 7787 | to do hash-consing of the objects allocated to pure space. |
| 7788 | The hash-consing still applies, but objects are not allocated in pure | ||
| 7789 | storage any more. | ||
| 7790 | This flag is still used in a few places not to decide where objects are | ||
| 7791 | allocated but to know if we're in the preload phase of Emacs's build. */); | ||
| 8180 | 7792 | ||
| 8181 | DEFVAR_BOOL ("garbage-collection-messages", garbage_collection_messages, | 7793 | DEFVAR_BOOL ("garbage-collection-messages", garbage_collection_messages, |
| 8182 | doc: /* Non-nil means display messages at start and end of garbage collection. */); | 7794 | doc: /* Non-nil means display messages at start and end of garbage collection. */); |