1
0
Fork 0
mirror of git://git.code.sf.net/p/zsh/code synced 2025-10-24 04:50:27 +02:00

41802 (minor tweaks): use heap during shell function call.

Replaces stack for more efficient memory management.

Also fix debug message when FUNCNEST is increased.
This commit is contained in:
Peter Stephenson 2017-10-04 09:18:51 +01:00
parent 174e560a23
commit e573857a03
3 changed files with 93 additions and 70 deletions

View file

@ -1,3 +1,9 @@
2017-10-04 Peter Stephenson <p.stephenson@samsung.com>
* 41802 (minor tweaks): Src/exec.c, Src/parse.c: use heap
instead of stack for temporary storage over shell function call,
also fix debug message when FUNCNEST increased.
2017-10-02 Peter Stephenson <p.stephenson@samsung.com> 2017-10-02 Peter Stephenson <p.stephenson@samsung.com>
* 41787 (minor corrections): configure.ac, README, * 41787 (minor corrections): configure.ac, README,

View file

@ -41,6 +41,20 @@ enum {
ADDVAR_RESTORE = 1 << 2 ADDVAR_RESTORE = 1 << 2
}; };
/* Structure in which to save values around shell function call */
struct funcsave {
char opts[OPT_SIZE];
char *argv0;
int zoptind, lastval, optcind, numpipestats;
int *pipestats;
char *scriptname;
int breaks, contflag, loops, emulation, noerrexit, oflags, restore_sticky;
Emulation_options sticky;
struct funcstack fstack;
};
typedef struct funcsave *Funcsave;
/* /*
* used to suppress ERREXIT and trapping of SIGZERR, SIGEXIT. * used to suppress ERREXIT and trapping of SIGZERR, SIGEXIT.
* Bits from noerrexit_bits. * Bits from noerrexit_bits.
@ -5495,34 +5509,36 @@ int sticky_emulation_differs(Emulation_options sticky2)
mod_export int mod_export int
doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval) doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
{ {
char **pptab, **x, *oargv0; char **pptab, **x;
int oldzoptind, oldlastval, oldoptcind, oldnumpipestats, ret; int ret;
int *oldpipestats = NULL;
char saveopts[OPT_SIZE], *oldscriptname = scriptname;
char *name = shfunc->node.nam; char *name = shfunc->node.nam;
int flags = shfunc->node.flags, ooflags; int flags = shfunc->node.flags;
int savnoerrexit;
char *fname = dupstring(name); char *fname = dupstring(name);
int obreaks, ocontflag, oloops, saveemulation, restore_sticky;
Eprog prog; Eprog prog;
struct funcstack fstack;
static int oflags; static int oflags;
Emulation_options save_sticky = NULL;
static int funcdepth; static int funcdepth;
Heap funcheap; Heap funcheap;
queue_signals(); /* Lots of memory and global state changes coming */ queue_signals(); /* Lots of memory and global state changes coming */
NEWHEAPS(funcheap) { NEWHEAPS(funcheap) {
oargv0 = NULL; /*
obreaks = breaks; * Save data in heap rather than on stack to keep recursive
ocontflag = contflag; * function cost down --- use of heap memory should be efficient
oloops = loops; * at this point. Saving is not actually massive.
*/
Funcsave funcsave = zhalloc(sizeof(struct funcsave));
funcsave->scriptname = scriptname;
funcsave->argv0 = NULL;
funcsave->breaks = breaks;
funcsave->contflag = contflag;
funcsave->loops = loops;
funcsave->lastval = lastval;
funcsave->pipestats = NULL;
funcsave->numpipestats = numpipestats;
funcsave->noerrexit = noerrexit;
if (trap_state == TRAP_STATE_PRIMED) if (trap_state == TRAP_STATE_PRIMED)
trap_return--; trap_return--;
oldlastval = lastval;
oldnumpipestats = numpipestats;
savnoerrexit = noerrexit;
/* /*
* Suppression of ERR_RETURN is turned off in function scope. * Suppression of ERR_RETURN is turned off in function scope.
*/ */
@ -5533,8 +5549,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
* immediately by a pushheap/popheap pair. * immediately by a pushheap/popheap pair.
*/ */
size_t bytes = sizeof(int)*numpipestats; size_t bytes = sizeof(int)*numpipestats;
oldpipestats = (int *)zhalloc(bytes); funcsave->pipestats = (int *)zhalloc(bytes);
memcpy(oldpipestats, pipestats, bytes); memcpy(funcsave->pipestats, pipestats, bytes);
} }
starttrapscope(); starttrapscope();
@ -5543,8 +5559,8 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
pptab = pparams; pptab = pparams;
if (!(flags & PM_UNDEFINED)) if (!(flags & PM_UNDEFINED))
scriptname = dupstring(name); scriptname = dupstring(name);
oldzoptind = zoptind; funcsave->zoptind = zoptind;
oldoptcind = optcind; funcsave->optcind = optcind;
if (!isset(POSIXBUILTINS)) { if (!isset(POSIXBUILTINS)) {
zoptind = 1; zoptind = 1;
optcind = 0; optcind = 0;
@ -5553,9 +5569,9 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
/* We need to save the current options even if LOCALOPTIONS is * /* We need to save the current options even if LOCALOPTIONS is *
* not currently set. That's because if it gets set in the * * not currently set. That's because if it gets set in the *
* function we need to restore the original options on exit. */ * function we need to restore the original options on exit. */
memcpy(saveopts, opts, sizeof(opts)); memcpy(funcsave->opts, opts, sizeof(opts));
saveemulation = emulation; funcsave->emulation = emulation;
save_sticky = sticky; funcsave->sticky = sticky;
if (sticky_emulation_differs(shfunc->sticky)) { if (sticky_emulation_differs(shfunc->sticky)) {
/* /*
@ -5572,7 +5588,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
*/ */
sticky = sticky_emulation_dup(shfunc->sticky, 1); sticky = sticky_emulation_dup(shfunc->sticky, 1);
emulation = sticky->emulation; emulation = sticky->emulation;
restore_sticky = 1; funcsave->restore_sticky = 1;
installemulation(emulation, opts); installemulation(emulation, opts);
if (sticky->n_on_opts) { if (sticky->n_on_opts) {
OptIndex *onptr; OptIndex *onptr;
@ -5591,7 +5607,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
/* All emulations start with pattern disables clear */ /* All emulations start with pattern disables clear */
clearpatterndisables(); clearpatterndisables();
} else } else
restore_sticky = 0; funcsave->restore_sticky = 0;
if (flags & (PM_TAGGED|PM_TAGGED_LOCAL)) if (flags & (PM_TAGGED|PM_TAGGED_LOCAL))
opts[XTRACE] = 1; opts[XTRACE] = 1;
@ -5609,11 +5625,11 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
else else
opts[WARNNESTEDVAR] = 0; opts[WARNNESTEDVAR] = 0;
} }
ooflags = oflags; funcsave->oflags = oflags;
/* /*
* oflags is static, because we compare it on the next recursive * oflags is static, because we compare it on the next recursive
* call. Hence also we maintain ooflags for restoring the previous * call. Hence also we maintain a saved version for restoring
* value of oflags after the call. * the previous value of oflags after the call.
*/ */
oflags = flags; oflags = flags;
opts[PRINTEXITVALUE] = 0; opts[PRINTEXITVALUE] = 0;
@ -5624,7 +5640,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
pparams = x = (char **) zshcalloc(((sizeof *x) * pparams = x = (char **) zshcalloc(((sizeof *x) *
(1 + countlinknodes(doshargs)))); (1 + countlinknodes(doshargs))));
if (isset(FUNCTIONARGZERO)) { if (isset(FUNCTIONARGZERO)) {
oargv0 = argzero; funcsave->argv0 = argzero;
argzero = ztrdup(getdata(node)); argzero = ztrdup(getdata(node));
} }
/* first node contains name regardless of option */ /* first node contains name regardless of option */
@ -5634,7 +5650,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
} else { } else {
pparams = (char **) zshcalloc(sizeof *pparams); pparams = (char **) zshcalloc(sizeof *pparams);
if (isset(FUNCTIONARGZERO)) { if (isset(FUNCTIONARGZERO)) {
oargv0 = argzero; funcsave->argv0 = argzero;
argzero = ztrdup(argzero); argzero = ztrdup(argzero);
} }
} }
@ -5644,21 +5660,21 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
lastval = 1; lastval = 1;
goto undoshfunc; goto undoshfunc;
} }
fstack.name = dupstring(name); funcsave->fstack.name = dupstring(name);
/* /*
* The caller is whatever is immediately before on the stack, * The caller is whatever is immediately before on the stack,
* unless we're at the top, in which case it's the script * unless we're at the top, in which case it's the script
* or interactive shell name. * or interactive shell name.
*/ */
fstack.caller = funcstack ? funcstack->name : funcsave->fstack.caller = funcstack ? funcstack->name :
dupstring(oargv0 ? oargv0 : argzero); dupstring(funcsave->argv0 ? funcsave->argv0 : argzero);
fstack.lineno = lineno; funcsave->fstack.lineno = lineno;
fstack.prev = funcstack; funcsave->fstack.prev = funcstack;
fstack.tp = FS_FUNC; funcsave->fstack.tp = FS_FUNC;
funcstack = &fstack; funcstack = &funcsave->fstack;
fstack.flineno = shfunc->lineno; funcsave->fstack.flineno = shfunc->lineno;
fstack.filename = getshfuncfile(shfunc); funcsave->fstack.filename = getshfuncfile(shfunc);
prog = shfunc->funcdef; prog = shfunc->funcdef;
if (prog->flags & EF_RUN) { if (prog->flags & EF_RUN) {
@ -5666,7 +5682,7 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
prog->flags &= ~EF_RUN; prog->flags &= ~EF_RUN;
runshfunc(prog, NULL, fstack.name); runshfunc(prog, NULL, funcsave->fstack.name);
if (!(shf = (Shfunc) shfunctab->getnode(shfunctab, if (!(shf = (Shfunc) shfunctab->getnode(shfunctab,
(name = fname)))) { (name = fname)))) {
@ -5679,52 +5695,52 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
} }
prog = shf->funcdef; prog = shf->funcdef;
} }
runshfunc(prog, wrappers, fstack.name); runshfunc(prog, wrappers, funcsave->fstack.name);
doneshfunc: doneshfunc:
funcstack = fstack.prev; funcstack = funcsave->fstack.prev;
undoshfunc: undoshfunc:
--funcdepth; --funcdepth;
if (retflag) { if (retflag) {
retflag = 0; retflag = 0;
breaks = obreaks; breaks = funcsave->breaks;
} }
freearray(pparams); freearray(pparams);
if (oargv0) { if (funcsave->argv0) {
zsfree(argzero); zsfree(argzero);
argzero = oargv0; argzero = funcsave->argv0;
} }
pparams = pptab; pparams = pptab;
if (!isset(POSIXBUILTINS)) { if (!isset(POSIXBUILTINS)) {
zoptind = oldzoptind; zoptind = funcsave->zoptind;
optcind = oldoptcind; optcind = funcsave->optcind;
} }
scriptname = oldscriptname; scriptname = funcsave->scriptname;
oflags = ooflags; oflags = funcsave->oflags;
endpatternscope(); /* before restoring old LOCALPATTERNS */ endpatternscope(); /* before restoring old LOCALPATTERNS */
if (restore_sticky) { if (funcsave->restore_sticky) {
/* /*
* If we switched to an emulation environment just for * If we switched to an emulation environment just for
* this function, we interpret the option and emulation * this function, we interpret the option and emulation
* switch as being a firewall between environments. * switch as being a firewall between environments.
*/ */
memcpy(opts, saveopts, sizeof(opts)); memcpy(opts, funcsave->opts, sizeof(opts));
emulation = saveemulation; emulation = funcsave->emulation;
sticky = save_sticky; sticky = funcsave->sticky;
} else if (isset(LOCALOPTIONS)) { } else if (isset(LOCALOPTIONS)) {
/* restore all shell options except PRIVILEGED and RESTRICTED */ /* restore all shell options except PRIVILEGED and RESTRICTED */
saveopts[PRIVILEGED] = opts[PRIVILEGED]; funcsave->opts[PRIVILEGED] = opts[PRIVILEGED];
saveopts[RESTRICTED] = opts[RESTRICTED]; funcsave->opts[RESTRICTED] = opts[RESTRICTED];
memcpy(opts, saveopts, sizeof(opts)); memcpy(opts, funcsave->opts, sizeof(opts));
emulation = saveemulation; emulation = funcsave->emulation;
} else { } else {
/* just restore a couple. */ /* just restore a couple. */
opts[XTRACE] = saveopts[XTRACE]; opts[XTRACE] = funcsave->opts[XTRACE];
opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE]; opts[PRINTEXITVALUE] = funcsave->opts[PRINTEXITVALUE];
opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS]; opts[LOCALOPTIONS] = funcsave->opts[LOCALOPTIONS];
opts[LOCALLOOPS] = saveopts[LOCALLOOPS]; opts[LOCALLOOPS] = funcsave->opts[LOCALLOOPS];
opts[WARNNESTEDVAR] = saveopts[WARNNESTEDVAR]; opts[WARNNESTEDVAR] = funcsave->opts[WARNNESTEDVAR];
} }
if (opts[LOCALLOOPS]) { if (opts[LOCALLOOPS]) {
@ -5732,9 +5748,9 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
zwarn("`continue' active at end of function scope"); zwarn("`continue' active at end of function scope");
if (breaks) if (breaks)
zwarn("`break' active at end of function scope"); zwarn("`break' active at end of function scope");
breaks = obreaks; breaks = funcsave->breaks;
contflag = ocontflag; contflag = funcsave->contflag;
loops = oloops; loops = funcsave->loops;
} }
endtrapscope(); endtrapscope();
@ -5742,11 +5758,11 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
if (trap_state == TRAP_STATE_PRIMED) if (trap_state == TRAP_STATE_PRIMED)
trap_return++; trap_return++;
ret = lastval; ret = lastval;
noerrexit = savnoerrexit; noerrexit = funcsave->noerrexit;
if (noreturnval) { if (noreturnval) {
lastval = oldlastval; lastval = funcsave->lastval;
numpipestats = oldnumpipestats; numpipestats = funcsave->numpipestats;
memcpy(pipestats, oldpipestats, sizeof(int)*numpipestats); memcpy(pipestats, funcsave->pipestats, sizeof(int)*numpipestats);
} }
} OLDHEAPS; } OLDHEAPS;

View file

@ -2742,7 +2742,8 @@ freeeprog(Eprog p)
DPUTS(p->nref < 0 && !(p->flags & EF_HEAP), "Real EPROG has nref < 0"); DPUTS(p->nref < 0 && !(p->flags & EF_HEAP), "Real EPROG has nref < 0");
DPUTS(p->nref < -1, "Uninitialised EPROG nref"); DPUTS(p->nref < -1, "Uninitialised EPROG nref");
#ifdef MAX_FUNCTION_DEPTH #ifdef MAX_FUNCTION_DEPTH
DPUTS(p->nref > MAX_FUNCTION_DEPTH + 10, "Overlarge EPROG nref"); DPUTS(zsh_funcnest >=0 && p->nref > zsh_funcnest + 10,
"Overlarge EPROG nref");
#endif #endif
if (p->nref > 0 && !--p->nref) { if (p->nref > 0 && !--p->nref) {
for (i = p->npats, pp = p->pats; i--; pp++) for (i = p->npats, pp = p->pats; i--; pp++)