awk: use static tmpvars instead of nvalloc(1)ed ones
ptest() was using this idea already. As far as I can see, this is safe. Ttestsuite passes. One downside is that a temporary from e.g. printf invocation won't be freed until the next printf call. function old new delta awk_printf 481 468 -13 as_regex 137 111 -26 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-39) Total: -39 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
1573487e21
commit
8b4c429025
@ -559,7 +559,9 @@ struct globals2 {
|
|||||||
unsigned evaluate__seed;
|
unsigned evaluate__seed;
|
||||||
regex_t evaluate__sreg;
|
regex_t evaluate__sreg;
|
||||||
|
|
||||||
var ptest__v;
|
var ptest__tmpvar;
|
||||||
|
var awk_printf__tmpvar;
|
||||||
|
var as_regex__tmpvar;
|
||||||
|
|
||||||
tsplitter exec_builtin__tspl;
|
tsplitter exec_builtin__tspl;
|
||||||
|
|
||||||
@ -1775,14 +1777,19 @@ static node *mk_splitter(const char *s, tsplitter *spl)
|
|||||||
static regex_t *as_regex(node *op, regex_t *preg)
|
static regex_t *as_regex(node *op, regex_t *preg)
|
||||||
{
|
{
|
||||||
int cflags;
|
int cflags;
|
||||||
var *tmpvar;
|
|
||||||
const char *s;
|
const char *s;
|
||||||
|
|
||||||
if ((op->info & OPCLSMASK) == OC_REGEXP) {
|
if ((op->info & OPCLSMASK) == OC_REGEXP) {
|
||||||
return icase ? op->r.ire : op->l.re;
|
return icase ? op->r.ire : op->l.re;
|
||||||
}
|
}
|
||||||
tmpvar = nvalloc(1);
|
|
||||||
s = getvar_s(evaluate(op, tmpvar));
|
#define TMPVAR (&G.as_regex__tmpvar)
|
||||||
|
//tmpvar = nvalloc(1);
|
||||||
|
// We use a single "static" tmpvar (instead of on-stack or malloced one)
|
||||||
|
// to decrease memory consumption in deeply-recursive awk programs.
|
||||||
|
// The rule to work safely is to never call evaluate() while our static
|
||||||
|
// TMPVAR's value is still needed.
|
||||||
|
s = getvar_s(evaluate(op, TMPVAR));
|
||||||
|
|
||||||
cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED;
|
cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED;
|
||||||
/* Testcase where REG_EXTENDED fails (unpaired '{'):
|
/* Testcase where REG_EXTENDED fails (unpaired '{'):
|
||||||
@ -1794,7 +1801,8 @@ static regex_t *as_regex(node *op, regex_t *preg)
|
|||||||
cflags &= ~REG_EXTENDED;
|
cflags &= ~REG_EXTENDED;
|
||||||
xregcomp(preg, s, cflags);
|
xregcomp(preg, s, cflags);
|
||||||
}
|
}
|
||||||
nvfree(tmpvar, 1);
|
//nvfree(tmpvar, 1);
|
||||||
|
#undef TMPVAR
|
||||||
return preg;
|
return preg;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2105,8 +2113,11 @@ static int hashwalk_next(var *v)
|
|||||||
/* evaluate node, return 1 when result is true, 0 otherwise */
|
/* evaluate node, return 1 when result is true, 0 otherwise */
|
||||||
static int ptest(node *pattern)
|
static int ptest(node *pattern)
|
||||||
{
|
{
|
||||||
/* ptest__v is "static": to save stack space? */
|
// We use a single "static" tmpvar (instead of on-stack or malloced one)
|
||||||
return istrue(evaluate(pattern, &G.ptest__v));
|
// to decrease memory consumption in deeply-recursive awk programs.
|
||||||
|
// The rule to work safely is to never call evaluate() while our static
|
||||||
|
// TMPVAR's value is still needed.
|
||||||
|
return istrue(evaluate(pattern, &G.ptest__tmpvar));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read next record from stream rsm into a variable v */
|
/* read next record from stream rsm into a variable v */
|
||||||
@ -2243,12 +2254,18 @@ static char *awk_printf(node *n, int *len)
|
|||||||
const char *s1;
|
const char *s1;
|
||||||
int i, j, incr, bsize;
|
int i, j, incr, bsize;
|
||||||
char c, c1;
|
char c, c1;
|
||||||
var *tmpvar, *arg;
|
var *arg;
|
||||||
|
|
||||||
tmpvar = nvalloc(1);
|
//tmpvar = nvalloc(1);
|
||||||
//TODO: above, to avoid allocating a single temporary var, take a pointer
|
#define TMPVAR (&G.awk_printf__tmpvar)
|
||||||
//to a temporary that our caller (evaluate()) already has?
|
// We use a single "static" tmpvar (instead of on-stack or malloced one)
|
||||||
fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), tmpvar)));
|
// to decrease memory consumption in deeply-recursive awk programs.
|
||||||
|
// The rule to work safely is to never call evaluate() while our static
|
||||||
|
// TMPVAR's value is still needed.
|
||||||
|
fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), TMPVAR)));
|
||||||
|
// ^^^^^^^^^ here we immediately strdup() the value, so the later call
|
||||||
|
// to evaluate() potentially recursing into another awk_printf() can't
|
||||||
|
// mangle the value.
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while (*f) {
|
while (*f) {
|
||||||
@ -2268,7 +2285,7 @@ static char *awk_printf(node *n, int *len)
|
|||||||
f++;
|
f++;
|
||||||
c1 = *f;
|
c1 = *f;
|
||||||
*f = '\0';
|
*f = '\0';
|
||||||
arg = evaluate(nextarg(&n), tmpvar);
|
arg = evaluate(nextarg(&n), TMPVAR);
|
||||||
|
|
||||||
j = i;
|
j = i;
|
||||||
if (c == 'c' || !c) {
|
if (c == 'c' || !c) {
|
||||||
@ -2289,7 +2306,9 @@ static char *awk_printf(node *n, int *len)
|
|||||||
}
|
}
|
||||||
|
|
||||||
free(fmt);
|
free(fmt);
|
||||||
nvfree(tmpvar, 1);
|
// nvfree(tmpvar, 1);
|
||||||
|
#undef TMPVAR
|
||||||
|
|
||||||
b = xrealloc(b, i + 1);
|
b = xrealloc(b, i + 1);
|
||||||
b[i] = '\0';
|
b[i] = '\0';
|
||||||
#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
|
#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS
|
||||||
|
Loading…
Reference in New Issue
Block a user