diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2021-07-01 17:50:26 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2021-07-01 17:50:26 +0200 |
commit | 8b4c429025c233640bd5c5838552f34683a06fc0 (patch) | |
tree | 385135c4fd35dbfd8f4e682c3819c0d46dc4770b | |
parent | 1573487e2100892d06e3628828690692313a48d5 (diff) | |
download | busybox-w32-8b4c429025c233640bd5c5838552f34683a06fc0.tar.gz busybox-w32-8b4c429025c233640bd5c5838552f34683a06fc0.tar.bz2 busybox-w32-8b4c429025c233640bd5c5838552f34683a06fc0.zip |
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>
-rw-r--r-- | editors/awk.c | 49 |
1 files changed, 34 insertions, 15 deletions
diff --git a/editors/awk.c b/editors/awk.c index 2c2cb74d7..0be044eef 100644 --- a/editors/awk.c +++ b/editors/awk.c | |||
@@ -559,7 +559,9 @@ struct globals2 { | |||
559 | unsigned evaluate__seed; | 559 | unsigned evaluate__seed; |
560 | regex_t evaluate__sreg; | 560 | regex_t evaluate__sreg; |
561 | 561 | ||
562 | var ptest__v; | 562 | var ptest__tmpvar; |
563 | var awk_printf__tmpvar; | ||
564 | var as_regex__tmpvar; | ||
563 | 565 | ||
564 | tsplitter exec_builtin__tspl; | 566 | tsplitter exec_builtin__tspl; |
565 | 567 | ||
@@ -1775,14 +1777,19 @@ static node *mk_splitter(const char *s, tsplitter *spl) | |||
1775 | static regex_t *as_regex(node *op, regex_t *preg) | 1777 | static regex_t *as_regex(node *op, regex_t *preg) |
1776 | { | 1778 | { |
1777 | int cflags; | 1779 | int cflags; |
1778 | var *tmpvar; | ||
1779 | const char *s; | 1780 | const char *s; |
1780 | 1781 | ||
1781 | if ((op->info & OPCLSMASK) == OC_REGEXP) { | 1782 | if ((op->info & OPCLSMASK) == OC_REGEXP) { |
1782 | return icase ? op->r.ire : op->l.re; | 1783 | return icase ? op->r.ire : op->l.re; |
1783 | } | 1784 | } |
1784 | tmpvar = nvalloc(1); | 1785 | |
1785 | s = getvar_s(evaluate(op, tmpvar)); | 1786 | #define TMPVAR (&G.as_regex__tmpvar) |
1787 | //tmpvar = nvalloc(1); | ||
1788 | // We use a single "static" tmpvar (instead of on-stack or malloced one) | ||
1789 | // to decrease memory consumption in deeply-recursive awk programs. | ||
1790 | // The rule to work safely is to never call evaluate() while our static | ||
1791 | // TMPVAR's value is still needed. | ||
1792 | s = getvar_s(evaluate(op, TMPVAR)); | ||
1786 | 1793 | ||
1787 | cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED; | 1794 | cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED; |
1788 | /* Testcase where REG_EXTENDED fails (unpaired '{'): | 1795 | /* Testcase where REG_EXTENDED fails (unpaired '{'): |
@@ -1794,7 +1801,8 @@ static regex_t *as_regex(node *op, regex_t *preg) | |||
1794 | cflags &= ~REG_EXTENDED; | 1801 | cflags &= ~REG_EXTENDED; |
1795 | xregcomp(preg, s, cflags); | 1802 | xregcomp(preg, s, cflags); |
1796 | } | 1803 | } |
1797 | nvfree(tmpvar, 1); | 1804 | //nvfree(tmpvar, 1); |
1805 | #undef TMPVAR | ||
1798 | return preg; | 1806 | return preg; |
1799 | } | 1807 | } |
1800 | 1808 | ||
@@ -2105,8 +2113,11 @@ static int hashwalk_next(var *v) | |||
2105 | /* evaluate node, return 1 when result is true, 0 otherwise */ | 2113 | /* evaluate node, return 1 when result is true, 0 otherwise */ |
2106 | static int ptest(node *pattern) | 2114 | static int ptest(node *pattern) |
2107 | { | 2115 | { |
2108 | /* ptest__v is "static": to save stack space? */ | 2116 | // We use a single "static" tmpvar (instead of on-stack or malloced one) |
2109 | return istrue(evaluate(pattern, &G.ptest__v)); | 2117 | // to decrease memory consumption in deeply-recursive awk programs. |
2118 | // The rule to work safely is to never call evaluate() while our static | ||
2119 | // TMPVAR's value is still needed. | ||
2120 | return istrue(evaluate(pattern, &G.ptest__tmpvar)); | ||
2110 | } | 2121 | } |
2111 | 2122 | ||
2112 | /* read next record from stream rsm into a variable v */ | 2123 | /* read next record from stream rsm into a variable v */ |
@@ -2243,12 +2254,18 @@ static char *awk_printf(node *n, int *len) | |||
2243 | const char *s1; | 2254 | const char *s1; |
2244 | int i, j, incr, bsize; | 2255 | int i, j, incr, bsize; |
2245 | char c, c1; | 2256 | char c, c1; |
2246 | var *tmpvar, *arg; | 2257 | var *arg; |
2247 | 2258 | ||
2248 | tmpvar = nvalloc(1); | 2259 | //tmpvar = nvalloc(1); |
2249 | //TODO: above, to avoid allocating a single temporary var, take a pointer | 2260 | #define TMPVAR (&G.awk_printf__tmpvar) |
2250 | //to a temporary that our caller (evaluate()) already has? | 2261 | // We use a single "static" tmpvar (instead of on-stack or malloced one) |
2251 | fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), tmpvar))); | 2262 | // to decrease memory consumption in deeply-recursive awk programs. |
2263 | // The rule to work safely is to never call evaluate() while our static | ||
2264 | // TMPVAR's value is still needed. | ||
2265 | fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), TMPVAR))); | ||
2266 | // ^^^^^^^^^ here we immediately strdup() the value, so the later call | ||
2267 | // to evaluate() potentially recursing into another awk_printf() can't | ||
2268 | // mangle the value. | ||
2252 | 2269 | ||
2253 | i = 0; | 2270 | i = 0; |
2254 | while (*f) { | 2271 | while (*f) { |
@@ -2268,7 +2285,7 @@ static char *awk_printf(node *n, int *len) | |||
2268 | f++; | 2285 | f++; |
2269 | c1 = *f; | 2286 | c1 = *f; |
2270 | *f = '\0'; | 2287 | *f = '\0'; |
2271 | arg = evaluate(nextarg(&n), tmpvar); | 2288 | arg = evaluate(nextarg(&n), TMPVAR); |
2272 | 2289 | ||
2273 | j = i; | 2290 | j = i; |
2274 | if (c == 'c' || !c) { | 2291 | if (c == 'c' || !c) { |
@@ -2289,7 +2306,9 @@ static char *awk_printf(node *n, int *len) | |||
2289 | } | 2306 | } |
2290 | 2307 | ||
2291 | free(fmt); | 2308 | free(fmt); |
2292 | nvfree(tmpvar, 1); | 2309 | // nvfree(tmpvar, 1); |
2310 | #undef TMPVAR | ||
2311 | |||
2293 | b = xrealloc(b, i + 1); | 2312 | b = xrealloc(b, i + 1); |
2294 | b[i] = '\0'; | 2313 | b[i] = '\0'; |
2295 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS | 2314 | #if ENABLE_FEATURE_AWK_GNU_EXTENSIONS |