merge_state *ms = arg;
eassume (ms != NULL);
+ if (ms->allocated_keys != NULL)
+ mark_objects (ms->allocated_keys, ms->listlen);
+
if (ms->reloc.size != NULL && *ms->reloc.size > 0)
{
Lisp_Object *src = (ms->reloc.src->values
if (length < MERGESTATE_TEMP_SIZE / 2)
keys = &ms.temparray[length + 1];
else
- keys = allocated_keys = xmalloc (length * word_size);
-
- for (ptrdiff_t i = 0; i < length; i++)
- keys[i] = call1 (keyfunc, seq[i]);
+ {
+ /* Fill with valid Lisp values in case a GC occurs before all
+ keys have been computed. */
+ verify (NIL_IS_ZERO);
+ keys = allocated_keys = xzalloc (length * word_size);
+ }
lo.keys = keys;
lo.values = seq;
}
+ merge_init (&ms, length, allocated_keys, &lo, predicate);
+
+ /* Compute keys after merge_markmem has been registered by merge_init
+ (any call to keyfunc might trigger a GC). */
+ if (!NILP (keyfunc))
+ for (ptrdiff_t i = 0; i < length; i++)
+ keys[i] = call1 (keyfunc, seq[i]);
+
/* FIXME: This is where we would check the keys for interesting
properties for more optimised comparison (such as all being fixnums
etc). */
- merge_init (&ms, length, allocated_keys, &lo, predicate);
-
/* March over the array once, left to right, finding natural runs,
and extending short natural runs to minrun elements. */
const ptrdiff_t minrun = merge_compute_minrun (length);
(should-not (and (> size 0) (eq res seq)))
(should (equal seq input))))))))))))
+(ert-deftest fns-tests-sort-gc ()
+ ;; Make sure our temporary storage is traversed by the GC.
+ (let* ((n 1000)
+ (a (mapcar #'number-to-string (number-sequence 1 n)))
+ (i 0)
+ ;; Force frequent GCs in both the :key and :lessp functions.
+ (s (sort a
+ :key (lambda (x)
+ (setq i (1+ i))
+ (when (> i 300)
+ (garbage-collect)
+ (setq i 0))
+ (copy-sequence x))
+ :lessp (lambda (a b)
+ (setq i (1+ i))
+ (when (> i 300)
+ (garbage-collect)
+ (setq i 0))
+ (string< a b)))))
+ (should (equal (length s) (length a)))))
+
(defvar w32-collate-ignore-punctuation)
(ert-deftest fns-tests-collate-sort ()