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:
		@@ -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
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user