[git commit] awk: free unused parsing structures after parse is done

Denys Vlasenko vda.linux at googlemail.com
Tue Jun 29 17:06:59 UTC 2021


commit: https://git.busybox.net/busybox/commit/?id=b3c91a127f8baecee0265ba92898ae1e718bdb31
branch: https://git.busybox.net/busybox/commit/?id=refs/heads/master

function                                             old     new   delta
hash_clear                                             -      90     +90
awk_main                                             827     849     +22
clear_array                                           90       -     -90
------------------------------------------------------------------------------
(add/remove: 1/1 grow/shrink: 1/0 up/down: 112/-90)            Total: 22 bytes

Signed-off-by: Denys Vlasenko <vda.linux at googlemail.com>
---
 editors/awk.c | 74 +++++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 47 insertions(+), 27 deletions(-)

diff --git a/editors/awk.c b/editors/awk.c
index 6142144bb..4e29b28cf 100644
--- a/editors/awk.c
+++ b/editors/awk.c
@@ -530,7 +530,8 @@ struct globals {
 	xhash *ahash;  /* argument names, used only while parsing function bodies */
 	xhash *fnhash; /* function names, used only in parsing stage */
 	xhash *vhash;  /* variables and arrays */
-	xhash *fdhash; /* file objects, used only in execution stage */
+	//xhash *fdhash; /* file objects, used only in execution stage */
+	//we are reusing ahash as fdhash, via define (see later)
 	const char *g_progname;
 	int g_lineno;
 	int nfields;
@@ -592,10 +593,13 @@ struct globals2 {
 #define break_ptr    (G1.break_ptr   )
 #define continue_ptr (G1.continue_ptr)
 #define iF           (G1.iF          )
-#define vhash        (G1.vhash       )
 #define ahash        (G1.ahash       )
-#define fdhash       (G1.fdhash      )
 #define fnhash       (G1.fnhash      )
+#define vhash        (G1.vhash       )
+#define fdhash       ahash
+//^^^^^^^^^^^^^^^^^^ ahash is cleared after every function parsing,
+// and ends up empty after parsing phase. Thus, we can simply reuse it
+// for fdhash in execution stage.
 #define g_progname   (G1.g_progname  )
 #define g_lineno     (G1.g_lineno    )
 #define nfields      (G1.nfields     )
@@ -682,6 +686,33 @@ static xhash *hash_init(void)
 	return newhash;
 }
 
+static void hash_clear(xhash *hash)
+{
+	unsigned i;
+	hash_item *hi, *thi;
+
+	for (i = 0; i < hash->csize; i++) {
+		hi = hash->items[i];
+		while (hi) {
+			thi = hi;
+			hi = hi->next;
+			free(thi->data.v.string);
+			free(thi);
+		}
+		hash->items[i] = NULL;
+	}
+	hash->glen = hash->nel = 0;
+}
+
+#if 0 //UNUSED
+static void hash_free(xhash *hash)
+{
+	hash_clear(hash);
+	free(hash->items);
+	free(hash);
+}
+#endif
+
 /* find item in hash, return ptr to data, NULL if not found */
 static void *hash_search(xhash *hash, const char *name)
 {
@@ -869,23 +900,7 @@ static xhash *iamarray(var *v)
 	return a->x.array;
 }
 
-static void clear_array(xhash *array)
-{
-	unsigned i;
-	hash_item *hi, *thi;
-
-	for (i = 0; i < array->csize; i++) {
-		hi = array->items[i];
-		while (hi) {
-			thi = hi;
-			hi = hi->next;
-			free(thi->data.v.string);
-			free(thi);
-		}
-		array->items[i] = NULL;
-	}
-	array->glen = array->nel = 0;
-}
+#define clear_array(array) hash_clear(array)
 
 /* clear a variable */
 static var *clrvar(var *v)
@@ -1742,7 +1757,7 @@ static void parse_program(char *p)
 			}
 			seq = &f->body;
 			chain_group();
-			clear_array(ahash);
+			hash_clear(ahash);
 		} else if (tclass & TS_OPSEQ) {
 			debug_printf_parse("%s: TS_OPSEQ\n", __func__);
 			rollback_token();
@@ -3471,11 +3486,16 @@ int awk_main(int argc UNUSED_PARAM, char **argv)
 			bb_show_usage();
 		parse_program(*argv++);
 	}
-	//free_hash(ahash) // ~250 bytes, arg names, used only during parse of function bodies
-	//ahash = NULL; // debug
-	//free_hash(fnhash) // ~250 bytes, used only for function names
-	//fnhash = NULL; // debug
-	/* parsing done, on to executing */
+	/* Free unused parse structures */
+	//hash_free(fnhash); // ~250 bytes when empty, used only for function names
+	//^^^^^^^^^^^^^^^^^ does not work, hash_clear() inside SEGVs
+	// (IOW: hash_clear() assumes it's a hash of variables. fnhash is not).
+	free(fnhash->items);
+	free(fnhash);
+	fnhash = NULL; // debug
+	//hash_free(ahash); // empty after parsing, will reuse as fdhash instead of freeing
+
+	/* Parsing done, on to executing */
 
 	/* fill in ARGV array */
 	setari_u(intvar[ARGV], 0, "awk");
@@ -3484,7 +3504,7 @@ int awk_main(int argc UNUSED_PARAM, char **argv)
 		setari_u(intvar[ARGV], ++i, *argv++);
 	setvar_i(intvar[ARGC], i + 1);
 
-	fdhash = hash_init();
+	//fdhash = ahash - done via define
 	newfile("/dev/stdin")->F = stdin;
 	newfile("/dev/stdout")->F = stdout;
 	newfile("/dev/stderr")->F = stderr;


More information about the busybox-cvs mailing list