+
+/* Checks the `cycle check' variable CHECK to see if it indicates that
+ EL is part of a cycle; CHECK must be either Qnil or a value returned
+ by an earlier use of CYCLE_CHECK. SUSPICIOUS is the number of
+ elements after which a cycle might be suspected; after that many
+ elements, this macro begins consing in order to keep more precise
+ track of elements.
+
+ Returns nil if a cycle was detected, otherwise a new value for CHECK
+ that includes EL.
+
+ CHECK is evaluated multiple times, EL and SUSPICIOUS 0 or 1 times, so
+ the caller should make sure that's ok. */
+
+#define CYCLE_CHECK(check, el, suspicious) \
+ (NILP (check) \
+ ? make_number (0) \
+ : (INTEGERP (check) \
+ ? (XFASTINT (check) < (suspicious) \
+ ? make_number (XFASTINT (check) + 1) \
+ : Fcons (el, Qnil)) \
+ : (!NILP (Fmemq ((el), (check))) \
+ ? Qnil \
+ : Fcons ((el), (check)))))
+
+
+/* SAFE_ALLOCA normally allocates memory on the stack, but if size is
+ larger than MAX_ALLOCA, use xmalloc to avoid overflowing the stack. */
+
+#define MAX_ALLOCA 16*1024
+
+extern Lisp_Object safe_alloca_unwind (Lisp_Object);
+
+#define USE_SAFE_ALLOCA \
+ int sa_count = SPECPDL_INDEX (), sa_must_free = 0
+
+/* SAFE_ALLOCA allocates a simple buffer. */
+
+#define SAFE_ALLOCA(buf, type, size) \
+ do { \
+ if ((size) < MAX_ALLOCA) \
+ buf = (type) alloca (size); \
+ else \
+ { \
+ buf = (type) xmalloc (size); \
+ sa_must_free++; \
+ record_unwind_protect (safe_alloca_unwind, \
+ make_save_value (buf, 0)); \
+ } \
+ } while (0)
+
+/* SAFE_FREE frees xmalloced memory and enables GC as needed. */
+
+#define SAFE_FREE() \
+ do { \
+ if (sa_must_free) { \
+ sa_must_free = 0; \
+ unbind_to (sa_count, Qnil); \
+ } \
+ } while (0)
+
+
+/* SAFE_ALLOCA_LISP allocates an array of Lisp_Objects. */
+
+#define SAFE_ALLOCA_LISP(buf, nelt) \
+ do { \
+ int size_ = (nelt) * sizeof (Lisp_Object); \
+ if (size_ < MAX_ALLOCA) \
+ buf = (Lisp_Object *) alloca (size_); \
+ else \
+ { \
+ Lisp_Object arg_; \
+ buf = (Lisp_Object *) xmalloc (size_); \
+ arg_ = make_save_value (buf, nelt); \
+ XSAVE_VALUE (arg_)->dogc = 1; \
+ sa_must_free++; \
+ record_unwind_protect (safe_alloca_unwind, arg_); \
+ } \
+ } while (0)
+
+