diff options
| author | Stefan Monnier | 2014-04-07 12:08:46 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2014-04-07 12:08:46 -0400 |
| commit | e3b838807bf9fbbbec9826de6c1e4efdf72acb78 (patch) | |
| tree | af955b069b9dab5d52cfed618cf1f2f7cffa40f5 /src | |
| parent | 190f899aed4eeb62286874bda47a92236d52ad4c (diff) | |
| download | emacs-e3b838807bf9fbbbec9826de6c1e4efdf72acb78.tar.gz emacs-e3b838807bf9fbbbec9826de6c1e4efdf72acb78.zip | |
* src/alloc.c: Keep track of symbols referenced from pure space (bug#17168).
(symbol_block_pinned): New var.
(Fmake_symbol): Initialize `pinned'.
(purecopy): New function, extracted from Fpurecopy. Mark symbols as
pinned and signal an error for un-purifiable objects.
(pure_cons): Use it.
(Fpurecopy): Use it, except for objects that can't be purified.
(mark_pinned_symbols): New function.
(Fgarbage_collect): Use it.
(gc_sweep): Remove hack made unnecessary.
* src/lisp.h (struct Lisp_Symbol): New bitfield `pinned'.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 15 | ||||
| -rw-r--r-- | src/alloc.c | 83 | ||||
| -rw-r--r-- | src/lisp.h | 3 |
3 files changed, 82 insertions, 19 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 9b084701933..7618fb202e0 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,18 @@ | |||
| 1 | 2014-04-07 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * lisp.h (struct Lisp_Symbol): New bitfield `pinned'. | ||
| 4 | |||
| 5 | * alloc.c: Keep track of symbols referenced from pure space (bug#17168). | ||
| 6 | (symbol_block_pinned): New var. | ||
| 7 | (Fmake_symbol): Initialize `pinned'. | ||
| 8 | (purecopy): New function, extracted from Fpurecopy. Mark symbols as | ||
| 9 | pinned and signal an error for un-purifiable objects. | ||
| 10 | (pure_cons): Use it. | ||
| 11 | (Fpurecopy): Use it, except for objects that can't be purified. | ||
| 12 | (mark_pinned_symbols): New function. | ||
| 13 | (Fgarbage_collect): Use it. | ||
| 14 | (gc_sweep): Remove hack made unnecessary. | ||
| 15 | |||
| 1 | 2014-04-05 Glenn Morris <rgm@gnu.org> | 16 | 2014-04-05 Glenn Morris <rgm@gnu.org> |
| 2 | 17 | ||
| 3 | * keyboard.c (Fopen_dribble_file): Doc tweak. | 18 | * keyboard.c (Fopen_dribble_file): Doc tweak. |
diff --git a/src/alloc.c b/src/alloc.c index 62c3beec1d2..d4e24b6244b 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -3316,6 +3316,13 @@ struct symbol_block | |||
| 3316 | 3316 | ||
| 3317 | static struct symbol_block *symbol_block; | 3317 | static struct symbol_block *symbol_block; |
| 3318 | static int symbol_block_index = SYMBOL_BLOCK_SIZE; | 3318 | static int symbol_block_index = SYMBOL_BLOCK_SIZE; |
| 3319 | /* Pointer to the first symbol_block that contains pinned symbols. | ||
| 3320 | Tests for 24.4 showed that at dump-time, Emacs contains about 15K symbols, | ||
| 3321 | 10K of which are pinned (and all but 250 of them are interned in obarray), | ||
| 3322 | whereas a "typical session" has in the order of 30K symbols. | ||
| 3323 | `symbol_block_pinned' lets mark_pinned_symbols scan only 15K symbols rather | ||
| 3324 | than 30K to find the 10K symbols we need to mark. */ | ||
| 3325 | static struct symbol_block *symbol_block_pinned; | ||
| 3319 | 3326 | ||
| 3320 | /* List of free symbols. */ | 3327 | /* List of free symbols. */ |
| 3321 | 3328 | ||
| @@ -3368,10 +3375,11 @@ Its value is void, and its function definition and property list are nil. */) | |||
| 3368 | SET_SYMBOL_VAL (p, Qunbound); | 3375 | SET_SYMBOL_VAL (p, Qunbound); |
| 3369 | set_symbol_function (val, Qnil); | 3376 | set_symbol_function (val, Qnil); |
| 3370 | set_symbol_next (val, NULL); | 3377 | set_symbol_next (val, NULL); |
| 3371 | p->gcmarkbit = 0; | 3378 | p->gcmarkbit = false; |
| 3372 | p->interned = SYMBOL_UNINTERNED; | 3379 | p->interned = SYMBOL_UNINTERNED; |
| 3373 | p->constant = 0; | 3380 | p->constant = 0; |
| 3374 | p->declared_special = 0; | 3381 | p->declared_special = false; |
| 3382 | p->pinned = false; | ||
| 3375 | consing_since_gc += sizeof (struct Lisp_Symbol); | 3383 | consing_since_gc += sizeof (struct Lisp_Symbol); |
| 3376 | symbols_consed++; | 3384 | symbols_consed++; |
| 3377 | total_free_symbols--; | 3385 | total_free_symbols--; |
| @@ -5173,6 +5181,8 @@ make_pure_c_string (const char *data, ptrdiff_t nchars) | |||
| 5173 | return string; | 5181 | return string; |
| 5174 | } | 5182 | } |
| 5175 | 5183 | ||
| 5184 | static Lisp_Object purecopy (Lisp_Object obj); | ||
| 5185 | |||
| 5176 | /* Return a cons allocated from pure space. Give it pure copies | 5186 | /* Return a cons allocated from pure space. Give it pure copies |
| 5177 | of CAR as car and CDR as cdr. */ | 5187 | of CAR as car and CDR as cdr. */ |
| 5178 | 5188 | ||
| @@ -5182,8 +5192,8 @@ pure_cons (Lisp_Object car, Lisp_Object cdr) | |||
| 5182 | Lisp_Object new; | 5192 | Lisp_Object new; |
| 5183 | struct Lisp_Cons *p = pure_alloc (sizeof *p, Lisp_Cons); | 5193 | struct Lisp_Cons *p = pure_alloc (sizeof *p, Lisp_Cons); |
| 5184 | XSETCONS (new, p); | 5194 | XSETCONS (new, p); |
| 5185 | XSETCAR (new, Fpurecopy (car)); | 5195 | XSETCAR (new, purecopy (car)); |
| 5186 | XSETCDR (new, Fpurecopy (cdr)); | 5196 | XSETCDR (new, purecopy (cdr)); |
| 5187 | return new; | 5197 | return new; |
| 5188 | } | 5198 | } |
| 5189 | 5199 | ||
| @@ -5224,9 +5234,19 @@ Does not copy symbols. Copies strings without text properties. */) | |||
| 5224 | { | 5234 | { |
| 5225 | if (NILP (Vpurify_flag)) | 5235 | if (NILP (Vpurify_flag)) |
| 5226 | return obj; | 5236 | return obj; |
| 5227 | 5237 | else if (MARKERP (obj) || OVERLAYP (obj) | |
| 5228 | if (PURE_POINTER_P (XPNTR (obj))) | 5238 | || HASH_TABLE_P (obj) || SYMBOLP (obj)) |
| 5239 | /* Can't purify those. */ | ||
| 5229 | return obj; | 5240 | return obj; |
| 5241 | else | ||
| 5242 | return purecopy (obj); | ||
| 5243 | } | ||
| 5244 | |||
| 5245 | static Lisp_Object | ||
| 5246 | purecopy (Lisp_Object obj) | ||
| 5247 | { | ||
| 5248 | if (PURE_POINTER_P (XPNTR (obj)) || INTEGERP (obj) || SUBRP (obj)) | ||
| 5249 | return obj; /* Already pure. */ | ||
| 5230 | 5250 | ||
| 5231 | if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing. */ | 5251 | if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing. */ |
| 5232 | { | 5252 | { |
| @@ -5254,7 +5274,7 @@ Does not copy symbols. Copies strings without text properties. */) | |||
| 5254 | size &= PSEUDOVECTOR_SIZE_MASK; | 5274 | size &= PSEUDOVECTOR_SIZE_MASK; |
| 5255 | vec = XVECTOR (make_pure_vector (size)); | 5275 | vec = XVECTOR (make_pure_vector (size)); |
| 5256 | for (i = 0; i < size; i++) | 5276 | for (i = 0; i < size; i++) |
| 5257 | vec->contents[i] = Fpurecopy (AREF (obj, i)); | 5277 | vec->contents[i] = purecopy (AREF (obj, i)); |
| 5258 | if (COMPILEDP (obj)) | 5278 | if (COMPILEDP (obj)) |
| 5259 | { | 5279 | { |
| 5260 | XSETPVECTYPE (vec, PVEC_COMPILED); | 5280 | XSETPVECTYPE (vec, PVEC_COMPILED); |
| @@ -5263,11 +5283,23 @@ Does not copy symbols. Copies strings without text properties. */) | |||
| 5263 | else | 5283 | else |
| 5264 | XSETVECTOR (obj, vec); | 5284 | XSETVECTOR (obj, vec); |
| 5265 | } | 5285 | } |
| 5266 | else if (MARKERP (obj)) | 5286 | else if (SYMBOLP (obj)) |
| 5267 | error ("Attempt to copy a marker to pure storage"); | 5287 | { |
| 5288 | if (!XSYMBOL (obj)->pinned) | ||
| 5289 | { /* We can't purify them, but they appear in many pure objects. | ||
| 5290 | Mark them as `pinned' so we know to mark them at every GC cycle. */ | ||
| 5291 | XSYMBOL (obj)->pinned = true; | ||
| 5292 | symbol_block_pinned = symbol_block; | ||
| 5293 | } | ||
| 5294 | return obj; | ||
| 5295 | } | ||
| 5268 | else | 5296 | else |
| 5269 | /* Not purified, don't hash-cons. */ | 5297 | { |
| 5270 | return obj; | 5298 | Lisp_Object args[2]; |
| 5299 | args[0] = build_pure_c_string ("Don't know how to purify: %S"); | ||
| 5300 | args[1] = obj; | ||
| 5301 | Fsignal (Qerror, (Fcons (Fformat (2, args), Qnil))); | ||
| 5302 | } | ||
| 5271 | 5303 | ||
| 5272 | if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing. */ | 5304 | if (HASH_TABLE_P (Vpurify_flag)) /* Hash consing. */ |
| 5273 | Fputhash (obj, obj, Vpurify_flag); | 5305 | Fputhash (obj, obj, Vpurify_flag); |
| @@ -5430,6 +5462,24 @@ compact_undo_list (Lisp_Object list) | |||
| 5430 | return list; | 5462 | return list; |
| 5431 | } | 5463 | } |
| 5432 | 5464 | ||
| 5465 | static void | ||
| 5466 | mark_pinned_symbols (void) | ||
| 5467 | { | ||
| 5468 | struct symbol_block *sblk; | ||
| 5469 | int lim = (symbol_block_pinned == symbol_block | ||
| 5470 | ? symbol_block_index : SYMBOL_BLOCK_SIZE); | ||
| 5471 | |||
| 5472 | for (sblk = symbol_block_pinned; sblk; sblk = sblk->next) | ||
| 5473 | { | ||
| 5474 | union aligned_Lisp_Symbol *sym = sblk->symbols, *end = sym + lim; | ||
| 5475 | for (; sym < end; ++sym) | ||
| 5476 | if (sym->s.pinned) | ||
| 5477 | mark_object (make_lisp_ptr (&sym->s, Lisp_Symbol)); | ||
| 5478 | |||
| 5479 | lim = SYMBOL_BLOCK_SIZE; | ||
| 5480 | } | ||
| 5481 | } | ||
| 5482 | |||
| 5433 | DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "", | 5483 | DEFUN ("garbage-collect", Fgarbage_collect, Sgarbage_collect, 0, 0, "", |
| 5434 | doc: /* Reclaim storage for Lisp objects no longer needed. | 5484 | doc: /* Reclaim storage for Lisp objects no longer needed. |
| 5435 | Garbage collection happens automatically if you cons more than | 5485 | Garbage collection happens automatically if you cons more than |
| @@ -5532,6 +5582,7 @@ See Info node `(elisp)Garbage Collection'. */) | |||
| 5532 | for (i = 0; i < staticidx; i++) | 5582 | for (i = 0; i < staticidx; i++) |
| 5533 | mark_object (*staticvec[i]); | 5583 | mark_object (*staticvec[i]); |
| 5534 | 5584 | ||
| 5585 | mark_pinned_symbols (); | ||
| 5535 | mark_specpdl (); | 5586 | mark_specpdl (); |
| 5536 | mark_terminals (); | 5587 | mark_terminals (); |
| 5537 | mark_kboards (); | 5588 | mark_kboards (); |
| @@ -6536,12 +6587,7 @@ gc_sweep (void) | |||
| 6536 | 6587 | ||
| 6537 | for (; sym < end; ++sym) | 6588 | for (; sym < end; ++sym) |
| 6538 | { | 6589 | { |
| 6539 | /* Check if the symbol was created during loadup. In such a case | 6590 | if (!sym->s.gcmarkbit) |
| 6540 | it might be pointed to by pure bytecode which we don't trace, | ||
| 6541 | so we conservatively assume that it is live. */ | ||
| 6542 | bool pure_p = PURE_POINTER_P (XSTRING (sym->s.name)); | ||
| 6543 | |||
| 6544 | if (!sym->s.gcmarkbit && !pure_p) | ||
| 6545 | { | 6591 | { |
| 6546 | if (sym->s.redirect == SYMBOL_LOCALIZED) | 6592 | if (sym->s.redirect == SYMBOL_LOCALIZED) |
| 6547 | xfree (SYMBOL_BLV (&sym->s)); | 6593 | xfree (SYMBOL_BLV (&sym->s)); |
| @@ -6555,8 +6601,7 @@ gc_sweep (void) | |||
| 6555 | else | 6601 | else |
| 6556 | { | 6602 | { |
| 6557 | ++num_used; | 6603 | ++num_used; |
| 6558 | if (!pure_p) | 6604 | eassert (!STRING_MARKED_P (XSTRING (sym->s.name))); |
| 6559 | eassert (!STRING_MARKED_P (XSTRING (sym->s.name))); | ||
| 6560 | sym->s.gcmarkbit = 0; | 6605 | sym->s.gcmarkbit = 0; |
| 6561 | } | 6606 | } |
| 6562 | } | 6607 | } |
diff --git a/src/lisp.h b/src/lisp.h index 30f52b9070c..ea294f8d1da 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -1568,6 +1568,9 @@ struct Lisp_Symbol | |||
| 1568 | special (with `defvar' etc), and shouldn't be lexically bound. */ | 1568 | special (with `defvar' etc), and shouldn't be lexically bound. */ |
| 1569 | bool_bf declared_special : 1; | 1569 | bool_bf declared_special : 1; |
| 1570 | 1570 | ||
| 1571 | /* True if pointed to from purespace and hence can't be GC'd. */ | ||
| 1572 | bool_bf pinned : 1; | ||
| 1573 | |||
| 1571 | /* The symbol's name, as a Lisp string. */ | 1574 | /* The symbol's name, as a Lisp string. */ |
| 1572 | Lisp_Object name; | 1575 | Lisp_Object name; |
| 1573 | 1576 | ||