]> git.eshelyaron.com Git - emacs.git/commitdiff
Avoid some false matches in mark_maybe_pointer
authorPaul Eggert <eggert@cs.ucla.edu>
Mon, 31 Aug 2020 06:40:11 +0000 (23:40 -0700)
committerPaul Eggert <eggert@cs.ucla.edu>
Mon, 31 Aug 2020 07:05:56 +0000 (00:05 -0700)
This lets Emacs avoid marking some garbage as if it were in use.
On one test platform (RHEL 7.8, Intel Xeon Silver 4116) it
sped up ‘cd lisp; make compile-always’ by a bit over 1%.
* src/alloc.c (live_string_holding, live_cons_holding)
(live_symbol_holding, live_large_vector_holding)
(live_small_vector_holding):
Count only pointers that point to a struct component,
or are a tagged pointer to the start of the struct.
Exception: for non-bool-vector pseudovectors,
count any pointer past the header, since it’s too much
of a pain to write code for every pseudovector.
(live_vector_pointer): New function.

src/alloc.c

index e057107f98c3b37436d284f6611743841f48fb2a..5453c54d9314d25071b217233fa5d8ec8353fa50 100644 (file)
@@ -4457,9 +4457,17 @@ live_string_holding (struct mem_node *m, void *p)
      must not be on the free-list.  */
   if (0 <= offset && offset < sizeof b->strings)
     {
-      struct Lisp_String *s = p = cp -= offset % sizeof b->strings[0];
-      if (s->u.s.data)
-       return s;
+      ptrdiff_t off = offset % sizeof b->strings[0];
+      if (off == Lisp_String
+         || off == 0
+         || off == offsetof (struct Lisp_String, u.s.size_byte)
+         || off == offsetof (struct Lisp_String, u.s.intervals)
+         || off == offsetof (struct Lisp_String, u.s.data))
+       {
+         struct Lisp_String *s = p = cp -= off;
+         if (s->u.s.data)
+           return s;
+       }
     }
   return NULL;
 }
@@ -4489,9 +4497,15 @@ live_cons_holding (struct mem_node *m, void *p)
       && (b != cons_block
          || offset / sizeof b->conses[0] < cons_block_index))
     {
-      struct Lisp_Cons *s = p = cp -= offset % sizeof b->conses[0];
-      if (!deadp (s->u.s.car))
-       return s;
+      ptrdiff_t off = offset % sizeof b->conses[0];
+      if (off == Lisp_Cons
+         || off == 0
+         || off == offsetof (struct Lisp_Cons, u.s.u.cdr))
+       {
+         struct Lisp_Cons *s = p = cp -= off;
+         if (!deadp (s->u.s.car))
+           return s;
+       }
     }
   return NULL;
 }
@@ -4522,9 +4536,23 @@ live_symbol_holding (struct mem_node *m, void *p)
       && (b != symbol_block
          || offset / sizeof b->symbols[0] < symbol_block_index))
     {
-      struct Lisp_Symbol *s = p = cp -= offset % sizeof b->symbols[0];
-      if (!deadp (s->u.s.function))
-       return s;
+      ptrdiff_t off = offset % sizeof b->symbols[0];
+      if (off == Lisp_Symbol
+
+         /* Use u's offset since '|| off == 0' would run afoul of gcc
+            -Wlogical-op, as Lisp_Symbol happens to be zero.  */
+         || off == offsetof (struct Lisp_Symbol, u)
+
+         || off == offsetof (struct Lisp_Symbol, u.s.name)
+         || off == offsetof (struct Lisp_Symbol, u.s.val)
+         || off == offsetof (struct Lisp_Symbol, u.s.function)
+         || off == offsetof (struct Lisp_Symbol, u.s.plist)
+         || off == offsetof (struct Lisp_Symbol, u.s.next))
+       {
+         struct Lisp_Symbol *s = p = cp -= off;
+         if (!deadp (s->u.s.function))
+           return s;
+       }
     }
   return NULL;
 }
@@ -4571,6 +4599,37 @@ live_float_p (struct mem_node *m, void *p)
   return live_float_holding (m, p) == p;
 }
 
+/* Return VECTOR if P points within it, NULL otherwise.  */
+
+static struct Lisp_Vector *
+live_vector_pointer (struct Lisp_Vector *vector, void *p)
+{
+  void *vvector = vector;
+  char *cvector = vvector;
+  char *cp = p;
+  ptrdiff_t offset = cp - cvector;
+  return ((offset == Lisp_Vectorlike
+          || offset == 0
+          || (sizeof vector->header <= offset
+              && offset < vector_nbytes (vector)
+              && (! (vector->header.size & PSEUDOVECTOR_FLAG)
+                  ? (offsetof (struct Lisp_Vector, contents) <= offset
+                     && (((offset - offsetof (struct Lisp_Vector, contents))
+                          % word_size)
+                         == 0))
+                  /* For non-bool-vector pseudovectors, treat any pointer
+                     past the header as valid since it's too much of a pain
+                     to write special-case code for every pseudovector.  */
+                  : (! PSEUDOVECTOR_TYPEP (&vector->header, PVEC_BOOL_VECTOR)
+                     || offset == offsetof (struct Lisp_Bool_Vector, size)
+                     || (offsetof (struct Lisp_Bool_Vector, data) <= offset
+                         && (((offset
+                               - offsetof (struct Lisp_Bool_Vector, data))
+                              % sizeof (bits_word))
+                             == 0))))))
+         ? vector : NULL);
+}
+
 /* If P is a pointer to a live, large vector-like object, return the object.
    Otherwise, return nil.
    M is a pointer to the mem_block for P.  */
@@ -4579,10 +4638,7 @@ static struct Lisp_Vector *
 live_large_vector_holding (struct mem_node *m, void *p)
 {
   eassert (m->type == MEM_TYPE_VECTORLIKE);
-  struct Lisp_Vector *vp = p;
-  struct Lisp_Vector *vector = large_vector_vec (m->start);
-  struct Lisp_Vector *next = ADVANCE (vector, vector_nbytes (vector));
-  return vector <= vp && vp < next ? vector : NULL;
+  return live_vector_pointer (large_vector_vec (m->start), p);
 }
 
 static bool
@@ -4612,7 +4668,7 @@ live_small_vector_holding (struct mem_node *m, void *p)
     {
       struct Lisp_Vector *next = ADVANCE (vector, vector_nbytes (vector));
       if (vp < next && !PSEUDOVECTOR_TYPEP (&vector->header, PVEC_FREE))
-       return vector;
+       return live_vector_pointer (vector, vp);
       vector = next;
     }
   return NULL;