637a5bcac8
Added: gawk-4.2.1-000-add-support-for-a-and-A-in-printf.patch gawk-4.2.1-001-remove-the-tail-recursion-optimization.patch gawk-4.2.1-002-copy-MPZ-MPFR-bits-also-in-r_dupnode.patch gawk-4.2.1-003-fix-rebuilding-records-if-using-API-parser.patch gawk-4.2.1-004-fix-a-corner-case-with-EPIPE-to-stdout-stderr.patch
310 lines
8.3 KiB
Diff
310 lines
8.3 KiB
Diff
From 47316d294571673a8dbf1e9e435893e2660f46a8 Mon Sep 17 00:00:00 2001
|
|
From: "Arnold D. Robbins" <arnold@skeeve.com>
|
|
Date: Mon, 26 Mar 2018 10:45:01 +0300
|
|
Subject: [PATCH] Remove the tail recursion optimization.
|
|
|
|
---
|
|
awk.h | 4 ----
|
|
awkgram.y | 27 ++-------------------------
|
|
eval.c | 49 +++++++------------------------------------------
|
|
test/Makefile.am | 4 +++-
|
|
test/Makefile.in | 9 ++++++++-
|
|
test/Maketests | 5 +++++
|
|
test/tailrecurse.awk | 15 +++++++++++++++
|
|
test/tailrecurse.ok | 5 +++++
|
|
8 files changed, 45 insertions(+), 73 deletions(-)
|
|
create mode 100644 test/tailrecurse.awk
|
|
create mode 100644 test/tailrecurse.ok
|
|
|
|
diff --git a/awk.h b/awk.h
|
|
index 3b351c2..36e71f2 100644
|
|
--- a/awk.h
|
|
+++ b/awk.h
|
|
@@ -527,7 +527,6 @@ typedef struct exp_node {
|
|
#define func_node sub.nodep.x.extra
|
|
#define prev_frame_size sub.nodep.reflags
|
|
#define reti sub.nodep.l.li
|
|
-#define num_tail_calls sub.nodep.cnt
|
|
|
|
/* Node_var: */
|
|
#define var_value lnode
|
|
@@ -862,9 +861,6 @@ typedef struct exp_instruction {
|
|
/* Op_func_call, Op_func */
|
|
#define func_body x.xn
|
|
|
|
-/* Op_func_call */
|
|
-#define tail_call d.dl
|
|
-
|
|
/* Op_subscript */
|
|
#define sub_count d.dl
|
|
|
|
diff --git a/awkgram.y b/awkgram.y
|
|
index ad830a5..caed09e 100644
|
|
--- a/awkgram.y
|
|
+++ b/awkgram.y
|
|
@@ -993,20 +993,9 @@ non_compound_stmt
|
|
$$ = list_create($1);
|
|
(void) list_prepend($$, instruction(Op_push_i));
|
|
$$->nexti->memory = dupnode(Nnull_string);
|
|
- } else {
|
|
- if (do_optimize
|
|
- && $3->lasti->opcode == Op_func_call
|
|
- && strcmp($3->lasti->func_name, in_function) == 0
|
|
- ) {
|
|
- /* Do tail recursion optimization. Tail
|
|
- * call without a return value is recognized
|
|
- * in mk_function().
|
|
- */
|
|
- ($3->lasti + 1)->tail_call = true;
|
|
- }
|
|
-
|
|
+ } else
|
|
$$ = list_append($3, $1);
|
|
- }
|
|
+
|
|
$$ = add_pending_comment($$);
|
|
}
|
|
| simple_stmt statement_term
|
|
@@ -4736,18 +4725,6 @@ mk_function(INSTRUCTION *fi, INSTRUCTION *def)
|
|
thisfunc = fi->func_body;
|
|
assert(thisfunc != NULL);
|
|
|
|
- if (do_optimize && def->lasti->opcode == Op_pop) {
|
|
- /* tail call which does not return any value. */
|
|
-
|
|
- INSTRUCTION *t;
|
|
-
|
|
- for (t = def->nexti; t->nexti != def->lasti; t = t->nexti)
|
|
- ;
|
|
- if (t->opcode == Op_func_call
|
|
- && strcmp(t->func_name, thisfunc->vname) == 0)
|
|
- (t + 1)->tail_call = true;
|
|
- }
|
|
-
|
|
/* add any pre-function comment to start of action for profile.c */
|
|
|
|
if (function_comment != NULL) {
|
|
diff --git a/eval.c b/eval.c
|
|
index 6ece236..34ba174 100644
|
|
--- a/eval.c
|
|
+++ b/eval.c
|
|
@@ -674,7 +674,7 @@ void
|
|
dump_fcall_stack(FILE *fp)
|
|
{
|
|
NODE *f, *func;
|
|
- long i = 0, j, k = 0;
|
|
+ long i = 0, k = 0;
|
|
|
|
if (fcall_count == 0)
|
|
return;
|
|
@@ -682,15 +682,13 @@ dump_fcall_stack(FILE *fp)
|
|
|
|
/* current frame */
|
|
func = frame_ptr->func_node;
|
|
- for (j = 0; j <= frame_ptr->num_tail_calls; j++)
|
|
- fprintf(fp, "\t# %3ld. %s\n", k++, func->vname);
|
|
+ fprintf(fp, "\t# %3ld. %s\n", k++, func->vname);
|
|
|
|
/* outer frames except main */
|
|
for (i = 1; i < fcall_count; i++) {
|
|
f = fcall_list[i];
|
|
func = f->func_node;
|
|
- for (j = 0; j <= f->num_tail_calls; j++)
|
|
- fprintf(fp, "\t# %3ld. %s\n", k++, func->vname);
|
|
+ fprintf(fp, "\t# %3ld. %s\n", k++, func->vname);
|
|
}
|
|
|
|
fprintf(fp, "\t# %3ld. -- main --\n", k);
|
|
@@ -1242,38 +1240,16 @@ setup_frame(INSTRUCTION *pc)
|
|
NODE *m, *f, *fp;
|
|
NODE **sp = NULL;
|
|
int pcount, arg_count, i, j;
|
|
- bool tail_optimize = false;
|
|
|
|
f = pc->func_body;
|
|
pcount = f->param_cnt;
|
|
fp = f->fparms;
|
|
arg_count = (pc + 1)->expr_count;
|
|
|
|
- /* tail recursion optimization */
|
|
- tail_optimize = ((pc + 1)->tail_call && do_optimize
|
|
- && ! do_debug && ! do_profile);
|
|
-
|
|
- if (tail_optimize) {
|
|
- /* free local vars of calling frame */
|
|
-
|
|
- NODE *func;
|
|
- int n;
|
|
-
|
|
- func = frame_ptr->func_node;
|
|
- for (n = func->param_cnt, sp = frame_ptr->stack; n > 0; n--) {
|
|
- r = *sp++;
|
|
- if (r->type == Node_var) /* local variable */
|
|
- DEREF(r->var_value);
|
|
- else if (r->type == Node_var_array) /* local array */
|
|
- assoc_clear(r);
|
|
- }
|
|
- sp = frame_ptr->stack;
|
|
-
|
|
- } else if (pcount > 0) {
|
|
+ if (pcount > 0) {
|
|
ezalloc(sp, NODE **, pcount * sizeof(NODE *), "setup_frame");
|
|
}
|
|
|
|
-
|
|
/* check for extra args */
|
|
if (arg_count > pcount) {
|
|
warning(
|
|
@@ -1287,13 +1263,9 @@ setup_frame(INSTRUCTION *pc)
|
|
}
|
|
|
|
for (i = 0, j = arg_count - 1; i < pcount; i++, j--) {
|
|
- if (tail_optimize)
|
|
- r = sp[i];
|
|
- else {
|
|
- getnode(r);
|
|
- memset(r, 0, sizeof(NODE));
|
|
- sp[i] = r;
|
|
- }
|
|
+ getnode(r);
|
|
+ memset(r, 0, sizeof(NODE));
|
|
+ sp[i] = r;
|
|
|
|
if (i >= arg_count) {
|
|
/* local variable */
|
|
@@ -1348,11 +1320,6 @@ setup_frame(INSTRUCTION *pc)
|
|
|
|
stack_adj(-arg_count); /* adjust stack pointer */
|
|
|
|
- if (tail_optimize) {
|
|
- frame_ptr->num_tail_calls++;
|
|
- return f->code_ptr;
|
|
- }
|
|
-
|
|
if (pc->opcode == Op_indirect_func_call) {
|
|
r = POP(); /* indirect var */
|
|
DEREF(r);
|
|
@@ -1372,7 +1339,6 @@ setup_frame(INSTRUCTION *pc)
|
|
frame_ptr->stack = sp;
|
|
frame_ptr->prev_frame_size = (stack_ptr - stack_bottom); /* size of the previous stack frame */
|
|
frame_ptr->func_node = f;
|
|
- frame_ptr->num_tail_calls = 0;
|
|
frame_ptr->vname = NULL;
|
|
frame_ptr->reti = pc; /* on return execute pc->nexti */
|
|
|
|
@@ -1774,7 +1740,6 @@ init_interpret()
|
|
frame_ptr->type = Node_frame;
|
|
frame_ptr->stack = NULL;
|
|
frame_ptr->func_node = NULL; /* in main */
|
|
- frame_ptr->num_tail_calls = 0;
|
|
frame_ptr->vname = NULL;
|
|
|
|
/* initialize true and false nodes */
|
|
diff --git a/test/Makefile.am b/test/Makefile.am
|
|
index bf1dbd3..40e25b2 100644
|
|
--- a/test/Makefile.am
|
|
+++ b/test/Makefile.am
|
|
@@ -1134,6 +1134,8 @@ EXTRA_DIST = \
|
|
synerr1.ok \
|
|
synerr2.awk \
|
|
synerr2.ok \
|
|
+ tailrecurse.awk \
|
|
+ tailrecurse.ok \
|
|
testext.ok \
|
|
time.awk \
|
|
time.ok \
|
|
@@ -1253,7 +1255,7 @@ BASIC_TESTS = \
|
|
sigpipe1 sortempty sortglos splitargv splitarr \
|
|
splitdef splitvar splitwht status-close strcat1 strnum1 strnum2 strtod \
|
|
subamp subback subi18n subsepnm subslash substr swaplns synerr1 synerr2 \
|
|
- tradanch tweakfld \
|
|
+ tailrecurse tradanch tweakfld \
|
|
uninit2 uninit3 uninit4 uninit5 uninitialized unterm uparrfs uplus \
|
|
wideidx wideidx2 widesub widesub2 widesub3 widesub4 wjposer1 \
|
|
zero2 zeroe0 zeroflag
|
|
diff --git a/test/Makefile.in b/test/Makefile.in
|
|
index f96151b..74405f8 100644
|
|
--- a/test/Makefile.in
|
|
+++ b/test/Makefile.in
|
|
@@ -1392,6 +1392,8 @@ EXTRA_DIST = \
|
|
synerr1.ok \
|
|
synerr2.awk \
|
|
synerr2.ok \
|
|
+ tailrecurse.awk \
|
|
+ tailrecurse.ok \
|
|
testext.ok \
|
|
time.awk \
|
|
time.ok \
|
|
@@ -1510,7 +1512,7 @@ BASIC_TESTS = \
|
|
sigpipe1 sortempty sortglos splitargv splitarr \
|
|
splitdef splitvar splitwht status-close strcat1 strnum1 strnum2 strtod \
|
|
subamp subback subi18n subsepnm subslash substr swaplns synerr1 synerr2 \
|
|
- tradanch tweakfld \
|
|
+ tailrecurse tradanch tweakfld \
|
|
uninit2 uninit3 uninit4 uninit5 uninitialized unterm uparrfs uplus \
|
|
wideidx wideidx2 widesub widesub2 widesub3 widesub4 wjposer1 \
|
|
zero2 zeroe0 zeroflag
|
|
@@ -3919,6 +3921,11 @@ synerr2:
|
|
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
|
|
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
|
|
|
|
+tailrecurse:
|
|
+ @echo $@
|
|
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
|
|
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
|
|
+
|
|
uninit2:
|
|
@echo $@
|
|
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
|
|
diff --git a/test/Maketests b/test/Maketests
|
|
index e449dd3..4a90e3e 100644
|
|
--- a/test/Maketests
|
|
+++ b/test/Maketests
|
|
@@ -1002,6 +1002,11 @@ synerr2:
|
|
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
|
|
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
|
|
|
|
+tailrecurse:
|
|
+ @echo $@
|
|
+ @AWKPATH="$(srcdir)" $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
|
|
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
|
|
+
|
|
uninit2:
|
|
@echo $@
|
|
@AWKPATH="$(srcdir)" $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
|
|
diff --git a/test/tailrecurse.awk b/test/tailrecurse.awk
|
|
new file mode 100644
|
|
index 0000000..b287d16
|
|
--- /dev/null
|
|
+++ b/test/tailrecurse.awk
|
|
@@ -0,0 +1,15 @@
|
|
+BEGIN {
|
|
+ abc(2)
|
|
+}
|
|
+
|
|
+
|
|
+function abc(c, A, B)
|
|
+{
|
|
+ print "abc(" c ", " length(A) ")"
|
|
+ if (! c--) {
|
|
+ return
|
|
+ }
|
|
+ B[""]
|
|
+ print length(B)
|
|
+ return abc(c, B)
|
|
+}
|
|
diff --git a/test/tailrecurse.ok b/test/tailrecurse.ok
|
|
new file mode 100644
|
|
index 0000000..73ce1ed
|
|
--- /dev/null
|
|
+++ b/test/tailrecurse.ok
|
|
@@ -0,0 +1,5 @@
|
|
+abc(2, 0)
|
|
+1
|
|
+abc(1, 1)
|
|
+1
|
|
+abc(0, 1)
|
|
--
|
|
2.14.4
|
|
|