about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--Src/exec.c402
2 files changed, 206 insertions, 201 deletions
diff --git a/ChangeLog b/ChangeLog
index 2e31d243b..f0c88c979 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2015-10-14  Barton E. Schaefer  <schaefer@zsh.org>
+
+	* 36853: Src/exec.c: replace pushheap/popheap by NEWHEAPS/OLDHEAPS
+	in doshfunc() to optimize memory management
+
 2015-10-14  Peter Stephenson  <p.stephenson@samsung.com>
 
 	* 36856: Doc/Zsh/contrib.yo, Functions/Chpwd/cdr: add -p and -P
diff --git a/Src/exec.c b/Src/exec.c
index bcc8065a2..f0d1d2f70 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -5067,230 +5067,230 @@ doshfunc(Shfunc shfunc, LinkList doshargs, int noreturnval)
 #ifdef MAX_FUNCTION_DEPTH
     static int funcdepth;
 #endif
+    Heap funcheap;
 
     queue_signals();	/* Lots of memory and global state changes coming */
 
-    pushheap();
+    NEWHEAPS(funcheap) {
+	oargv0 = NULL;
+	obreaks = breaks;
+	ocontflag = contflag;
+	oloops = loops;
+	if (trap_state == TRAP_STATE_PRIMED)
+	    trap_return--;
+	oldlastval = lastval;
+	oldnumpipestats = numpipestats;
+	if (noreturnval) {
+	    /*
+	     * Easiest to use the heap here since we're bracketed
+	     * immediately by a pushheap/popheap pair.
+	     */
+	    size_t bytes = sizeof(int)*numpipestats;
+	    oldpipestats = (int *)zhalloc(bytes);
+	    memcpy(oldpipestats, pipestats, bytes);
+	}
 
-    oargv0 = NULL;
-    obreaks = breaks;
-    ocontflag = contflag;
-    oloops = loops;
-    if (trap_state == TRAP_STATE_PRIMED)
-	trap_return--;
-    oldlastval = lastval;
-    oldnumpipestats = numpipestats;
-    if (noreturnval) {
-	/*
-	 * Easiest to use the heap here since we're bracketed
-	 * immediately by a pushheap/popheap pair.
-	 */
-	size_t bytes = sizeof(int)*numpipestats;
-	oldpipestats = (int *)zhalloc(bytes);
-	memcpy(oldpipestats, pipestats, bytes);
-    }
+	starttrapscope();
+	startpatternscope();
+
+	pptab = pparams;
+	if (!(flags & PM_UNDEFINED))
+	    scriptname = dupstring(name);
+	oldzoptind = zoptind;
+	oldoptcind = optcind;
+	if (!isset(POSIXBUILTINS)) {
+	    zoptind = 1;
+	    optcind = 0;
+	}
 
-    starttrapscope();
-    startpatternscope();
-
-    pptab = pparams;
-    if (!(flags & PM_UNDEFINED))
-	scriptname = dupstring(name);
-    oldzoptind = zoptind;
-    oldoptcind = optcind;
-    if (!isset(POSIXBUILTINS)) {
-	zoptind = 1;
-	optcind = 0;
-    }
+	/* We need to save the current options even if LOCALOPTIONS is *
+	 * not currently set.  That's because if it gets set in the    *
+	 * function we need to restore the original options on exit.   */
+	memcpy(saveopts, opts, sizeof(opts));
+	saveemulation = emulation;
+	save_sticky = sticky;
 
-    /* We need to save the current options even if LOCALOPTIONS is *
-     * not currently set.  That's because if it gets set in the    *
-     * function we need to restore the original options on exit.   */
-    memcpy(saveopts, opts, sizeof(opts));
-    saveemulation = emulation;
-    save_sticky = sticky;
+	if (sticky_emulation_differs(shfunc->sticky)) {
+	    /*
+	     * Function is marked for sticky emulation.
+	     * Enable it now.
+	     *
+	     * We deliberately do not do this if the sticky emulation
+	     * in effect is the same as that requested.  This enables
+	     * option setting naturally within emulation environments.
+	     * Note that a difference in EMULATE_FULLY (emulate with
+	     * or without -R) counts as a different environment.
+	     *
+	     * This propagates the sticky emulation to subfunctions.
+	     */
+	    sticky = sticky_emulation_dup(shfunc->sticky, 1);
+	    emulation = sticky->emulation;
+	    restore_sticky = 1;
+	    installemulation(emulation, opts);
+	    if (sticky->n_on_opts) {
+		OptIndex *onptr;
+		for (onptr = sticky->on_opts;
+		     onptr < sticky->on_opts + sticky->n_on_opts;
+		     onptr++)
+		    opts[*onptr] = 1;
+	    }
+	    if (sticky->n_off_opts) {
+		OptIndex *offptr;
+		for (offptr = sticky->off_opts;
+		     offptr < sticky->off_opts + sticky->n_off_opts;
+		     offptr++)
+		    opts[*offptr] = 0;
+	    }
+	    /* All emulations start with pattern disables clear */
+	    clearpatterndisables();
+	} else
+	    restore_sticky = 0;
 
-    if (sticky_emulation_differs(shfunc->sticky)) {
+	if (flags & (PM_TAGGED|PM_TAGGED_LOCAL))
+	    opts[XTRACE] = 1;
+	else if (oflags & PM_TAGGED_LOCAL)
+	    opts[XTRACE] = 0;
+	ooflags = oflags;
 	/*
-	 * Function is marked for sticky emulation.
-	 * Enable it now.
-	 *
-	 * We deliberately do not do this if the sticky emulation
-	 * in effect is the same as that requested.  This enables
-	 * option setting naturally within emulation environments.
-	 * Note that a difference in EMULATE_FULLY (emulate with
-	 * or without -R) counts as a different environment.
-	 *
-	 * This propagates the sticky emulation to subfunctions.
+	 * oflags is static, because we compare it on the next recursive
+	 * call.  Hence also we maintain ooflags for restoring the previous
+	 * value of oflags after the call.
 	 */
-	sticky = sticky_emulation_dup(shfunc->sticky, 1);
-	emulation = sticky->emulation;
-	restore_sticky = 1;
-	installemulation(emulation, opts);
-	if (sticky->n_on_opts) {
-	    OptIndex *onptr;
-	    for (onptr = sticky->on_opts;
-		 onptr < sticky->on_opts + sticky->n_on_opts;
-		 onptr++)
-		opts[*onptr] = 1;
-	}
-	if (sticky->n_off_opts) {
-	    OptIndex *offptr;
-	    for (offptr = sticky->off_opts;
-		 offptr < sticky->off_opts + sticky->n_off_opts;
-		 offptr++)
-		opts[*offptr] = 0;
-	}
-	/* All emulations start with pattern disables clear */
-	clearpatterndisables();
-    } else
-	restore_sticky = 0;
-
-    if (flags & (PM_TAGGED|PM_TAGGED_LOCAL))
-	opts[XTRACE] = 1;
-    else if (oflags & PM_TAGGED_LOCAL)
-	opts[XTRACE] = 0;
-    ooflags = oflags;
-    /*
-     * oflags is static, because we compare it on the next recursive
-     * call.  Hence also we maintain ooflags for restoring the previous
-     * value of oflags after the call.
-     */
-    oflags = flags;
-    opts[PRINTEXITVALUE] = 0;
-    if (doshargs) {
-	LinkNode node;
-
-	node = firstnode(doshargs);
-	pparams = x = (char **) zshcalloc(((sizeof *x) *
-					 (1 + countlinknodes(doshargs))));
-	if (isset(FUNCTIONARGZERO)) {
-	    oargv0 = argzero;
-	    argzero = ztrdup(getdata(node));
-	}
-	/* first node contains name regardless of option */
-	node = node->next;
-	for (; node; node = node->next, x++)
-	    *x = ztrdup(getdata(node));
-    } else {
-	pparams = (char **) zshcalloc(sizeof *pparams);
-	if (isset(FUNCTIONARGZERO)) {
-	    oargv0 = argzero;
-	    argzero = ztrdup(argzero);
+	oflags = flags;
+	opts[PRINTEXITVALUE] = 0;
+	if (doshargs) {
+	    LinkNode node;
+
+	    node = firstnode(doshargs);
+	    pparams = x = (char **) zshcalloc(((sizeof *x) *
+					       (1 + countlinknodes(doshargs))));
+	    if (isset(FUNCTIONARGZERO)) {
+		oargv0 = argzero;
+		argzero = ztrdup(getdata(node));
+	    }
+	    /* first node contains name regardless of option */
+	    node = node->next;
+	    for (; node; node = node->next, x++)
+		*x = ztrdup(getdata(node));
+	} else {
+	    pparams = (char **) zshcalloc(sizeof *pparams);
+	    if (isset(FUNCTIONARGZERO)) {
+		oargv0 = argzero;
+		argzero = ztrdup(argzero);
+	    }
 	}
-    }
 #ifdef MAX_FUNCTION_DEPTH
-    if(++funcdepth > MAX_FUNCTION_DEPTH)
-    {
-        zerr("maximum nested function level reached");
-	goto undoshfunc;
-    }
+	if(++funcdepth > MAX_FUNCTION_DEPTH)
+	    {
+		zerr("maximum nested function level reached");
+		goto undoshfunc;
+	    }
 #endif
-    fstack.name = dupstring(name);
-    /*
-     * The caller is whatever is immediately before on the stack,
-     * unless we're at the top, in which case it's the script
-     * or interactive shell name.
-     */
-    fstack.caller = funcstack ? funcstack->name :
-	dupstring(oargv0 ? oargv0 : argzero);
-    fstack.lineno = lineno;
-    fstack.prev = funcstack;
-    fstack.tp = FS_FUNC;
-    funcstack = &fstack;
-
-    fstack.flineno = shfunc->lineno;
-    fstack.filename = dupstring(shfunc->filename);
-
-    prog = shfunc->funcdef;
-    if (prog->flags & EF_RUN) {
-	Shfunc shf;
+	fstack.name = dupstring(name);
+	/*
+	 * The caller is whatever is immediately before on the stack,
+	 * unless we're at the top, in which case it's the script
+	 * or interactive shell name.
+	 */
+	fstack.caller = funcstack ? funcstack->name :
+	    dupstring(oargv0 ? oargv0 : argzero);
+	fstack.lineno = lineno;
+	fstack.prev = funcstack;
+	fstack.tp = FS_FUNC;
+	funcstack = &fstack;
 
-	prog->flags &= ~EF_RUN;
+	fstack.flineno = shfunc->lineno;
+	fstack.filename = dupstring(shfunc->filename);
 
-	runshfunc(prog, NULL, fstack.name);
+	prog = shfunc->funcdef;
+	if (prog->flags & EF_RUN) {
+	    Shfunc shf;
 
-	if (!(shf = (Shfunc) shfunctab->getnode(shfunctab,
-						(name = fname)))) {
-	    zwarn("%s: function not defined by file", name);
-	    if (noreturnval)
-		errflag |= ERRFLAG_ERROR;
-	    else
-		lastval = 1;
-	    goto doneshfunc;
+	    prog->flags &= ~EF_RUN;
+
+	    runshfunc(prog, NULL, fstack.name);
+
+	    if (!(shf = (Shfunc) shfunctab->getnode(shfunctab,
+						    (name = fname)))) {
+		zwarn("%s: function not defined by file", name);
+		if (noreturnval)
+		    errflag |= ERRFLAG_ERROR;
+		else
+		    lastval = 1;
+		goto doneshfunc;
+	    }
+	    prog = shf->funcdef;
 	}
-	prog = shf->funcdef;
-    }
-    runshfunc(prog, wrappers, fstack.name);
- doneshfunc:
-    funcstack = fstack.prev;
+	runshfunc(prog, wrappers, fstack.name);
+    doneshfunc:
+	funcstack = fstack.prev;
 #ifdef MAX_FUNCTION_DEPTH
- undoshfunc:
-    --funcdepth;
+    undoshfunc:
+	--funcdepth;
 #endif
-    if (retflag) {
-	retflag = 0;
-	breaks = obreaks;
-    }
-    freearray(pparams);
-    if (oargv0) {
-	zsfree(argzero);
-	argzero = oargv0;
-    }
-    pparams = pptab;
-    if (!isset(POSIXBUILTINS)) {
-	zoptind = oldzoptind;
-	optcind = oldoptcind;
-    }
-    scriptname = oldscriptname;
-    oflags = ooflags;
+	if (retflag) {
+	    retflag = 0;
+	    breaks = obreaks;
+	}
+	freearray(pparams);
+	if (oargv0) {
+	    zsfree(argzero);
+	    argzero = oargv0;
+	}
+	pparams = pptab;
+	if (!isset(POSIXBUILTINS)) {
+	    zoptind = oldzoptind;
+	    optcind = oldoptcind;
+	}
+	scriptname = oldscriptname;
+	oflags = ooflags;
 
-    endpatternscope();		/* before restoring old LOCALPATTERNS */
+	endpatternscope();	/* before restoring old LOCALPATTERNS */
 
-    if (restore_sticky) {
-	/*
-	 * If we switched to an emulation environment just for
-	 * this function, we interpret the option and emulation
-	 * switch as being a firewall between environments.
-	 */
-	memcpy(opts, saveopts, sizeof(opts));
-	emulation = saveemulation;
-	sticky = save_sticky;
-    } else if (isset(LOCALOPTIONS)) {
-	/* restore all shell options except PRIVILEGED and RESTRICTED */
-	saveopts[PRIVILEGED] = opts[PRIVILEGED];
-	saveopts[RESTRICTED] = opts[RESTRICTED];
-	memcpy(opts, saveopts, sizeof(opts));
-	emulation = saveemulation;
-    } else {
-	/* just restore a couple. */
-	opts[XTRACE] = saveopts[XTRACE];
-	opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
-	opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
-	opts[LOCALLOOPS] = saveopts[LOCALLOOPS];
-    }
+	if (restore_sticky) {
+	    /*
+	     * If we switched to an emulation environment just for
+	     * this function, we interpret the option and emulation
+	     * switch as being a firewall between environments.
+	     */
+	    memcpy(opts, saveopts, sizeof(opts));
+	    emulation = saveemulation;
+	    sticky = save_sticky;
+	} else if (isset(LOCALOPTIONS)) {
+	    /* restore all shell options except PRIVILEGED and RESTRICTED */
+	    saveopts[PRIVILEGED] = opts[PRIVILEGED];
+	    saveopts[RESTRICTED] = opts[RESTRICTED];
+	    memcpy(opts, saveopts, sizeof(opts));
+	    emulation = saveemulation;
+	} else {
+	    /* just restore a couple. */
+	    opts[XTRACE] = saveopts[XTRACE];
+	    opts[PRINTEXITVALUE] = saveopts[PRINTEXITVALUE];
+	    opts[LOCALOPTIONS] = saveopts[LOCALOPTIONS];
+	    opts[LOCALLOOPS] = saveopts[LOCALLOOPS];
+	}
 
-    if (opts[LOCALLOOPS]) {
-	if (contflag)
-	    zwarn("`continue' active at end of function scope");
-	if (breaks)
-	    zwarn("`break' active at end of function scope");
-	breaks = obreaks;
-	contflag = ocontflag;
-	loops = oloops;
-    }
+	if (opts[LOCALLOOPS]) {
+	    if (contflag)
+		zwarn("`continue' active at end of function scope");
+	    if (breaks)
+		zwarn("`break' active at end of function scope");
+	    breaks = obreaks;
+	    contflag = ocontflag;
+	    loops = oloops;
+	}
 
-    endtrapscope();
+	endtrapscope();
 
-    if (trap_state == TRAP_STATE_PRIMED)
-	trap_return++;
-    ret = lastval;
-    if (noreturnval) {
-	lastval = oldlastval;
-	numpipestats = oldnumpipestats;
-	memcpy(pipestats, oldpipestats, sizeof(int)*numpipestats);
-    }
-    popheap();
+	if (trap_state == TRAP_STATE_PRIMED)
+	    trap_return++;
+	ret = lastval;
+	if (noreturnval) {
+	    lastval = oldlastval;
+	    numpipestats = oldnumpipestats;
+	    memcpy(pipestats, oldpipestats, sizeof(int)*numpipestats);
+	}
+    } OLDHEAPS;
 
     unqueue_signals();