+2014-09-15 Dmitry Antipov <dmantipov@yandex.ru>
+
+ If USE_LOCAL_ALLOCATORS, allocate some Lisp objects on stack.
+ * lisp.h (local_cons, local_list1, local_list2, local_list3)
+ [USE_LOCAL_ALLOCATORS]: New macros.
+ [!USE_LOCAL_ALLOCATORS]: Fall back to regular functions.
+ (build_local_string): Avoid argument name expansion clash with
+ make_local_string.
+ * alloc.c (toplevel)
+ [USE_LOCAL_ALLOCATORS && GC_MARK_STACK != GC_MAKE_GCPROS_NOOPS]:
+ Preprocessor guard to avoid impossible configuration.
+ * charset.c (Ffind_charset_region, Ffind_charset_string):
+ Use make_local_vector.
+ * lread.c (read1, substitute_object_recurse): Use scoped_cons.
+ * textprop.c (Fput_text_property, Fadd_face_text_property):
+ Use scoped_list2.
+ (copy_text_properties): Use local_cons and local_list3.
+ * chartab.c (uniprop_table):
+ * data.c (wrong_choice, wrong_range):
+ * doc.c (get_doc_string):
+ * editfns.c (format2):
+ * fileio.c (Fexpand_file_name, auto_save_error):
+ * fns.c (Fyes_or_no_p):
+ * font.c (font_parse_xlfd, font_parse_family_registry, font_add_log):
+ * fontset.c (Fset_fontset_font):
+ * keyboard.c (echo_add_key, echo_dash, parse_menu_item)
+ (read_char_minibuf_menu_prompt):
+ * keymap.c (silly_event_symbol_error, describe_vector):
+ * menu.c (single_menu_item):
+ * minibuf.c (Fread_buffer):
+ * process.c (status_message, Fformat_network_address)
+ (server_accept_connection): Use make_local_string and
+ build_local_string. Prefer compound literals where appropriate.
+
2014-09-15 Daniel Colascione <dancol@dancol.org>
* fns.c (Fsort): Tweak sort docstring.
static bool valgrind_p;
#endif
+#ifdef USE_LOCAL_ALLOCATORS
+# if GC_MARK_STACK != GC_MAKE_GCPROS_NOOPS
+# error "Stack-allocated Lisp objects are not compatible with GCPROs"
+# endif
+#endif
+
/* GC_CHECK_MARKED_OBJECTS means do sanity checks on allocated objects.
Doable only if GC_MARK_STACK. */
#if ! GC_MARK_STACK
from_byte = CHAR_TO_BYTE (from);
- charsets = Fmake_vector (make_number (charset_table_used), Qnil);
+ charsets = make_local_vector (charset_table_used, Qnil);
while (1)
{
find_charsets_in_text (BYTE_POS_ADDR (from_byte), stop - from,
CHECK_STRING (str);
- charsets = Fmake_vector (make_number (charset_table_used), Qnil);
+ charsets = make_local_vector (charset_table_used, Qnil);
find_charsets_in_text (SDATA (str), SCHARS (str), SBYTES (str),
charsets, table,
STRING_MULTIBYTE (str));
{
struct gcpro gcpro1;
GCPRO1 (val);
- result = Fload (concat2 (build_string ("international/"), table),
+ result = Fload (concat2 (build_local_string ("international/"), table),
Qt, Qt, Qt, Qt);
UNGCPRO;
if (NILP (result))
for (obj = choice; !NILP (obj); obj = XCDR (obj))
{
args[i++] = SYMBOL_NAME (XCAR (obj));
- args[i++] = build_string (NILP (XCDR (obj)) ? " should be specified"
- : (NILP (XCDR (XCDR (obj))) ? " or " : ", "));
+ args[i++] = build_local_string
+ (NILP (XCDR (obj)) ? " should be specified"
+ : (NILP (XCDR (XCDR (obj))) ? " or " : ", "));
}
obj = Fconcat (i, args);
static void
wrong_range (Lisp_Object min, Lisp_Object max, Lisp_Object wrong)
{
- Lisp_Object args[4];
-
- args[0] = build_string ("Value should be from ");
- args[1] = Fnumber_to_string (min);
- args[2] = build_string (" to ");
- args[3] = Fnumber_to_string (max);
-
- xsignal2 (Qerror, Fconcat (4, args), wrong);
+ xsignal2 (Qerror, Fconcat (4, ((Lisp_Object [])
+ { build_local_string ("Value should be from "),
+ Fnumber_to_string (min),
+ build_local_string (" to "),
+ Fnumber_to_string (max) })), wrong);
}
/* Store NEWVAL into SYMBOL, where VALCONTENTS is found in the value cell
if (fd < 0)
{
SAFE_FREE ();
- return concat3 (build_string ("Cannot open doc string file \""),
- file, build_string ("\"\n"));
+ return concat3 (build_local_string ("Cannot open doc string file \""),
+ file, build_local_string ("\"\n"));
}
}
count = SPECPDL_INDEX ();
Lisp_Object
format2 (const char *string1, Lisp_Object arg0, Lisp_Object arg1)
{
- Lisp_Object args[3];
- args[0] = build_string (string1);
- args[1] = arg0;
- args[2] = arg1;
- return Fformat (3, args);
+ return Fformat (3, ((Lisp_Object [])
+ { build_local_string (string1), arg0, arg1 }));
}
\f
DEFUN ("char-equal", Fchar_equal, Schar_equal, 2, 2, 0,
char newdir_utf8[MAX_UTF8_PATH];
filename_from_ansi (newdir, newdir_utf8);
- tem = build_string (newdir_utf8);
+ tem = build_local_string (newdir_utf8);
}
else
#endif
- tem = build_string (newdir);
+ tem = build_local_string (newdir);
newdirlim = newdir + SBYTES (tem);
if (multibyte && !STRING_MULTIBYTE (tem))
{
/* `getpwnam' may return a unibyte string, which will
bite us since we expect the directory to be
multibyte. */
- tem = build_string (newdir);
+ tem = build_local_string (newdir);
newdirlim = newdir + SBYTES (tem);
if (multibyte && !STRING_MULTIBYTE (tem))
{
adir = NULL;
else if (multibyte)
{
- Lisp_Object tem = build_string (adir);
+ Lisp_Object tem = build_local_string (adir);
tem = DECODE_FILE (tem);
newdirlim = adir + SBYTES (tem);
getcwd (adir, adir_size);
if (multibyte)
{
- Lisp_Object tem = build_string (adir);
+ Lisp_Object tem = build_local_string (adir);
tem = DECODE_FILE (tem);
newdirlim = adir + SBYTES (tem);
static Lisp_Object
auto_save_error (Lisp_Object error_val)
{
- Lisp_Object args[3], msg;
+ Lisp_Object msg;
int i;
struct gcpro gcpro1;
ring_bell (XFRAME (selected_frame));
- args[0] = build_string ("Auto-saving %s: %s");
- args[1] = BVAR (current_buffer, name);
- args[2] = Ferror_message_string (error_val);
- msg = Fformat (3, args);
+ msg = Fformat (3, ((Lisp_Object [])
+ { build_local_string ("Auto-saving %s: %s"),
+ BVAR (current_buffer, name),
+ Ferror_message_string (error_val) }));
GCPRO1 (msg);
for (i = 0; i < 3; ++i)
(Lisp_Object prompt)
{
register Lisp_Object ans;
- Lisp_Object args[2];
struct gcpro gcpro1;
CHECK_STRING (prompt);
return obj;
}
- args[0] = prompt;
- args[1] = build_string ("(yes or no) ");
- prompt = Fconcat (2, args);
-
+ prompt = Fconcat (2, ((Lisp_Object [])
+ { prompt, build_local_string ("(yes or no) ") }));
GCPRO1 (prompt);
while (1)
{
val = prop[XLFD_ENCODING_INDEX];
if (! NILP (val))
- val = concat2 (build_string ("*-"), SYMBOL_NAME (val));
+ val = concat2 (build_local_string ("*-"), SYMBOL_NAME (val));
}
else if (NILP (prop[XLFD_ENCODING_INDEX]))
- val = concat2 (SYMBOL_NAME (val), build_string ("-*"));
+ val = concat2 (SYMBOL_NAME (val), build_local_string ("-*"));
else
- val = concat3 (SYMBOL_NAME (val), build_string ("-"),
+ val = concat3 (SYMBOL_NAME (val), build_local_string ("-"),
SYMBOL_NAME (prop[XLFD_ENCODING_INDEX]));
if (! NILP (val))
ASET (font, FONT_REGISTRY_INDEX, Fintern (val, Qnil));
if (! p1)
{
if (SDATA (registry)[len - 1] == '*')
- registry = concat2 (registry, build_string ("-*"));
+ registry = concat2 (registry, build_local_string ("-*"));
else
- registry = concat2 (registry, build_string ("*-*"));
+ registry = concat2 (registry, build_local_string ("*-*"));
}
registry = Fdowncase (registry);
ASET (font_spec, FONT_REGISTRY_INDEX, Fintern (registry, Qnil));
if (FONTP (arg))
{
Lisp_Object tail, elt;
- Lisp_Object equalstr = build_string ("=");
+ Lisp_Object equalstr = build_local_string ("=");
val = Ffont_xlfd_name (arg, Qt);
for (tail = AREF (arg, FONT_EXTRA_INDEX); CONSP (tail);
val = Ffont_xlfd_name (result, Qt);
if (! FONT_SPEC_P (result))
val = concat3 (SYMBOL_NAME (AREF (result, FONT_TYPE_INDEX)),
- build_string (":"), val);
+ build_local_string (":"), val);
result = val;
}
else if (CONSP (result))
registry = AREF (font_spec, FONT_REGISTRY_INDEX);
if (! NILP (registry))
registry = Fdowncase (SYMBOL_NAME (registry));
- encoding = find_font_encoding (concat3 (family, build_string ("-"),
+ encoding = find_font_encoding (concat3 (family, build_local_string ("-"),
registry));
if (NILP (encoding))
encoding = Qascii;
if (XINT (last_char) == '-' && XINT (prev_char) != ' ')
Faset (echo_string, idx, make_number (' '));
else
- echo_string = concat2 (echo_string, build_string (" "));
+ echo_string = concat2 (echo_string, build_local_string (" "));
}
else if (STRINGP (echo_string) && SCHARS (echo_string) > 0)
- echo_string = concat2 (echo_string, build_string (" "));
+ echo_string = concat2 (echo_string, build_local_string (" "));
kset_echo_string
(current_kboard,
- concat2 (echo_string, make_string (buffer, ptr - buffer)));
+ concat2 (echo_string, make_local_string (buffer, ptr - buffer)));
SAFE_FREE ();
}
but make it go away when the next character is added. */
kset_echo_string
(current_kboard,
- concat2 (KVAR (current_kboard, echo_string), build_string ("-")));
+ concat2 (KVAR (current_kboard, echo_string), build_local_string ("-")));
echo_now ();
}
/* The previous code preferred :key-sequence to :keys, so we
preserve this behavior. */
if (STRINGP (keyeq) && !CONSP (keyhint))
- keyeq = concat2 (build_string (" "), Fsubstitute_command_keys (keyeq));
+ keyeq = concat2 (build_local_string (" "),
+ Fsubstitute_command_keys (keyeq));
else
{
Lisp_Object prefix = keyeq;
if (STRINGP (XCDR (prefix)))
tem = concat2 (tem, XCDR (prefix));
}
- keyeq = concat2 (build_string (" "), tem);
- /* keyeq = concat3(build_string(" ("),tem,build_string(")")); */
+ keyeq = concat2 (build_local_string (" "), tem);
}
else
keyeq = Qnil;
Lisp_Object selected
= AREF (item_properties, ITEM_PROPERTY_SELECTED);
if (EQ (tem, QCradio))
- tem = build_string (NILP (selected) ? "(*) " : "( ) ");
+ tem = build_local_string (NILP (selected) ? "(*) " : "( ) ");
else
- tem = build_string (NILP (selected) ? "[X] " : "[ ] ");
+ tem = build_local_string (NILP (selected) ? "[X] " : "[ ] ");
s = concat2 (tem, s);
}
*p = 0;
c = reorder_modifiers (c);
- keystring = concat2 (build_string (new_mods), XCDR (assoc));
+ keystring = concat2 (build_local_string (new_mods), XCDR (assoc));
error ("To bind the key %s, use [?%s], not [%s]",
SDATA (SYMBOL_NAME (c)), SDATA (keystring),
if (CONSP (key) && INTEGERP (XCAR (key)) && INTEGERP (XCDR (key)))
/* An interval from a map-char-table. */
return concat3 (Fsingle_key_description (XCAR (key), no_angles),
- build_string (".."),
+ build_local_string (".."),
Fsingle_key_description (XCDR (key), no_angles));
key = EVENT_HEAD (key);
{
Lisp_Object tem;
tem = Fkey_description (prefix, Qnil);
- elt_prefix = concat2 (tem, build_string (" "));
+ elt_prefix = concat2 (tem, build_local_string (" "));
}
prefix = Qnil;
}
# define USE_LOCAL_ALLOCATORS
+/* Return a function-scoped cons whose car is X and cdr is Y. */
+
+# define local_cons(x, y) \
+ ({ \
+ struct Lisp_Cons *c = alloca (sizeof (struct Lisp_Cons)); \
+ c->car = (x); \
+ c->u.cdr = (y); \
+ make_lisp_ptr (c, Lisp_Cons); \
+ })
+
+# define local_list1(x) local_cons (x, Qnil)
+# define local_list2(x, y) local_cons (x, local_list1 (y))
+# define local_list3(x, y, z) local_cons (x, local_list2 (y, z))
+
/* Return a function-scoped vector of length SIZE, with each element
being INIT. */
/* Return a function-scoped string with contents DATA. */
-# define build_local_string(data) \
- ({ char const *data_ = data; make_local_string (data_, strlen (data_)); })
+# define build_local_string(data) \
+ ({ char const *data1_ = (data); \
+ make_local_string (data1_, strlen (data1_)); })
#else
/* Safer but slower implementations. */
+# define local_cons(car, cdr) Fcons (car, cdr)
+# define local_list1(x) list1 (x)
+# define local_list2(x, y) list2 (x, y)
+# define local_list3(x, y, z) list3 (x, y, z)
# define make_local_vector(size, init) Fmake_vector (make_number (size), init)
# define make_local_string(data, nbytes) make_string (data, nbytes)
# define build_local_string(data) build_string (data)
Lisp_Object placeholder;
Lisp_Object cell;
- placeholder = Fcons (Qnil, Qnil);
+ placeholder = scoped_cons (Qnil, Qnil);
cell = Fcons (make_number (n), placeholder);
read_objects = Fcons (cell, read_objects);
substitute_in_interval contains part of the logic. */
INTERVAL root_interval = string_intervals (subtree);
- Lisp_Object arg = Fcons (object, placeholder);
+ Lisp_Object arg = scoped_cons (object, placeholder);
traverse_intervals_noorder (root_interval,
&substitute_in_interval, arg);
in the installed Lisp directory.
We don't use Fexpand_file_name because that would make
the directory absolute now. */
- elt = concat2 (build_string ("../lisp/"),
- Ffile_name_nondirectory (elt));
+ elt = concat2 (build_local_string ("../lisp/"),
+ Ffile_name_nondirectory (elt));
}
else if (EQ (elt, Vload_file_name)
&& ! NILP (elt)
if (!submenu && SREF (tem, 0) != '\0'
&& SREF (tem, 0) != '-')
ASET (menu_items, idx + MENU_ITEMS_ITEM_NAME,
- concat2 (build_string (" "), tem));
+ concat2 (build_local_string (" "), tem));
idx += MENU_ITEMS_ITEM_LENGTH;
}
}
/* Calculate prefix, if any, for this item. */
if (EQ (type, QCtoggle))
- prefix = build_string (NILP (selected) ? "[ ] " : "[X] ");
+ prefix = build_local_string (NILP (selected) ? "[ ] " : "[X] ");
else if (EQ (type, QCradio))
- prefix = build_string (NILP (selected) ? "( ) " : "(*) ");
+ prefix = build_local_string (NILP (selected) ? "( ) " : "(*) ");
}
/* Not a button. If we have earlier buttons, then we need a prefix. */
else if (!skp->notbuttons && SREF (item_string, 0) != '\0'
&& SREF (item_string, 0) != '-')
- prefix = build_string (" ");
+ prefix = build_local_string (" ");
if (!NILP (prefix))
item_string = concat2 (prefix, item_string);
|| FRAME_MSDOS_P (XFRAME (Vmenu_updating_frame)))
&& !NILP (map))
/* Indicate visually that this is a submenu. */
- item_string = concat2 (item_string, build_string (" >"));
+ item_string = concat2 (item_string, build_local_string (" >"));
push_menu_item (item_string, enabled, key,
AREF (item_properties, ITEM_PROPERTY_DEF),
function, instead of the usual behavior. */)
(Lisp_Object prompt, Lisp_Object def, Lisp_Object require_match)
{
- Lisp_Object args[4], result;
+ Lisp_Object result;
char *s;
ptrdiff_t len;
ptrdiff_t count = SPECPDL_INDEX ();
STRING_MULTIBYTE (prompt));
}
- args[0] = build_string ("%s (default %s): ");
- args[1] = prompt;
- args[2] = CONSP (def) ? XCAR (def) : def;
- prompt = Fformat (3, args);
+ prompt = Fformat (3, ((Lisp_Object [])
+ { build_local_string ("%s (default %s): "),
+ prompt, CONSP (def) ? XCAR (def) : def }));
}
result = Fcompleting_read (prompt, intern ("internal-complete-buffer"),
Qbuffer_name_history, def, Qnil);
}
else
- {
- args[0] = Vread_buffer_function;
- args[1] = prompt;
- args[2] = def;
- args[3] = require_match;
- result = Ffuncall (4, args);
- }
+ result = Ffuncall (4, ((Lisp_Object [])
+ { Vread_buffer_function, prompt, def, require_match }));
return unbind_to (count, result);
}
\f
if (c1 != c2)
Faset (string, make_number (0), make_number (c2));
}
- string2 = build_string (coredump ? " (core dumped)\n" : "\n");
+ string2 = build_local_string (coredump ? " (core dumped)\n" : "\n");
return concat2 (string, string2);
}
else if (EQ (symbol, Qexit))
if (code == 0)
return build_string ("finished\n");
string = Fnumber_to_string (make_number (code));
- string2 = build_string (coredump ? " (core dumped)\n" : "\n");
- return concat3 (build_string ("exited abnormally with code "),
+ string2 = build_local_string (coredump ? " (core dumped)\n" : "\n");
+ return concat3 (build_local_string ("exited abnormally with code "),
string, string2);
}
else if (EQ (symbol, Qfailed))
{
string = Fnumber_to_string (make_number (code));
- string2 = build_string ("\n");
+ string2 = build_local_string ("\n");
return concat3 (build_string ("failed with code "),
string, string2);
}
if (size == 4 || (size == 5 && !NILP (omit_port)))
{
- args[0] = build_string ("%d.%d.%d.%d");
+ args[0] = build_local_string ("%d.%d.%d.%d");
nargs = 4;
}
else if (size == 5)
{
- args[0] = build_string ("%d.%d.%d.%d:%d");
+ args[0] = build_local_string ("%d.%d.%d.%d:%d");
nargs = 5;
}
else if (size == 8 || (size == 9 && !NILP (omit_port)))
{
- args[0] = build_string ("%x:%x:%x:%x:%x:%x:%x:%x");
+ args[0] = build_local_string ("%x:%x:%x:%x:%x:%x:%x:%x");
nargs = 8;
}
else if (size == 9)
{
- args[0] = build_string ("[%x:%x:%x:%x:%x:%x:%x:%x]:%d");
+ args[0] = build_local_string ("[%x:%x:%x:%x:%x:%x:%x:%x]:%d");
nargs = 9;
}
else
args[i+1] = p->contents[i];
}
- return Fformat (nargs+1, args);
+ return Fformat (nargs + 1, args);
}
if (CONSP (address))
- {
- Lisp_Object args[2];
- args[0] = build_string ("<Family %d>");
- args[1] = Fcar (address);
- return Fformat (2, args);
- }
+ return Fformat (2, ((Lisp_Object [])
+ { build_local_string ("<Family %d>"), Fcar (address) }));
return Qnil;
}
{
case AF_INET:
{
- Lisp_Object args[5];
unsigned char *ip = (unsigned char *)&saddr.in.sin_addr.s_addr;
- args[0] = build_string ("%d.%d.%d.%d");
- args[1] = make_number (*ip++);
- args[2] = make_number (*ip++);
- args[3] = make_number (*ip++);
- args[4] = make_number (*ip++);
- host = Fformat (5, args);
- service = make_number (ntohs (saddr.in.sin_port));
- args[0] = build_string (" <%s:%d>");
- args[1] = host;
- args[2] = service;
- caller = Fformat (3, args);
+ host = Fformat (5, ((Lisp_Object [])
+ { build_local_string ("%d.%d.%d.%d"), make_number (*ip++),
+ make_number (*ip++), make_number (*ip++), make_number (*ip++) }));
+ service = make_number (ntohs (saddr.in.sin_port));
+ caller = Fformat (3, ((Lisp_Object [])
+ { build_local_string (" <%s:%d>"), host, service }));
}
break;
Lisp_Object args[9];
uint16_t *ip6 = (uint16_t *)&saddr.in6.sin6_addr;
int i;
- args[0] = build_string ("%x:%x:%x:%x:%x:%x:%x:%x");
+
+ args[0] = build_local_string ("%x:%x:%x:%x:%x:%x:%x:%x");
for (i = 0; i < 8; i++)
- args[i+1] = make_number (ntohs (ip6[i]));
+ args[i + 1] = make_number (ntohs (ip6[i]));
host = Fformat (9, args);
service = make_number (ntohs (saddr.in.sin_port));
-
- args[0] = build_string (" <[%s]:%d>");
- args[1] = host;
- args[2] = service;
- caller = Fformat (3, args);
+ caller = Fformat (3, ((Lisp_Object [])
+ { build_local_string (" <[%s]:%d>"), host, service }));
}
break;
#endif
#endif
default:
caller = Fnumber_to_string (make_number (connect_counter));
- caller = concat3 (build_string (" <"), caller, build_string (">"));
+ caller = concat3
+ (build_local_string (" <"), caller, build_local_string (">"));
break;
}
if (!NILP (ps->log))
call3 (ps->log, server, proc,
- concat3 (build_string ("accept from "),
- (STRINGP (host) ? host : build_string ("-")),
- build_string ("\n")));
+ concat3 (build_local_string ("accept from "),
+ (STRINGP (host) ? host : build_local_string ("-")),
+ build_local_string ("\n")));
exec_sentinel (proc,
- concat3 (build_string ("open from "),
- (STRINGP (host) ? host : build_string ("-")),
- build_string ("\n")));
+ concat3 (build_local_string ("open from "),
+ (STRINGP (host) ? host : build_local_string ("-")),
+ build_local_string ("\n")));
}
/* This variable is different from waiting_for_input in keyboard.c.
If the optional fifth argument OBJECT is a buffer (or nil, which means
the current buffer), START and END are buffer positions (integers or
markers). If OBJECT is a string, START and END are 0-based indices into it. */)
- (Lisp_Object start, Lisp_Object end, Lisp_Object property, Lisp_Object value, Lisp_Object object)
+ (Lisp_Object start, Lisp_Object end, Lisp_Object property,
+ Lisp_Object value, Lisp_Object object)
{
- Fadd_text_properties (start, end, list2 (property, value), object);
+ Fadd_text_properties (start, end, scoped_list2 (property, value), object);
return Qnil;
}
(Lisp_Object start, Lisp_Object end, Lisp_Object face,
Lisp_Object append, Lisp_Object object)
{
- add_text_properties_1 (start, end, list2 (Qface, face), object,
+ add_text_properties_1 (start, end, scoped_list2 (Qface, face), object,
(NILP (append)
? TEXT_PROPERTY_PREPEND
: TEXT_PROPERTY_APPEND));
/* Note this can GC when DEST is a buffer. */
Lisp_Object
-copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src, Lisp_Object pos, Lisp_Object dest, Lisp_Object prop)
+copy_text_properties (Lisp_Object start, Lisp_Object end, Lisp_Object src,
+ Lisp_Object pos, Lisp_Object dest, Lisp_Object prop)
{
INTERVAL i;
Lisp_Object res;
plist = Fcdr (Fcdr (plist));
}
if (! NILP (plist))
- {
- /* Must defer modifications to the interval tree in case src
- and dest refer to the same string or buffer. */
- stuff = Fcons (list3 (make_number (p), make_number (p + len), plist),
- stuff);
- }
+ /* Must defer modifications to the interval tree in case
+ src and dest refer to the same string or buffer. */
+ stuff = local_cons
+ (local_list3 (make_number (p), make_number (p + len), plist),
+ stuff);
i = next_interval (i);
if (!i)