diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2020-04-11 19:59:26 -0700 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2020-04-11 23:41:50 -0700 |
commit | 3d7330b827d6e9cc0d9e87edd30388374cb45900 (patch) | |
tree | 2731382bb1425855b2adc4d1420a47e4dfa87eb8 /match.c | |
parent | a4c376979d15323ad729e92e41ba43768e8dc163 (diff) | |
download | txr-3d7330b827d6e9cc0d9e87edd30388374cb45900.tar.gz txr-3d7330b827d6e9cc0d9e87edd30388374cb45900.tar.bz2 txr-3d7330b827d6e9cc0d9e87edd30388374cb45900.zip |
txr: avoid by-value match_files_ctx passing.
Passing the match_files_ctx structure by value looks nice in
the code, but it is contributing to a long standing false
retention issue.
This test case runs in constant memory:
$ yes | txr -c '@(skip)
n'
skip scans through the lazy list of "y" lines
looking for an "n" that never comes.
This version should also run in constant memory,
but shows unbounded memory growth.
$ yes | txr -c '@(next *stdin*)
@(skip)
n'
This patch doesn't fix it, but it moves things in that
direction.
* match.c (mf_all, mf_args, mf_data, mf_spec,
mf_spec_bindings, mf_file_data, mf_from_ml): Take pointer to structure
which to initialize and return that pointer, instead of
initializing a local structure and returning it by value.
(match_files): Take pointer to context rather than copy.
(h_call, do_match_line, v_fuzz, v_block, v_next_impl,
v_parallel, v_gather, v_collect, v_bind, hv_trampoline,
v_try, v_fun, v_if, v_assesrt, v_load, v_call, match_filter,
match_fun, extract): Adjust to by-pointer context handling of
mf_all, match_files and other functions.
Diffstat (limited to 'match.c')
-rw-r--r-- | match.c | 261 |
1 files changed, 144 insertions, 117 deletions
@@ -1488,8 +1488,9 @@ typedef struct { val spec, files, curfile, bindings, data, data_lineno; } match_files_ctx; -static match_files_ctx mf_all(val spec, val files, val bindings, - val data, val curfile); +static match_files_ctx *mf_all(match_files_ctx *nc, + val spec, val files, val bindings, + val data, val curfile); static val v_fun(match_files_ctx *c); @@ -1513,11 +1514,11 @@ static val h_call(match_line_ctx *c) if (ret == decline_k) { val spec = cons(new_specline, nil); - match_files_ctx vc = mf_all(spec, nil, c->bindings, nil, c->file); - val vresult = v_fun(&vc); + match_files_ctx vcs, *vc = mf_all(&vcs, spec, nil, c->bindings, nil, c->file); + val vresult = v_fun(vc); if (vresult == next_spec_k) { - c->bindings = vc.bindings; + c->bindings = vc->bindings; return vresult; } else if (vresult == decline_k) { sem_error(elem, lit("call: function ~s not found"), funval, nao); @@ -1582,15 +1583,15 @@ static val do_match_line(match_line_ctx *c) continue; } else if (result == decline_k) { val spec = rlcp(cons(cons(elem, nil), nil), elem); - match_files_ctx vc = mf_all(spec, nil, c->bindings, - nil, c->file); - val vresult = v_fun(&vc); + match_files_ctx vcs, *vc = mf_all(&vcs, spec, nil, c->bindings, + nil, c->file); + val vresult = v_fun(vc); if (vresult == next_spec_k) { - c->bindings = vc.bindings; + c->bindings = vc->bindings; break; } else if (vresult == repeat_spec_k) { - c->bindings = vc.bindings; + c->bindings = vc->bindings; continue; } else if (vresult == decline_k) { if (gethash(v_directive_table, directive)) @@ -2246,78 +2247,80 @@ static void do_output(val bindings, val specs, val filter, val out) } } -static match_files_ctx mf_all(val spec, val files, val bindings, - val data, val curfile) +static match_files_ctx *mf_all(match_files_ctx *nc, + val spec, val files, val bindings, + val data, val curfile) { - match_files_ctx c; - c.spec = spec; - c.files = files; - c.curfile = curfile; - c.bindings = bindings; - c.data = data; - c.data_lineno = if3(data, one, zero); - return c; + nc->spec = spec; + nc->files = files; + nc->curfile = curfile; + nc->bindings = bindings; + nc->data = data; + nc->data_lineno = if3(data, one, zero); + return nc; } -static match_files_ctx mf_args(match_files_ctx c) +static match_files_ctx *mf_args(match_files_ctx *nc, match_files_ctx *c) { - match_files_ctx nc = c; - nc.data = c.files; - nc.curfile = lit("args"); - nc.data_lineno = one; + *nc = *c; + nc->data = c->files; + nc->curfile = lit("args"); + nc->data_lineno = one; return nc; } -static match_files_ctx mf_data(match_files_ctx c, val data, val data_lineno) +static match_files_ctx *mf_data(match_files_ctx *nc, match_files_ctx *c, + val data, val data_lineno) { - match_files_ctx nc = c; - nc.data = data; - nc.data_lineno = data_lineno; + *nc = *c; + nc->data = data; + nc->data_lineno = data_lineno; return nc; } -static match_files_ctx mf_spec(match_files_ctx c, val spec) +static match_files_ctx *mf_spec(match_files_ctx *nc, + const match_files_ctx *c, val spec) { - match_files_ctx nc = c; - nc.spec = spec; + *nc = *c; + nc->spec = spec; return nc; } -static match_files_ctx mf_spec_bindings(match_files_ctx c, val spec, - val bindings) +static match_files_ctx *mf_spec_bindings(match_files_ctx *nc, + match_files_ctx *c, val spec, + val bindings) { - match_files_ctx nc = c; - nc.spec = spec; - nc.bindings = bindings; + *nc = *c; + nc->spec = spec; + nc->bindings = bindings; return nc; } -static match_files_ctx mf_file_data(match_files_ctx c, val file, - val data, val data_lineno) +static match_files_ctx *mf_file_data(match_files_ctx *nc, + match_files_ctx *c, val file, + val data, val data_lineno) { - match_files_ctx nc = c; - nc.files = cons(file, c.files); - nc.curfile = file; - nc.data = data; - nc.data_lineno = data_lineno; + *nc = *c; + nc->files = cons(file, c->files); + nc->curfile = file; + nc->data = data; + nc->data_lineno = data_lineno; return nc; } -static match_files_ctx mf_from_ml(match_line_ctx ml) +static match_files_ctx *mf_from_ml(match_files_ctx *nc, match_line_ctx *ml) { - match_files_ctx mf; - - mf.spec = cons(ml.specline, nil); - mf.files = nil; - mf.curfile = ml.file; - mf.bindings = ml.bindings; - mf.data = nil; - mf.data_lineno = ml.data_lineno; + nc->spec = cons(ml->specline, nil); + nc->files = nil; + nc->curfile = ml->file; + nc->bindings = ml->bindings; + nc->data = nil; + nc->data_lineno = ml->data_lineno; - return mf; + return nc; } -static val match_files(match_files_ctx a); +static val match_files(match_files_ctx *c); typedef val (*v_match_func)(match_files_ctx *cout); @@ -2372,7 +2375,7 @@ static val v_skip(match_files_ctx *c) } while (greedy || !max || reps_max++ < cmax) { - result = match_files(*c); + result = match_files(c); if (result) { if (greedy) { @@ -2438,7 +2441,7 @@ static val v_fuzz(match_files_ctx *c) cnum reps, good; for (reps = 0, good = 0; reps < cn; reps++) { - match_files_ctx fuzz_ctx = mf_spec(*c, cons(first(c->spec), nil)); + match_files_ctx fs, *fuzz_ctx = mf_spec(&fs, c, cons(first(c->spec), nil)); val result = match_files(fuzz_ctx); if (result) { @@ -2470,7 +2473,7 @@ static val v_fuzz(match_files_ctx *c) return nil; } - return match_files(*c); + return match_files(c); } } } @@ -2490,7 +2493,7 @@ static val v_trailer(match_files_ctx *c) if (!c->spec) { result = cons(c->bindings, cons(c->data, c->data_lineno)); } else { - cons_bind (new_bindings, success, match_files(*c)); + cons_bind (new_bindings, success, match_files(c)); result = if2(success, cons(new_bindings, cons(c->data, c->data_lineno))); } @@ -2627,7 +2630,8 @@ static val v_block(match_files_ctx *c) { uw_block_begin(name, result); - result = match_files(mf_spec(*c, spec)); + match_files_ctx cs; + result = match_files(mf_spec(&cs, c, spec)); uw_block_end; if (vectorp(result)) @@ -2683,8 +2687,9 @@ static val v_next_impl(match_files_ctx *c) if (rest(args)) { sem_error(specline, lit("(next :args) takes no additional arguments"), nao); } else { + match_files_ctx cs; cons_bind (new_bindings, success, - match_files(mf_args(*c))); + match_files(mf_args(&cs, c))); if (success) return cons(new_bindings, @@ -2695,8 +2700,9 @@ static val v_next_impl(match_files_ctx *c) if (rest(args)) { sem_error(specline, lit("(next :env) takes no additional arguments"), nao); } else { + match_files_ctx cs; cons_bind (new_bindings, success, - match_files(mf_file_data(*c, lit("env"), env(), one))); + match_files(mf_file_data(&cs, c, lit("env"), env(), one))); if (success) return cons(new_bindings, @@ -2708,8 +2714,9 @@ static val v_next_impl(match_files_ctx *c) if (sym == var_s || sym == expr_s) meta = t; } else if (!source) { + match_files_ctx cs; cons_bind (new_bindings, success, - match_files(mf_all(c->spec, nil, c->bindings, nil, lit("empty")))); + match_files(mf_all(&cs, c->spec, nil, c->bindings, nil, lit("empty")))); if (success) return cons(new_bindings, @@ -2764,8 +2771,9 @@ static val v_next_impl(match_files_ctx *c) val existing = tx_lookup_var_ubc(from_var, c->bindings, first_spec); { + match_files_ctx cs; cons_bind (new_bindings, success, - match_files(mf_file_data(*c, lit("var"), + match_files(mf_file_data(&cs, c, lit("var"), lazy_flatten(cdr(existing)), one))); if (success) @@ -2782,8 +2790,9 @@ static val v_next_impl(match_files_ctx *c) goto nothrow_lisp; { + match_files_ctx cs; cons_bind (new_bindings, success, - match_files(mf_file_data(*c, lit("var"), + match_files(mf_file_data(&cs, c, lit("var"), lazy_flatten(list_val), one))); if (success) @@ -2793,8 +2802,9 @@ static val v_next_impl(match_files_ctx *c) } } else if (tlist_expr) { val list_val = txeval(specline, tlist_expr, c->bindings); + match_files_ctx cs; cons_bind (new_bindings, success, - match_files(mf_file_data(*c, lit("var"), + match_files(mf_file_data(&cs, c, lit("var"), lazy_flatten(list_val), one))); if (success) @@ -2811,8 +2821,9 @@ static val v_next_impl(match_files_ctx *c) sem_error(specline, lit(":string arg ~s evaluated to non-string ~s"), string_expr, str_val, nao); { + match_files_ctx cs; cons_bind (new_bindings, success, - match_files(mf_file_data(*c, lit("var"), + match_files(mf_file_data(&cs, c, lit("var"), split_str(str_val, lit("\n")), one))); if (success) @@ -2844,8 +2855,9 @@ static val v_next_impl(match_files_ctx *c) val stream = complex_open(str, nil, nil, nothrow, nil); if (stream) { + match_files_ctx cs; cons_bind (new_bindings, success, - match_files(mf_file_data(*c, str, + match_files(mf_file_data(&cs, c, str, lazy_stream_cons(stream), one))); if (success) @@ -2871,7 +2883,8 @@ static val v_next_impl(match_files_ctx *c) original file we we were called with. Hence, we can't make a straight tail call here. */ { - cons_bind (new_bindings, success, match_files(mf_data(*c, t, nil))); + match_files_ctx cs; + cons_bind (new_bindings, success, match_files(mf_data(&cs, c, t, nil))); if (success) return cons(new_bindings, @@ -2948,8 +2961,9 @@ static val v_parallel(match_files_ctx *c) for (iter = specs; iter != nil; iter = rest(iter)) { val nested_spec = first(iter); + match_files_ctx cs; cons_bind (new_bindings, success, - match_files(mf_spec(*c, nested_spec))); + match_files(mf_spec(&cs, c, nested_spec))); if (success) { some_match = t; @@ -3075,8 +3089,9 @@ static val v_gather(match_files_ctx *c) for (iter = specs, next = cdr(iter); iter != nil; iter = next, next = cdr(iter)) { val nested_spec = first(iter); + match_files_ctx cs; cons_bind (new_bindings, success, - match_files(mf_spec(*c, nested_spec))); + match_files(mf_spec(&cs, c, nested_spec))); if (!success) { rplacd(iter, nil); @@ -3096,8 +3111,9 @@ static val v_gather(match_files_ctx *c) if (until_last) { + match_files_ctx cs; cons_bind (until_last_bindings, success, - match_files(mf_spec(*c, ul_spec))); + match_files(mf_spec(&cs, c, ul_spec))); if (success) { debuglf(specline, lit("until/last matched ~a:~d"), @@ -3378,11 +3394,13 @@ static val v_collect(match_files_ctx *c) break; { + match_files_ctx cs; + if (counter) { rplacd(counter_binding, plus(num(timescounter), counter_base)); rplacd(bindings_with_counter, c->bindings); cons_set (new_bindings, success, - match_files(mf_spec_bindings(*c, coll_spec, bindings_with_counter))); + match_files(mf_spec_bindings(&cs, c, coll_spec, bindings_with_counter))); if (!new_bindings) { rplacd(counter_binding, nil); @@ -3390,7 +3408,7 @@ static val v_collect(match_files_ctx *c) } } else { cons_set (new_bindings, success, - match_files(mf_spec(*c, coll_spec))); + match_files(mf_spec(&cs, c, coll_spec))); } /* Until/last clause sees un-collated bindings from collect. */ @@ -3398,7 +3416,7 @@ static val v_collect(match_files_ctx *c) { uses_or2; cons_bind (until_last_bindings, success, - match_files(mf_spec_bindings(*c, ul_spec, + match_files(mf_spec_bindings(&cs, c, ul_spec, or2(new_bindings, c->bindings)))); if (success) { @@ -3683,7 +3701,7 @@ static val v_bind(match_files_ctx *c) static val hv_trampoline(match_line_ctx *c) { val ret; - match_files_ctx mf = mf_from_ml(*c); + match_files_ctx cs, *mf = mf_from_ml(&cs, c); val sym = first(first(c->specline)); val entry = gethash(v_directive_table, sym); @@ -3692,9 +3710,9 @@ static val hv_trampoline(match_line_ctx *c) { v_match_func vmf = coerce(v_match_func, cptr_get(entry)); - ret = vmf(&mf); + ret = vmf(mf); if (ret == next_spec_k) - c->bindings = mf.bindings; + c->bindings = mf->bindings; return ret; } } @@ -3898,10 +3916,11 @@ static val v_try(match_files_ctx *c) val finally_clause = nil; { + match_files_ctx cs; uw_block_begin(nil, result); uw_catch_begin(catch_syms, exsym, exvals); - result = match_files(mf_spec(*c, try_clause)); + result = match_files(mf_spec(&cs, c, try_clause)); uw_catch(exsym, exvals) { { @@ -3937,8 +3956,9 @@ static val v_try(match_files_ctx *c) } if (all_bind) { + match_files_ctx cs; cons_bind (new_bindings, success, - match_files(mf_spec(*c, body))); + match_files(mf_spec(&cs, c, body))); if (success) { c->bindings = new_bindings; result = t; /* catch succeeded, so try succeeds */ @@ -3994,8 +4014,9 @@ static val v_try(match_files_ctx *c) v_take_accept(c, specline, ex->bl.result); if (finally_clause) { + match_files_ctx cs; cons_bind (new_bindings, success, - match_files(mf_spec(*c, finally_clause))); + match_files(mf_spec(&cs, c, finally_clause))); if (success) { c->bindings = new_bindings; @@ -4204,12 +4225,14 @@ static val v_fun(match_files_ctx *c) { args_decl_list(args, ARGS_MIN, bindings_cp); + match_files_ctx cs; + uw_block_begin(nil, result); uw_match_env_begin; uw_simple_catch_begin; - result = match_files(mf_spec_bindings(*c, body, bindings_cp)); + result = match_files(mf_spec_bindings(&cs, c, body, bindings_cp)); uw_unwind { fun_intercept_accept(c->bindings, ub_p_a_pairs, sym, specline); @@ -4283,8 +4306,10 @@ static val v_if(match_files_ctx *c) for (; args; args = cdr(args)) { cons_bind (expr, spec, car(args)); - if (tleval(c->spec, expr, c->bindings)) - return maybe_next(c, match_files(mf_spec(*c, spec))); + if (tleval(c->spec, expr, c->bindings)) { + match_files_ctx cs; + return maybe_next(c, match_files(mf_spec(&cs, c, spec))); + } } return next_spec_k; @@ -4305,7 +4330,7 @@ static val v_assert(match_files_ctx *c) { val args = rest(first_spec); val type = pop(&args); - val result = match_files(*c); + val result = match_files(c); if (result) { return result; @@ -4377,7 +4402,8 @@ static val v_load(match_files_ctx *c) ret = parser->syntax_tree; } else { val spec = parser->syntax_tree; - val result = match_files(mf_spec(*c, spec)); + match_files_ctx cs; + val result = match_files(mf_spec(&cs, c, spec)); if (!result) { debuglf(specline, lit("load: ~a failed"), path, nao); @@ -4518,8 +4544,8 @@ static val v_call(match_files_ctx *c) val argexprs = cdr(exprs); val call = cons(funval, argexprs); val spec = cons(cons(call, nil), nil); - match_files_ctx ctx = mf_spec_bindings(*c, spec, c->bindings); - val ret = v_fun(&ctx); + match_files_ctx cs, *nc = mf_spec_bindings(&cs, c, spec, c->bindings); + val ret = v_fun(nc); if (ret == nil) return nil; @@ -4527,7 +4553,7 @@ static val v_call(match_files_ctx *c) if (ret == decline_k) sem_error(nil, lit("call: function ~s not found"), funval, nao); - return cons(ctx.bindings, if3(ctx.data, cons(ctx.data, ctx.data_lineno), t)); + return cons(cs.bindings, if3(cs.data, cons(cs.data, cs.data_lineno), t)); } static val h_do(match_line_ctx *c) @@ -4619,18 +4645,18 @@ static void open_data_source(match_files_ctx *c) } } -static val match_files(match_files_ctx c) +static val match_files(match_files_ctx *c) { - gc_hint(c.data); + gc_hint(c->data); - for (; c.spec; c.spec = rest(c.spec), - c.data = rest(c.data), - c.data_lineno = plus(c.data_lineno, one)) + for (; c->spec; c->spec = rest(c->spec), + c->data = rest(c->data), + c->data_lineno = plus(c->data_lineno, one)) repeat_spec_same_data: { - spec_bind (specline, first_spec, c.spec); + spec_bind (specline, first_spec, c->spec); - open_data_source(&c); + open_data_source(c); /* Line with nothing but a single directive or call: vertical mode. */ if (consp(first_spec) && !rest(specline)) { @@ -4642,12 +4668,12 @@ repeat_spec_same_data: /* It's actually a var or text; go to horizontal processing below */ } else if (entry) { v_match_func vmf = coerce(v_match_func, cptr_get(entry)); - val result = vmf(&c); + val result = vmf(c); set_last_form_evaled(lfe_save); if (result == next_spec_k) { - if ((c.spec = rest(c.spec)) == nil) + if ((c->spec = rest(c->spec)) == nil) break; goto repeat_spec_same_data; } else if (result == decline_k) { @@ -4658,12 +4684,12 @@ repeat_spec_same_data: } else if (gethash(h_directive_table,sym)) { /* Lone horizontal-only directive: go to horizontal processing */ } else { - val result = v_fun(&c); + val result = v_fun(c); set_last_form_evaled(lfe_save); if (result == next_spec_k) { - if ((c.spec = rest(c.spec)) == nil) + if ((c->spec = rest(c->spec)) == nil) break; goto repeat_spec_same_data; } else if (result == decline_k) { @@ -4676,22 +4702,22 @@ repeat_spec_same_data: } } - open_data_source(&c); + open_data_source(c); - if (consp(c.data) && car(c.data)) + if (consp(c->data) && car(c->data)) { - val dataline = car(c.data); + val dataline = car(c->data); cons_bind (new_bindings, success, - match_line_completely(ml_all(c.bindings, specline, + match_line_completely(ml_all(c->bindings, specline, dataline, zero, - c.data, c.data_lineno, c.curfile))); + c->data, c->data_lineno, c->curfile))); if (!success) return nil; - c.bindings = new_bindings; - } else if (consp(c.data) || nilp(c.data)) { + c->bindings = new_bindings; + } else if (consp(c->data) || nilp(c->data)) { debuglf(specline, lit("spec ran out of data"), nao); return nil; } else { @@ -4699,7 +4725,7 @@ repeat_spec_same_data: } } - return cons(c.bindings, if3(c.data, cons(c.data, c.data_lineno), t)); + return cons(c->bindings, if3(c->data, cons(c->data, c->data_lineno), t)); } val match_filter(val name, val arg, val other_args) @@ -4712,8 +4738,8 @@ val match_filter(val name, val arg, val other_args) val spec = cons(list(cons(name, cons(in_arg_sym, cons(out_arg_sym, other_args))), nao), nil); - match_files_ctx c = mf_all(spec, nil, bindings, nil, nil); - val ret = v_fun(&c); + match_files_ctx cs, *c = mf_all(&cs, spec, nil, bindings, nil, nil); + val ret = v_fun(c); (void) first_spec; rlcp(car(spec), specline); @@ -4726,7 +4752,7 @@ val match_filter(val name, val arg, val other_args) sem_error(specline, lit("filter: function ~s not found"), name, nao); { - val out = tx_lookup_var(out_arg_sym, c.bindings); + val out = tx_lookup_var(out_arg_sym, cs.bindings); if (!out) sem_error(specline, lit("filter: (~s ~s ~s) did not bind ~s"), name, @@ -4750,10 +4776,10 @@ val match_fun(val name, val args, val input_in, val files_in) lazy_stream_cons(input), input); /* TODO: pass through source location context */ - match_files_ctx c = mf_all(spec, files, in_bindings, data, curfile); + match_files_ctx cs, *c = mf_all(&cs, spec, files, in_bindings, data, curfile); val ret; - ret = v_fun(&c); + ret = v_fun(c); if (ret == nil) return nil; @@ -4761,19 +4787,20 @@ val match_fun(val name, val args, val input_in, val files_in) if (ret == decline_k) sem_error(nil, lit("match-fun: function ~s not found"), name, nao); - return cons(c.bindings, if3(c.data, cons(c.data, c.data_lineno), t)); + return cons(cs.bindings, if3(cs.data, cons(cs.data, cs.data_lineno), t)); } val include(val specline) { val spec = cons(specline, nil); - match_files_ctx c = mf_all(spec, nil, nil, nil, nil); - return v_load(&c); + match_files_ctx cs, *c = mf_all(&cs, spec, nil, nil, nil, nil); + return v_load(c); } val extract(val spec, val files, val predefined_bindings) { - val result = match_files(mf_all(spec, files, predefined_bindings, + match_files_ctx cs; + val result = match_files(mf_all(&cs, spec, files, predefined_bindings, t, nil)); cons_bind (bindings, success, result); |