diff options
| author | Robin Haberkorn <rhaberkorn@fmsbw.de> | 2026-08-23 21:51:48 +0200 |
|---|---|---|
| committer | Robin Haberkorn <rhaberkorn@fmsbw.de> | 2026-08-23 21:51:48 +0200 |
| commit | 3f3db5422397f1bf8d5af1ade256638d89b1081c (patch) | |
| tree | edc57f9b1048cfbfebd0ff1a3cffcb7c72c764c1 | |
| parent | 6aa97a68a85b83267de597bfb30b70c04b7de97b (diff) | |
functions that can tail-call must be tail-called as welltail-calls
Otherwise we could "leak" stack frames, which causes crashes on platforms with small stack sizes.
This still did not result in a reproducable speedup with GCC 16.
fixup 2e097cec409182c3cb39b74489387480bf8a278f
| -rw-r--r-- | src/core-commands.c | 30 | ||||
| -rw-r--r-- | src/parser.h | 10 | ||||
| -rw-r--r-- | src/stdio-commands.c | 4 |
3 files changed, 24 insertions, 20 deletions
diff --git a/src/core-commands.c b/src/core-commands.c index d01cbb9..d850c14 100644 --- a/src/core-commands.c +++ b/src/core-commands.c @@ -914,10 +914,8 @@ teco_state_start_input(teco_machine_main_t *ctx, gunichar chr, GError **error) /* * <CTRL/x> commands implemented in teco_state_control */ - if (TECO_IS_CTL(chr)) { - teco_state_t *next = teco_state_control_input(ctx, TECO_CTL_ECHO(chr), error); - TECO_RETURN(ctx, next, error); - } + if (TECO_IS_CTL(chr)) + TECO_TAIL return teco_state_control_input(ctx, TECO_CTL_ECHO(chr), error); } teco_state_t *next = teco_machine_main_transition_input(ctx, transitions, G_N_ELEMENTS(transitions), @@ -1828,7 +1826,7 @@ TECO_DEFINE_STATE(teco_state_ascii, * at the expense of yet another parser state. */ static teco_state_t * -teco_return(teco_machine_main_t *ctx, GError **error) +teco_throw_return(teco_machine_main_t *ctx, GError **error) { g_assert(ctx->flags.mode == TECO_MODE_NORMAL); @@ -1871,9 +1869,11 @@ teco_return(teco_machine_main_t *ctx, GError **error) static teco_state_t * teco_state_escape_input(teco_machine_main_t *ctx, gunichar chr, GError **error) { - if (chr == '\e' || chr == '$') - return ctx->flags.mode > TECO_MODE_NORMAL - ? &teco_state_start : teco_return(ctx, error); + if (chr == '\e' || chr == '$') { + if (ctx->flags.mode > TECO_MODE_NORMAL) + TECO_RETURN(ctx, &teco_state_start, error); + return teco_throw_return(ctx, error); + } /* * Alternatives: ^[, <CTRL/[>, <ESC>, $ (dollar) @@ -1900,7 +1900,7 @@ teco_state_escape_input(teco_machine_main_t *ctx, gunichar chr, GError **error) if (ctx->flags.mode == TECO_MODE_NORMAL && !teco_expressions_discard_args(error)) return NULL; - return teco_state_start_input(ctx, chr, error); + TECO_TAIL return teco_state_start_input(ctx, chr, error); } static gboolean @@ -1940,12 +1940,13 @@ static teco_state_t * teco_state_ctlc_input(teco_machine_main_t *ctx, gunichar chr, GError **error) { switch (chr) { - case TECO_CTL_KEY('C'): return teco_state_ctlc_control_input(ctx, 'C', error); + case TECO_CTL_KEY('C'): TECO_TAIL return teco_state_ctlc_control_input(ctx, 'C', error); case '^': TECO_RETURN(ctx, &teco_state_ctlc_control, error); } - return ctx->flags.mode > TECO_MODE_NORMAL - ? teco_state_start_input(ctx, chr, error) : teco_return(ctx, error); + if (ctx->flags.mode > TECO_MODE_NORMAL) + TECO_TAIL return teco_state_start_input(ctx, chr, error); + return teco_throw_return(ctx, error); } static gboolean @@ -2009,8 +2010,9 @@ teco_state_ctlc_control_input(teco_machine_main_t *ctx, gunichar chr, GError **e return NULL; } - return ctx->flags.mode > TECO_MODE_NORMAL - ? teco_state_control_input(ctx, chr, error) : teco_return(ctx, error); + if (ctx->flags.mode > TECO_MODE_NORMAL) + TECO_TAIL return teco_state_control_input(ctx, chr, error); + return teco_throw_return(ctx, error); } /* diff --git a/src/parser.h b/src/parser.h index 75a3432..0441a9c 100644 --- a/src/parser.h +++ b/src/parser.h @@ -557,6 +557,8 @@ gboolean teco_machine_main_step(teco_machine_main_t *ctx, #if __has_attribute(musttail) +#define TECO_TAIL __attribute__((musttail)) + /** * Transition from a teco_machine_main input_cb() to another state. * @@ -608,14 +610,14 @@ gboolean teco_machine_main_step(teco_machine_main_t *ctx, \ /* the caller's signature will not line up exactly with input_cb */ \ typedef teco_state_t *(*caller_t)(teco_machine_main_t *, gunichar, GError **); \ - __attribute__((musttail)) return ((caller_t)__state->input_cb)(__ctx, chr, __error); \ + TECO_TAIL return ((caller_t)__state->input_cb)(__ctx, chr, __error); \ } G_STMT_END #else /* __has_attribute(musttail) */ -/* - * This will effectively return into the teco_machine_main_step() loop. - */ +/* leave it to the optimizer (may or may not tail call) */ +#define TECO_TAIL +/* this will effectively return into the teco_machine_main_step() loop */ #define TECO_RETURN(CTX, STATE, ERROR) return (STATE) #endif /* !__has_attribute(musttail) */ diff --git a/src/stdio-commands.c b/src/stdio-commands.c index 94da3c7..52f1e3f 100644 --- a/src/stdio-commands.c +++ b/src/stdio-commands.c @@ -146,7 +146,7 @@ teco_state_print_decimal_input(teco_machine_main_t *ctx, gunichar chr, GError ** return NULL; teco_expressions_pop_num(0); } - return teco_state_start_input(ctx, chr, error); + TECO_TAIL return teco_state_start_input(ctx, chr, error); } /* @@ -205,7 +205,7 @@ teco_state_print_octal_input(teco_machine_main_t *ctx, gunichar chr, GError **er return NULL; teco_expressions_pop_num(0); } - return teco_state_start_input(ctx, chr, error); + TECO_TAIL return teco_state_start_input(ctx, chr, error); } /* |
