bc: fix for() to not leave data on stack

function                                             old     new   delta
zbc_parse_stmt_possibly_auto                        1665    1697     +32
zbc_vm_process                                       672     701     +29
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 2/0 up/down: 61/0)               Total: 61 bytes
   text	   data	    bss	    dec	    hex	filename
 981656	    485	   7296	 989437	  f18fd	busybox_old
 981748	    485	   7296	 989529	  f1959	busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Denys Vlasenko 2018-12-21 20:29:34 +01:00
parent 5d57bc442d
commit 19eee8ed7c
2 changed files with 38 additions and 25 deletions

View File

@ -170,6 +170,8 @@
#define DEBUG_LEXER 0 #define DEBUG_LEXER 0
#define DEBUG_COMPILE 0 #define DEBUG_COMPILE 0
#define DEBUG_EXEC 0 #define DEBUG_EXEC 0
// This can be left enabled for production as well:
#define SANITY_CHECKS 1
#if DEBUG_LEXER #if DEBUG_LEXER
static uint8_t lex_indent; static uint8_t lex_indent;
@ -1218,8 +1220,6 @@ static char** bc_program_const(size_t idx)
IF_DC(return bc_vec_item(&G.prog.consts, idx);) IF_DC(return bc_vec_item(&G.prog.consts, idx);)
} }
static int bc_id_cmp(const void *e1, const void *e2) static int bc_id_cmp(const void *e1, const void *e2)
{ {
return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name); return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
@ -4227,12 +4227,15 @@ static BC_STATUS zbc_parse_for(BcParse *p)
s = zbc_lex_next(&p->l); s = zbc_lex_next(&p->l);
if (s) RETURN_STATUS(s); if (s) RETURN_STATUS(s);
if (p->l.t.t != BC_LEX_SCOLON) if (p->l.t.t != BC_LEX_SCOLON) {
s = zbc_parse_expr(p, 0); s = zbc_parse_expr(p, 0);
else bc_parse_push(p, BC_INST_POP);
if (s) RETURN_STATUS(s);
} else {
s = bc_POSIX_does_not_allow_empty_X_expression_in_for("init"); s = bc_POSIX_does_not_allow_empty_X_expression_in_for("init");
IF_ERROR_RETURN_POSSIBLE(if (s) RETURN_STATUS(s);)
}
if (s) RETURN_STATUS(s);
if (p->l.t.t != BC_LEX_SCOLON) RETURN_STATUS(bc_error_bad_token()); if (p->l.t.t != BC_LEX_SCOLON) RETURN_STATUS(bc_error_bad_token());
s = zbc_lex_next(&p->l); s = zbc_lex_next(&p->l);
if (s) RETURN_STATUS(s); if (s) RETURN_STATUS(s);
@ -4254,8 +4257,8 @@ static BC_STATUS zbc_parse_for(BcParse *p)
bc_parse_pushNUM(p); bc_parse_pushNUM(p);
s = bc_POSIX_does_not_allow_empty_X_expression_in_for("condition"); s = bc_POSIX_does_not_allow_empty_X_expression_in_for("condition");
} }
if (s) RETURN_STATUS(s); if (s) RETURN_STATUS(s);
if (p->l.t.t != BC_LEX_SCOLON) RETURN_STATUS(bc_error_bad_token()); if (p->l.t.t != BC_LEX_SCOLON) RETURN_STATUS(bc_error_bad_token());
s = zbc_lex_next(&p->l); s = zbc_lex_next(&p->l);
@ -4267,12 +4270,14 @@ static BC_STATUS zbc_parse_for(BcParse *p)
bc_vec_push(&p->conds, &update_idx); bc_vec_push(&p->conds, &update_idx);
bc_vec_push(&p->func->labels, &p->func->code.len); bc_vec_push(&p->func->labels, &p->func->code.len);
if (p->l.t.t != BC_LEX_RPAREN) if (p->l.t.t != BC_LEX_RPAREN) {
s = zbc_parse_expr(p, 0); s = zbc_parse_expr(p, 0);
else bc_parse_push(p, BC_INST_POP);
if (s) RETURN_STATUS(s);
} else {
s = bc_POSIX_does_not_allow_empty_X_expression_in_for("update"); s = bc_POSIX_does_not_allow_empty_X_expression_in_for("update");
IF_ERROR_RETURN_POSSIBLE(if (s) RETURN_STATUS(s);)
if (s) RETURN_STATUS(s); }
if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token()); if (p->l.t.t != BC_LEX_RPAREN) RETURN_STATUS(bc_error_bad_token());
bc_parse_pushJUMP(p, cond_idx); bc_parse_pushJUMP(p, cond_idx);
@ -6434,12 +6439,13 @@ static BC_STATUS zbc_program_exec(void)
BcFunc *func = bc_program_func(ip->func); BcFunc *func = bc_program_func(ip->func);
char *code = func->code.v; char *code = func->code.v;
dbg_exec("func:%zd bytes:%zd ip:%zd", ip->func, func->code.len, ip->idx); dbg_exec("func:%zd bytes:%zd ip:%zd results.len:%d",
ip->func, func->code.len, ip->idx, G.prog.results.len);
while (ip->idx < func->code.len) { while (ip->idx < func->code.len) {
BcStatus s = BC_STATUS_SUCCESS; BcStatus s = BC_STATUS_SUCCESS;
char inst = code[ip->idx++]; char inst = code[ip->idx++];
dbg_exec("inst at %zd:%d", ip->idx - 1, inst); dbg_exec("inst at %zd:%d results.len:%d", ip->idx - 1, inst, G.prog.results.len);
switch (inst) { switch (inst) {
#if ENABLE_BC #if ENABLE_BC
case BC_INST_JUMP_ZERO: { case BC_INST_JUMP_ZERO: {
@ -6671,7 +6677,6 @@ static BC_STATUS zbc_program_exec(void)
} }
fflush_and_check(); fflush_and_check();
} }
RETURN_STATUS(BC_STATUS_SUCCESS); RETURN_STATUS(BC_STATUS_SUCCESS);
@ -6723,23 +6728,16 @@ static BC_STATUS zbc_vm_process(const char *text)
// storage. // storage.
if (IS_BC) { if (IS_BC) {
BcFunc *f; BcFunc *f;
BcInstPtr *ip; BcInstPtr *ip = (void*)G.prog.exestack.v;
//FIXME: this does not clear up the stack
//for(i=1; i<3; i++) {
// i
// if(i==2) continue
// 77
//}
// if (G.prog.results.len != 0)
// bb_error_msg_and_die("data stack not empty: %d slots", G.prog.results.len);
#if SANITY_CHECKS
if (G.prog.results.len != 0)
bb_error_msg_and_die("data stack not empty: %d slots", G.prog.results.len);
if (G.prog.exestack.len != 1) // should be empty if (G.prog.exestack.len != 1) // should be empty
bb_error_msg_and_die("BUG:call stack"); bb_error_msg_and_die("BUG:call stack");
ip = (void*)G.prog.exestack.v;
if (ip->func != BC_PROG_MAIN) if (ip->func != BC_PROG_MAIN)
bb_error_msg_and_die("BUG:not MAIN"); bb_error_msg_and_die("BUG:not MAIN");
#endif
//bb_error_msg("ip->func:%d >idx:%d >len:%d", ip->func, ip->idx, ip->len); //bb_error_msg("ip->func:%d >idx:%d >len:%d", ip->func, ip->idx, ip->len);
f = bc_program_func_BC_PROG_MAIN(); 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 //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

View File

@ -56,6 +56,21 @@ testing "bc for(;;)" \
"2\n3\n2\n9\n" \ "2\n3\n2\n9\n" \
"" "i=2; for (;;) { 2; if(--i==0) break; 3; }; 9" "" "i=2; for (;;) { 2; if(--i==0) break; 3; }; 9"
testing "bc for (;cond;)" \
"bc" \
"1\n2\n3\n9\n" \
"" "i=0; for(;i<3;)++i; 9"
testing "bc for (;cond;upd)" \
"bc" \
"1\n2\n3\n9\n" \
"" "i=1; for(;i<4;i++)i; 9"
testing "bc for (init;cond;upd)" \
"bc" \
"1\n2\n3\n9\n" \
"" "for(i=1;i<4;i++)i; 9"
testing "bc define auto" \ testing "bc define auto" \
"bc" \ "bc" \
"8\n9\n" \ "8\n9\n" \