]> git.eshelyaron.com Git - emacs.git/commitdiff
Turn specpdl_ref into a type of its own
authorMattias Engdegård <mattiase@acm.org>
Wed, 2 Feb 2022 15:51:43 +0000 (16:51 +0100)
committerMattias Engdegård <mattiase@acm.org>
Sat, 12 Feb 2022 17:18:58 +0000 (18:18 +0100)
Wrap the specpdl_ref contents in a struct, which gives us some very
useful type checking to make sure that all code that assumed integral
specpdl refs has been converted.

We only do this on 64-bit platforms, since those tend to have modern
ABIs where small structs are optimised as scalars.  In other words,
this change should not affect the compiled code.

* src/lisp.h (specpdl_ref): Now a struct on 64-bit platforms.
(wrap_specpdl_ref, unwrap_specpdl_ref): New.
(specpdl_count_to_ref, specpdl_ref_to_count)
(specpdl_ref_eq, specpdl_ref_lt)
(specpdl_ref_valid_p, make_invalid_specpdl_ref): Use new wrappers.

src/lisp.h

index 3ff9dccc4ecc5834ce7899004cc8a65b65c4de1e..9b82307f67593b790147fe86fd8c6a8d82c8d97d 100644 (file)
@@ -3350,45 +3350,79 @@ union specbinding
     } bt;
   };
 
+/* We use 64-bit platforms as a proxy for ones with ABIs that treat
+   small structs efficiently.  */
+#if SIZE_MAX > 0xffffffff
+#define WRAP_SPECPDL_REF 1
+#endif
+
 /* Abstract reference to to a specpdl entry.  */
+#ifdef WRAP_SPECPDL_REF
+/* Use a proper type for specpdl_ref if it does not make the code slower,
+   since the type checking is quite useful.  */
+typedef struct { ptrdiff_t n; } specpdl_ref;
+#else
 typedef ptrdiff_t specpdl_ref;
+#endif
 
+/* Internal use only.  */
 INLINE specpdl_ref
-specpdl_count_to_ref (ptrdiff_t count)
+wrap_specpdl_ref (ptrdiff_t count)
 {
+#ifdef WRAP_SPECPDL_REF
+  return (specpdl_ref) {.n = count};
+#else
   return count;
+#endif
 }
 
+/* Internal use only.  */
 INLINE ptrdiff_t
-specpdl_ref_to_count (specpdl_ref ref)
+unwrap_specpdl_ref (specpdl_ref ref)
 {
+#ifdef WRAP_SPECPDL_REF
+  return ref.n;
+#else
   return ref;
+#endif
+}
+
+INLINE specpdl_ref
+specpdl_count_to_ref (ptrdiff_t count)
+{
+  return wrap_specpdl_ref (count);
+}
+
+INLINE ptrdiff_t
+specpdl_ref_to_count (specpdl_ref ref)
+{
+  return unwrap_specpdl_ref (ref);
 }
 
 /* Whether two `specpdl_ref' refer to the same entry.  */
 INLINE bool
 specpdl_ref_eq (specpdl_ref a, specpdl_ref b)
 {
-  return a == b;
+  return unwrap_specpdl_ref (a) == unwrap_specpdl_ref (b);
 }
 
 /* Whether `a' refers to an earlier entry than `b'.  */
 INLINE bool
 specpdl_ref_lt (specpdl_ref a, specpdl_ref b)
 {
-  return a < b;
+  return unwrap_specpdl_ref (a) < unwrap_specpdl_ref (b);
 }
 
 INLINE bool
 specpdl_ref_valid_p (specpdl_ref ref)
 {
-  return specpdl_ref_to_count (ref) >= 0;
+  return unwrap_specpdl_ref (ref) >= 0;
 }
 
 INLINE specpdl_ref
 make_invalid_specpdl_ref (void)
 {
-  return specpdl_count_to_ref (-1);
+  return wrap_specpdl_ref (-1);
 }
 
 /* Return a reference that is `delta' steps more recent than `ref'.