bc: make long-running dc drop data it does not need (when it can)
function old new delta zbc_vm_process 765 824 +59 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
5cf0b2d466
commit
ec74a9c145
@ -3437,11 +3437,11 @@ static BC_STATUS zdc_lex_token(BcLex *l)
|
|||||||
// break;
|
// break;
|
||||||
case '\n':
|
case '\n':
|
||||||
// '\n' is BC_LEX_NLINE, not BC_LEX_WHITESPACE
|
// '\n' is BC_LEX_NLINE, not BC_LEX_WHITESPACE
|
||||||
// (and "case '\n'" is not just empty here)
|
// (and "case '\n':" is not just empty here)
|
||||||
// only to allow interactive dc have a way to exit
|
// only to allow interactive dc have a way to exit
|
||||||
// "parse" stage of "parse,execute" loop
|
// "parse" stage of "parse,execute" loop
|
||||||
// on '\n', not on _next_ token (which would mean
|
// on <enter>, not on _next_ token (which would mean
|
||||||
// command are not executed on pressing <enter>).
|
// commands are not executed on pressing <enter>).
|
||||||
// IOW: typing "1p<enter>" should print "1" _at once_,
|
// IOW: typing "1p<enter>" should print "1" _at once_,
|
||||||
// not after some more input.
|
// not after some more input.
|
||||||
l->t.t = BC_LEX_NLINE;
|
l->t.t = BC_LEX_NLINE;
|
||||||
@ -6673,6 +6673,9 @@ static BC_STATUS zbc_vm_process(const char *text)
|
|||||||
if (s) RETURN_STATUS(s);
|
if (s) RETURN_STATUS(s);
|
||||||
|
|
||||||
while (G.prs.l.t.t != BC_LEX_EOF) {
|
while (G.prs.l.t.t != BC_LEX_EOF) {
|
||||||
|
BcInstPtr *ip;
|
||||||
|
BcFunc *f;
|
||||||
|
|
||||||
dbg_lex("%s:%d G.prs.l.t.t:%d, parsing...", __func__, __LINE__, G.prs.l.t.t);
|
dbg_lex("%s:%d G.prs.l.t.t:%d, parsing...", __func__, __LINE__, G.prs.l.t.t);
|
||||||
if (IS_BC) {
|
if (IS_BC) {
|
||||||
// FIXME: "eating" of stmt delimiters is coded inconsistently
|
// FIXME: "eating" of stmt delimiters is coded inconsistently
|
||||||
@ -6695,6 +6698,15 @@ static BC_STATUS zbc_vm_process(const char *text)
|
|||||||
bc_program_reset();
|
bc_program_reset();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ip = (void*)G.prog.exestack.v;
|
||||||
|
#if SANITY_CHECKS
|
||||||
|
if (G.prog.exestack.len != 1) // should have only main's IP
|
||||||
|
bb_error_msg_and_die("BUG:call stack");
|
||||||
|
if (ip->func != BC_PROG_MAIN)
|
||||||
|
bb_error_msg_and_die("BUG:not MAIN");
|
||||||
|
#endif
|
||||||
|
f = bc_program_func_BC_PROG_MAIN();
|
||||||
// bc discards strings, constants and code after each
|
// bc discards strings, constants and code after each
|
||||||
// top-level statement in the "main program".
|
// top-level statement in the "main program".
|
||||||
// This prevents "yes 1 | bc" from growing its memory
|
// This prevents "yes 1 | bc" from growing its memory
|
||||||
@ -6706,22 +6718,10 @@ static BC_STATUS zbc_vm_process(const char *text)
|
|||||||
// but bc stores function strings/constants in per-function
|
// but bc stores function strings/constants in per-function
|
||||||
// storage.
|
// storage.
|
||||||
if (IS_BC) {
|
if (IS_BC) {
|
||||||
BcFunc *f;
|
|
||||||
BcInstPtr *ip = (void*)G.prog.exestack.v;
|
|
||||||
|
|
||||||
#if SANITY_CHECKS
|
#if SANITY_CHECKS
|
||||||
if (G.prog.results.len != 0) // should be empty
|
if (G.prog.results.len != 0) // should be empty
|
||||||
bb_error_msg_and_die("BUG:data stack");
|
bb_error_msg_and_die("BUG:data stack");
|
||||||
if (G.prog.exestack.len != 1) // should have only main's IP
|
|
||||||
bb_error_msg_and_die("BUG:call stack");
|
|
||||||
if (ip->func != BC_PROG_MAIN)
|
|
||||||
bb_error_msg_and_die("BUG:not MAIN");
|
|
||||||
#endif
|
#endif
|
||||||
//bb_error_msg("ip->func:%d >idx:%d >len:%d", ip->func, ip->inst_idx, ip->len);
|
|
||||||
f = bc_program_func_BC_PROG_MAIN();
|
|
||||||
//bb_error_msg("MAIN->code.len:%d >strs.len:%d >consts.len:%d", f->code.len, f->strs.len, f->consts.len); // labels, autos, nparams
|
|
||||||
bc_vec_pop_all(&f->code);
|
|
||||||
ip->inst_idx = 0;
|
|
||||||
IF_BC(bc_vec_pop_all(&f->strs);)
|
IF_BC(bc_vec_pop_all(&f->strs);)
|
||||||
IF_BC(bc_vec_pop_all(&f->consts);)
|
IF_BC(bc_vec_pop_all(&f->consts);)
|
||||||
} else {
|
} else {
|
||||||
@ -6731,7 +6731,26 @@ static BC_STATUS zbc_vm_process(const char *text)
|
|||||||
s = zbc_lex_next(&G.prs.l);
|
s = zbc_lex_next(&G.prs.l);
|
||||||
if (s) RETURN_STATUS(s);
|
if (s) RETURN_STATUS(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (G.prog.results.len == 0
|
||||||
|
&& G.prog.vars.len == 0
|
||||||
|
) {
|
||||||
|
// If stack is empty and no registers exist (TODO: or they are all empty),
|
||||||
|
// we can get rid of accumulated strings and constants.
|
||||||
|
// In this example dc process should not grow
|
||||||
|
// its memory consumption with time:
|
||||||
|
// yes 1pc | dc
|
||||||
|
IF_DC(bc_vec_pop_all(&G.prog.strs);)
|
||||||
|
IF_DC(bc_vec_pop_all(&G.prog.consts);)
|
||||||
}
|
}
|
||||||
|
// The code is discarded always (below), thus this example
|
||||||
|
// should also not grow its memory consumption with time,
|
||||||
|
// even though its data stack is not empty:
|
||||||
|
// { echo 1; yes dk; } | dc
|
||||||
|
}
|
||||||
|
// We drop generated and executed code for both bc and dc:
|
||||||
|
bc_vec_pop_all(&f->code);
|
||||||
|
ip->inst_idx = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg_lex_done("%s:%d done", __func__, __LINE__);
|
dbg_lex_done("%s:%d done", __func__, __LINE__);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user