about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--Completion/Core/compdump3
-rw-r--r--Completion/Core/compinit7
-rw-r--r--Doc/Zsh/builtins.yo49
-rw-r--r--Doc/Zsh/func.yo21
-rw-r--r--Src/builtin.c4
-rw-r--r--Src/cond.c2
-rw-r--r--Src/exec.c96
-rw-r--r--Src/glob.c22
-rw-r--r--Src/lex.c6
-rw-r--r--Src/loop.c4
-rw-r--r--Src/math.c7
-rw-r--r--Src/mem.c2
-rw-r--r--Src/parse.c657
-rw-r--r--Src/text.c4
-rw-r--r--Src/utils.c2
-rw-r--r--Src/zsh.h21
16 files changed, 766 insertions, 141 deletions
diff --git a/Completion/Core/compdump b/Completion/Core/compdump
index c577747a1..0d8666f75 100644
--- a/Completion/Core/compdump
+++ b/Completion/Core/compdump
@@ -14,13 +14,14 @@
 # to see if auto-dump should re-dump the dump-file.
 
 emulate -L zsh
+setopt extendedglob
 
 typeset _d_file _d_f _d_bks _d_line _d_als
 
 _d_file=${_comp_dumpfile-${0:h}/compinit.dump}.$HOST.$$
 
 typeset -U _d_files
-_d_files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
+_d_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) )
 
 print "#files: $#_d_files" > $_d_file
 
diff --git a/Completion/Core/compinit b/Completion/Core/compinit
index 5aaaea8fe..a421c2d8d 100644
--- a/Completion/Core/compinit
+++ b/Completion/Core/compinit
@@ -56,6 +56,7 @@
 # default dumpfile) is now the default; to turn off dumping use -D.
 
 emulate -L zsh
+setopt extendedglob
 
 typeset _i_dumpfile _i_files _i_line _i_done _i_dir _i_autodump=1
 typeset _i_tag _i_file _i_addfiles
@@ -419,7 +420,7 @@ zstyle ':completion:*:options' prefix-hidden yes"
 # Now we automatically make the definition files autoloaded.
 
 typeset -U _i_files
-_i_files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
+_i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) )
 if [[ $#_i_files -lt 20 || $_compdir = */Core || -d $_compdir/Core ]]; then
   # Too few files:  we need some more directories,
   # or we need to check that all directories (not just Core) are present.
@@ -438,7 +439,7 @@ if [[ $#_i_files -lt 20 || $_compdir = */Core || -d $_compdir/Core ]]; then
         _i_addfiles[$_i_line]=
     done
     fpath=($fpath $_i_addfiles)
-    _i_files=( ${^~fpath:/.}/_(|*[^~])(N:t) )
+    _i_files=( ${^~fpath:/.}/^([^_]*|*~|*.zwc)(N:t) )
   fi
 fi
 
@@ -468,7 +469,7 @@ fi
 if [[ -z "$_i_done" ]]; then
   for _i_dir in $fpath; do
     [[ $_i_dir = . ]] && continue
-    for _i_file in $_i_dir/_(|*[^~])(N); do
+    for _i_file in $_i_dir/^([^_]*|*~|*.zwc)(N); do
       read -rA _i_line < $_i_file
       _i_tag=$_i_line[1]
       shift _i_line
diff --git a/Doc/Zsh/builtins.yo b/Doc/Zsh/builtins.yo
index a46ec0f92..3491c8591 100644
--- a/Doc/Zsh/builtins.yo
+++ b/Doc/Zsh/builtins.yo
@@ -1283,6 +1283,55 @@ findex(which)
 item(tt(which) [ tt(-wpams) ] var(name) ...)(
 Equivalent to tt(whence -c).
 )
+findex(zcompile)
+cindex(wordcode, creation)
+cindex(compilation)
+xitem(tt(zcompile) [ tt(-U) ] [ tt(-r) | tt(-m) ] var(file) [ var(function) ... ])
+item(tt(zcompile -t) var(file) [ var(name) ... ])(
+This builtin command can be used to create and display files
+containing the wordcode for functions. In the first form, a wordcode
+file is created. If called with only the var(file) argument, the
+wordcode file has the name `var(file)tt(.zwc)' and will be placed in
+the same directory as the var(file). This will make the wordcode file
+be loaded instead of the normal function file when the function is
+autoloaded (see
+ifzman(\
+the section `Autoloading Functions' in zmanref(zshfunc)
+)\
+ifnzman(\
+noderef(Functions)
+)
+for a description of how autoloaded functions are searched).
+
+If there is at least one var(function) argument, the wordcode for all
+these functions will be put in the created wordcode var(file). Such
+files containing the code for multiple functions are intended to be
+used as elements of the tt(FPATH)/tt(fpath) special array.
+
+If the tt(-U) option is given, aliases in the var(function)s will not
+be expanded. If the tt(-r) option is given, the function(s) in the
+file will be read and copied into the shell's memory when they are
+autoloaded. If the tt(-m) option is given instead, the wordcode file
+will be mapped into the shell's memory. This is done in such a way
+that multiple instances of the shell running on the same host will
+share this mapped function. If neither tt(-r) nor tt(-m) are given,
+the tt(zcompile) builtin decides which style is used based on the size 
+of the resulting wordcode file.
+
+In every case, the created file contains two versions of the wordcode, 
+one for big-endian machines and one for small-endian machines. The
+upshot of this is that the wordcode file is machine independent and if 
+it is read or mapped, only one half of the file will really be used
+(and mapped).
+
+In the second form, with the tt(-t) option, an existing wordcode file is
+tested. Without further arguments, the names of the function files
+used for it are listed. The first line tells the version of the shell
+the file was created with and how the file will be used (mapping or
+reading the file). With arguments, only the return value is set
+to zero if all var(name)s name functiones defined in the file and
+non-zero if at least one var(name) is not contained in the wordcode file.
+)
 findex(zmodload)
 cindex(modules, loading)
 cindex(loading modules)
diff --git a/Doc/Zsh/func.yo b/Doc/Zsh/func.yo
index c2462b7dd..43c063f8c 100644
--- a/Doc/Zsh/func.yo
+++ b/Doc/Zsh/func.yo
@@ -33,10 +33,17 @@ cindex(autoloading functions)
 cindex(functions, autoloading)
 A function can be marked as em(undefined) using the tt(autoload) builtin
 (or `tt(functions -u)' or `tt(typeset -fu)').  Such a function has no
-body.  When the function is first executed, the tt(fpath)
-variable will be searched for a file with the same name as the
-function.  The usual alias expansion during reading will be suppressed if
-the tt(autoload) builtin or its equivalent is given the option tt(-U);
+body.  When the function is first executed, each element of the tt(fpath)
+variable will first be searched for a file with the same name as the
+function plus the extension tt(.zwc) and then with the name of the
+function.  The first file will only be used if it was created with the 
+tt(zcompile) builtin command, if it contains the wordcode for the
+function and it is either older than the file with the name of the
+function in the same directory or if such a file does not exist.  The
+usual alias expansion during reading will be suppressed
+if the tt(autoload) builtin or its equivalent is given the option
+tt(-U), for wordcode files this has to be decided when creating the
+file with the tt(-U) option of the tt(zcompile) builtin command;
 this is recommended for the use of functions supplied with the zsh
 distribution.  Thus to define functions for autoloading, a typical sequence
 is:
@@ -44,6 +51,12 @@ is:
 example(fpath=(~/myfuncs $fpath)
 autoload myfunc1 myfunc2 ...)
 
+The elements of the tt(fpath) array may also name wordcode files
+directly. This is mostly useful for wordcode files containing multiple 
+functions, in which case the file is treated like a directory
+containing files for functions and will be searched for the definition 
+of the function.
+
 pindex(KSH_AUTOLOAD, use of)
 If the tt(KSH_AUTOLOAD) option is set, or the file contains only a simple
 definition of the function, the file's contents will be
diff --git a/Src/builtin.c b/Src/builtin.c
index bf29e0d33..60595c3bd 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -124,6 +124,7 @@ static struct builtin builtins[] =
     BUILTIN("where", 0, bin_whence, 0, -1, 0, "pmsw", "ca"),
     BUILTIN("which", 0, bin_whence, 0, -1, 0, "ampsw", "c"),
     BUILTIN("zmodload", 0, bin_zmodload, 0, -1, 0, "ILabcfdipue", NULL),
+    BUILTIN("zcompile", 0, bin_zcompile, 0, -1, 0, "tUmr", NULL),
 };
 
 /****************************************/
@@ -2151,7 +2152,8 @@ mkautofn(Shfunc shf)
     p->shf = shf;
     p->npats = 0;
     p->pats = NULL;
-    p->heap = 0;
+    p->alloc = EA_REAL;
+    p->dump = NULL;
 
     p->prog[0] = WCB_LIST((Z_SYNC | Z_END), 0);
     p->prog[1] = WCB_SUBLIST(WC_SUBLIST_END, 0, 3);
diff --git a/Src/cond.c b/Src/cond.c
index 87c89ea92..654b756a3 100644
--- a/Src/cond.c
+++ b/Src/cond.c
@@ -206,7 +206,7 @@ evalcond(Estate state)
 						  &htok));
 		if (htok)
 		    singsub(&right);
-		save = (!state->prog->heap &&
+		save = (state->prog->alloc != EA_HEAP &&
 			!strcmp(opat, right) && pprog != dummy_patprog2);
 
 		if (!(pprog = patcompile(right, (save ? PAT_ZDUP : PAT_STATIC),
diff --git a/Src/exec.c b/Src/exec.c
index f186a1be2..df42bad32 100644
--- a/Src/exec.c
+++ b/Src/exec.c
@@ -1265,16 +1265,25 @@ mod_export void
 untokenize(char *s)
 {
     if (*s) {
-	char *p = s;
 	int c;
 
 	while ((c = *s++))
 	    if (itok(c)) {
+		char *p = s - 1;
+
 		if (c != Nularg)
 		    *p++ = ztokens[c - Pound];
-	    } else
-		*p++ = c;
-	*p = '\0';
+
+		while ((c = *s++)) {
+		    if (itok(c)) {
+			if (c != Nularg)
+			    *p++ = ztokens[c - Pound];
+		    } else
+			*p++ = c;
+		}
+		*p = '\0';
+		break;
+	    }
     }
 }
 
@@ -3010,7 +3019,7 @@ execfuncdef(Estate state, int do_exec)
 {
     Shfunc shf;
     char *s;
-    int signum, nprg, npats, len, plen, i, htok = 0;
+    int signum, nprg, sbeg, nstrs, npats, len, plen, i, htok = 0;
     Wordcode beg = state->pc, end;
     Eprog prog;
     Patprog *pp;
@@ -3018,26 +3027,40 @@ execfuncdef(Estate state, int do_exec)
 
     end = beg + WC_FUNCDEF_SKIP(state->pc[-1]);
     names = ecgetlist(state, *state->pc++, EC_DUPTOK, &htok);
-    nprg = *state->pc++ - 4;
+    nprg = end - beg;
+    sbeg = *state->pc++;
+    nstrs = *state->pc++;
     npats = *state->pc++;
 
-    plen = (end - state->pc) * sizeof(wordcode);
-    len = plen + (npats * sizeof(Patprog));
+    nprg = (end - state->pc);
+    plen = nprg * sizeof(wordcode);
+    len = plen + (npats * sizeof(Patprog)) + nstrs;
 
     if (htok)
 	execsubst(names);
 
     while ((s = (char *) ugetnode(names))) {
 	prog = (Eprog) zalloc(sizeof(*prog));
-	prog->heap = 0;
-	prog->len = len;
 	prog->npats = npats;
-	prog->pats = pp = (Patprog *) zalloc(len);
-	prog->prog = (Wordcode) (prog->pats + npats);
+	prog->len = len;
+	if (state->prog->dump) {
+	    prog->alloc = EA_MAP;
+	    incrdumpcount(state->prog->dump);
+	    prog->pats = pp = (Patprog *) zalloc(npats * sizeof(Patprog));
+	    prog->prog = state->pc;
+	    prog->strs = state->strs + sbeg;
+	    prog->dump = state->prog->dump;
+	} else {
+	    prog->alloc = EA_REAL;
+	    prog->pats = pp = (Patprog *) zalloc(len);
+	    prog->prog = (Wordcode) (prog->pats + npats);
+	    prog->strs = (char *) (prog->prog + nprg);
+	    prog->dump = NULL;
+	    memcpy(prog->prog, state->pc, plen);
+	    memcpy(prog->strs, state->strs + sbeg, nstrs);
+	}
 	for (i = npats; i--; pp++)
 	    *pp = dummy_patprog1;
-	memcpy(prog->prog, state->pc, plen);
-	prog->strs = (char *) (prog->prog + nprg);
 	prog->shf = NULL;
 
 	shf = (Shfunc) zalloc(sizeof(*shf));
@@ -3150,7 +3173,10 @@ execautofn(Estate state, int do_exec)
 	}
     } else {
 	freeeprog(shf->funcdef);
-	shf->funcdef = zdupeprog(stripkshdef(prog, shf->nam));
+	if (prog->alloc == EA_MAP)
+	    shf->funcdef = stripkshdef(prog, shf->nam);
+	else
+	    shf->funcdef = zdupeprog(stripkshdef(prog, shf->nam));
 	shf->flags &= ~PM_UNDEFINED;
     }
     popheap();
@@ -3180,7 +3206,10 @@ loadautofn(Shfunc shf)
     }
     if (!prog)
 	prog = &dummy_eprog;
-    shf->funcdef = zdupeprog(stripkshdef(prog, shf->nam));
+    if (prog->alloc == EA_MAP)
+	shf->funcdef = stripkshdef(prog, shf->nam);
+    else
+	shf->funcdef = zdupeprog(stripkshdef(prog, shf->nam));
     shf->flags &= ~PM_UNDEFINED;
 
     popheap();
@@ -3339,6 +3368,8 @@ getfpfunc(char *s)
 	    sprintf(buf, "%s/%s", *pp, s);
 	else
 	    strcpy(buf, s);
+	if ((r = try_dump_file(*pp, s, buf)))
+	    return r;
 	unmetafy(buf, NULL);
 	if (!access(buf, R_OK) && (fd = open(buf, O_RDONLY | O_NOCTTY)) != -1) {
 	    if ((len = lseek(fd, 0, 2)) != -1) {
@@ -3372,7 +3403,7 @@ getfpfunc(char *s)
  * contents of that definition.  Otherwise, use the entire file.           */
 
 /**/
-static Eprog
+Eprog
 stripkshdef(Eprog prog, char *name)
 {
     Wordcode pc = prog->prog;
@@ -3399,25 +3430,34 @@ stripkshdef(Eprog prog, char *name)
     {
 	Eprog ret;
 	Wordcode end = pc + WC_FUNCDEF_SKIP(code);
-	int nprg = pc[2] - 4;
-	int npats = pc[3];
-	int plen, len, i;
+	int sbeg = pc[2], nstrs = pc[3], nprg, npats = pc[4], plen, len, i;
 	Patprog *pp;
 
-	pc += 4;
+	pc += 5;
 
-	plen = (end - pc) * sizeof(wordcode);
-	len = plen + (npats * sizeof(Patprog));
+	nprg = end - pc;
+	plen = nprg * sizeof(wordcode);
+	len = plen + (npats * sizeof(Patprog)) + nstrs;
 
-	ret = (Eprog) zhalloc(sizeof(*ret));
-	ret->heap = 1;
+	if (prog->alloc == EA_MAP) {
+	    ret = prog;
+	    free(prog->pats);
+	    ret->pats = pp = (Patprog *) zalloc(npats * sizeof(Patprog));
+	    ret->prog = pc;
+	    ret->strs = prog->strs + sbeg;
+	} else {
+	    ret = (Eprog) zhalloc(sizeof(*ret));
+	    ret->alloc = EA_HEAP;
+	    ret->pats = pp = (Patprog *) zhalloc(len);
+	    ret->prog = (Wordcode) (ret->pats + npats);
+	    memcpy(ret->prog, pc, plen);
+	    memcpy(ret->strs, prog->strs + sbeg, nstrs);
+	    ret->dump = NULL;
+	}
 	ret->len = len;
 	ret->npats = npats;
-	ret->pats = pp = (Patprog *) zhalloc(len);
-	ret->prog = (Wordcode) (ret->pats + npats);
 	for (i = npats; i--; pp++)
 	    *pp = dummy_patprog1;
-	memcpy(ret->prog, pc, plen);
 	ret->strs = (char *) (ret->prog + nprg);
 	ret->shf = NULL;
 
diff --git a/Src/glob.c b/Src/glob.c
index 05bfbbafb..c457e97ac 100644
--- a/Src/glob.c
+++ b/Src/glob.c
@@ -2327,16 +2327,22 @@ mod_export void
 remnulargs(char *s)
 {
     if (*s) {
-	char *t = s, *p = s, c;
+	char *o = s, c;
 
 	while ((c = *s++))
-	    if (!INULL(c))
-		*p++ = c;
-	*p = '\0';
-	if (!*t) {
-	    t[0] = Nularg;
-	    t[1] = '\0';
-	}
+	    if (INULL(c)) {
+		char *t = s - 1;
+
+		while ((c = *s++))
+		    if (!INULL(c))
+			*t++ = c;
+		*t = '\0';
+		if (!*o) {
+		    o[0] = Nularg;
+		    o[1] = '\0';
+		}
+		break;
+	    }
     }
 }
 
diff --git a/Src/lex.c b/Src/lex.c
index 1031b57e2..333aa403b 100644
--- a/Src/lex.c
+++ b/Src/lex.c
@@ -194,7 +194,7 @@ struct lexstack {
     int eclen, ecused, ecfree, ecnpats;
     Wordcode ecbuf;
     Eccstr ecstrs;
-    int ecsoffs;
+    int ecsoffs, ecssub, ecnfunc;
 
     unsigned char *cstack;
     int csp;
@@ -255,6 +255,8 @@ lexsave(void)
     ls->ecbuf = ecbuf;
     ls->ecstrs = ecstrs;
     ls->ecsoffs = ecsoffs;
+    ls->ecssub = ecssub;
+    ls->ecnfunc = ecnfunc;
     cmdsp = 0;
     inredir = 0;
     hdocs = NULL;
@@ -314,6 +316,8 @@ lexrestore(void)
     ecbuf = lstack->ecbuf;
     ecstrs = lstack->ecstrs;
     ecsoffs = lstack->ecsoffs;
+    ecssub = lstack->ecssub;
+    ecnfunc = lstack->ecnfunc;
     hlinesz = lstack->hlinesz;
     errflag = 0;
 
diff --git a/Src/loop.c b/Src/loop.c
index 2459d65b8..b1edb22c4 100644
--- a/Src/loop.c
+++ b/Src/loop.c
@@ -524,7 +524,7 @@ execcase(Estate state, int do_exec)
 
 	    opat = pat = ecgetstr(state, EC_DUP, NULL);
 	    singsub(&pat);
-	    save = (!state->prog->heap &&
+	    save = (state->prog->alloc != EA_HEAP &&
 		    !strcmp(pat, opat) && *spprog != dummy_patprog2);
 
 	    pat2 = dupstring(pat);
@@ -548,7 +548,7 @@ execcase(Estate state, int do_exec)
 						state->pc - 2, &htok));
 		if (htok)
 		    singsub(&pat);
-		save = (!state->prog->heap &&
+		save = (state->prog->alloc != EA_HEAP &&
 			!strcmp(pat, opat) && *spprog != dummy_patprog2);
 	    }
 	    if (!(pprog = patcompile(pat, (save ? PAT_ZDUP : PAT_STATIC),
diff --git a/Src/math.c b/Src/math.c
index a3609d429..ce685e2db 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -396,7 +396,7 @@ zzlex(void)
 	    }
 	    if (iident(*ptr)) {
 		int func = 0;
-		char *p, q;
+		char *p;
 
 		p = ptr;
 		while (iident(*++ptr));
@@ -413,10 +413,7 @@ zzlex(void)
 			    ptr++;
 		    }
 		}
-		q = *ptr;
-		*ptr = '\0';
-		yylval = dupstring(p);
-		*ptr = q;
+		yylval = dupstrpfx(p, ptr - p);
 		return (func ? FUNC : (cct ? CID : ID));
 	    }
 	    else if (cct) {
diff --git a/Src/mem.c b/Src/mem.c
index 1e627cd99..29bd213f4 100644
--- a/Src/mem.c
+++ b/Src/mem.c
@@ -1272,7 +1272,7 @@ bin_mem(char *name, char **argv, char *ops, int func)
 	printf("blocks is shown. For otherwise used blocks the first few\n");
 	printf("bytes are shown as an ASCII dump.\n");
     }
-    printf("\nblock list:\nnum\ttnum\taddr\tlen\tstate\tcum\n");
+    printf("\nblock list:\nnum\ttnum\taddr\t\tlen\tstate\tcum\n");
     for (m = m_l, mf = m_free, ii = fi = ui = 1; ((char *)m) < m_high;
 	 m = (struct m_hdr *)(((char *)m) + M_ISIZE + m->len), ii++) {
 	for (j = 0, ms = NULL; j < M_NSMALL && !ms; j++)
diff --git a/Src/parse.c b/Src/parse.c
index df7671c5d..0b11668c2 100644
--- a/Src/parse.c
+++ b/Src/parse.c
@@ -131,10 +131,11 @@ struct heredocs *hdocs;
  *     - if (type == PIPE), followed by pipe
  *
  *   WC_FUNCDEF
- *     - data contains offset to after body-strings
+ *     - data contains offset to after body
  *     - followed by number of names
  *     - followed by names
- *     - followed by number of codes for body
+ *     - followed by offset to first string
+ *     - followed by length of string table
  *     - followed by number of patterns for body
  *     - follwoed by codes for body
  *     - followed by strings for body
@@ -230,28 +231,7 @@ Wordcode ecbuf;
 /**/
 Eccstr ecstrs;
 /**/
-int ecsoffs;
-
-/* Make at least n bytes free (aligned to sizeof(wordcode)). */
-
-static int
-ecspace(int n)
-{
-    n = (n + sizeof(wordcode) - 1) / sizeof(wordcode);
-
-    if (ecfree < n) {
-	int a = (n > 256 ? n : 256);
-
-	ecbuf = (Wordcode) hrealloc((char *) ecbuf, eclen * sizeof(wordcode),
-				    (eclen + a) * sizeof(wordcode));
-	eclen += a;
-	ecfree += a;
-    }
-    ecused += n;
-    ecfree -= n;
-
-    return ecused - 1;
-}
+int ecsoffs, ecssub, ecnfunc;
 
 /* Insert n free code-slots at position p. */
 
@@ -323,7 +303,7 @@ ecstrcode(char *s)
 	Eccstr p, q = NULL;
 
 	for (p = ecstrs; p; q = p, p = p->next)
-	    if (!strcmp(s, p->str))
+	    if (p->nfunc == ecnfunc && !strcmp(s, p->str))
 		return p->offs;
 
 	p = (Eccstr) zhalloc(sizeof(*p));
@@ -332,8 +312,9 @@ ecstrcode(char *s)
 	    q->next = p;
 	else
 	    ecstrs = p;
-	p->offs = (ecsoffs << 2) | (t ? 1 : 0);
+	p->offs = ((ecsoffs - ecssub) << 2) | (t ? 1 : 0);
 	p->str = s;
+	p->nfunc = ecnfunc;
 	ecsoffs += l;
 
 	return p->offs;
@@ -370,6 +351,8 @@ init_parse(void)
     ecused = 0;
     ecstrs = NULL;
     ecsoffs = ecnpats = 0;
+    ecssub = 0;
+    ecnfunc = 0;
 }
 
 /* Build eprog. */
@@ -393,7 +376,8 @@ bld_eprog(void)
     ret->prog = (Wordcode) (ret->pats + ecnpats);
     ret->strs = (char *) (ret->prog + ecused);
     ret->shf = NULL;
-    ret->heap = 1;
+    ret->alloc = EA_HEAP;
+    ret->dump = NULL;
     for (l = 0; l < ecnpats; l++)
 	ret->pats[l] = dummy_patprog1;
     memcpy(ret->prog, ecbuf, ecused * sizeof(wordcode));
@@ -1288,8 +1272,8 @@ par_subsh(int *complex)
 static void
 par_funcdef(void)
 {
-    int oecused = ecused, oldlineno = lineno, num = 0, sbeg, onp, p, c = 0;
-    Eccstr ostrs;
+    int oecused = ecused, oldlineno = lineno, num = 0, onp, p, c = 0;
+    int so, oecssub = ecssub;
 
     lineno = 0;
     nocorrect = 1;
@@ -1311,6 +1295,7 @@ par_funcdef(void)
     }
     ecadd(0);
     ecadd(0);
+    ecadd(0);
 
     nocorrect = 0;
     if (tok == INOUTPAR)
@@ -1318,10 +1303,8 @@ par_funcdef(void)
     while (tok == SEPER)
 	yylex();
 
-    sbeg = ecsoffs;
-    ecsoffs = 0;
-    ostrs = ecstrs;
-    ecstrs = NULL;
+    ecnfunc++;
+    ecssub = so = ecsoffs;
     onp = ecnpats;
     ecnpats = 0;
 
@@ -1330,43 +1313,28 @@ par_funcdef(void)
 	par_list(&c);
 	if (tok != OUTBRACE) {
 	    lineno += oldlineno;
-	    ecsoffs = sbeg;
-	    ecstrs = ostrs;
 	    ecnpats = onp;
+	    ecssub = oecssub;
 	    YYERRORV(oecused);
 	}
 	yylex();
     } else if (unset(SHORTLOOPS)) {
 	lineno += oldlineno;
-	ecsoffs = sbeg;
-	ecstrs = ostrs;
 	ecnpats = onp;
+	ecssub = oecssub;
 	YYERRORV(oecused);
     } else
 	par_list1(&c);
 
     ecadd(WCB_END());
-    ecbuf[p + num + 2] = ecused - num - p;
-    ecbuf[p + num + 3] = ecnpats;
+    ecbuf[p + num + 2] = so - oecssub;
+    ecbuf[p + num + 3] = ecsoffs - so;
+    ecbuf[p + num + 4] = ecnpats;
     ecbuf[p + 1] = num;
 
-    if (ecsoffs) {
-	int beg = ecused, l;
-	Eccstr sp;
-	char *sq;
-
-	ecspace(ecsoffs);
-
-	for (sp = ecstrs, sq = (char *) (ecbuf + beg); sp;
-	     sp = sp->next, sq += l) {
-	    l = strlen(sp->str) + 1;
-	    memcpy(sq, sp->str, l);
-	}
-    }
     lineno += oldlineno;
-    ecsoffs = sbeg;
-    ecstrs = ostrs;
     ecnpats = onp;
+    ecssub = oecssub;
 
     ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p);
 }
@@ -1481,8 +1449,7 @@ par_simple(int *complex, int nr)
 	    p += 3;		/* 3 codes per redirection */
 	    sr++;
 	} else if (tok == INOUTPAR) {
-	    int oldlineno = lineno, sbeg, onp;
-	    Eccstr ostrs;
+	    int oldlineno = lineno, onp, so, oecssub = ecssub;
 
 	    *complex = c;
 	    lineno = 0;
@@ -1496,11 +1463,10 @@ par_simple(int *complex, int nr)
 	    ecbuf[p + 1] = argc;
 	    ecadd(0);
 	    ecadd(0);
+	    ecadd(0);
 
-	    sbeg = ecsoffs;
-	    ecsoffs = 0;
-	    ostrs = ecstrs;
-	    ecstrs = NULL;
+	    ecnfunc++;
+	    ecssub = so = ecsoffs;
 	    onp = ecnpats;
 	    ecnpats = 0;
 
@@ -1512,9 +1478,8 @@ par_simple(int *complex, int nr)
 		if (tok != OUTBRACE) {
 		    cmdpop();
 		    lineno += oldlineno;
-		    ecsoffs = sbeg;
-		    ecstrs = ostrs;
 		    ecnpats = onp;
+		    ecssub = oecssub;
 		    YYERROR(oecused);
 		}
 		yylex();
@@ -1532,26 +1497,13 @@ par_simple(int *complex, int nr)
 	    cmdpop();
 
 	    ecadd(WCB_END());
-	    ecbuf[p + argc + 2] = ecused - argc - p;
-	    ecbuf[p + argc + 3] = ecnpats;
-
-	    if (ecsoffs) {
-		int beg = ecused, l;
-		Eccstr sp;
-		char *sq;
+	    ecbuf[p + argc + 2] = so - oecssub;
+	    ecbuf[p + argc + 3] = ecsoffs - so;
+	    ecbuf[p + argc + 4] = ecnpats;
 
-		ecspace(ecsoffs);
-
-		for (sp = ecstrs, sq = (char *) (ecbuf + beg); sp;
-		     sp = sp->next, sq += l) {
-		    l = strlen(sp->str) + 1;
-		    memcpy(sq, sp->str, l);
-		}
-	    }
 	    lineno += oldlineno;
-	    ecsoffs = sbeg;
-	    ecstrs = ostrs;
 	    ecnpats = onp;
+	    ecssub = oecssub;
 
 	    ecbuf[p] = WCB_FUNCDEF(ecused - 1 - p);
 
@@ -2020,7 +1972,8 @@ zdupeprog(Eprog p)
 	return p;
 
     r = (Eprog) zalloc(sizeof(*r));
-    r->heap = 0;
+    r->alloc = EA_REAL;
+    r->dump = NULL;
     r->len = p->len;
     r->npats = p->npats;
     pp = r->pats = (Patprog *) zcalloc(r->len);
@@ -2056,7 +2009,11 @@ freeeprogs(void)
     while ((p = (Eprog) getlinknode(eprog_free))) {
 	for (i = p->npats, pp = p->pats; i--; pp++)
 	    freepatprog(*pp);
-	zfree(p->pats, p->len);
+	if (p->dump) {
+	    decrdumpcount(p->dump);
+	    zfree(p->pats, p->npats * sizeof(Patprog));
+	} else
+	    zfree(p->pats, p->len);
 	zfree(p, sizeof(*p));
     }
 }
@@ -2083,6 +2040,17 @@ ecgetstr(Estate s, int dup, int *tok)
     }
     if (tok)
 	*tok = (c & 1);
+
+    /*** Since function dump files are mapped read-only, avoiding to
+     *   to duplicate strings when they don't contain tokens may fail
+     *   when one of the many utility functions happens to write to
+     *   one of the strings (without really modifying it).
+     *   If that happens to you and you don't feel like debugging it,
+     *   just change the line below to:
+     *
+     *     return (dup ? dupstring(r) : r);
+     */
+
     return ((dup == EC_DUP || (dup && (c & 1)))  ? dupstring(r) : r);
 }
 
@@ -2193,3 +2161,530 @@ init_eprog(void)
 
     eprog_free = znewlinklist();
 }
+
+/* Code for function dump files.
+ *
+ * Dump files consist of a header and the function bodies (the wordcode
+ * plus the string table) and that twice: once for the byte-order of the
+ * host the file was created on and once for the other byte-order. The
+ * header describes where the beginning of the `other' version is and it
+ * is up to the shell reading the file to decide which version it needs.
+ * This is done by checking if the first word is FD_MAGIC (then the 
+ * shell reading the file has the same byte order as the one that created
+ * the file) or if it is FD_OMAGIC, then the `other' version has to be
+ * read.
+ * The header is the magic number, a word containing the flags (if the
+ * file should be mapped or read and if this header is the `other' one),
+ * the version string in a field of 40 characters and the descriptions
+ * for the functions in the dump file.
+ * Each description consists of a struct fdhead followed by the name,
+ * aligned to sizeof(wordcode) (i.e. 4 bytes).
+ */
+
+#include "version.h"
+
+#define FD_EXT ".zwc"
+#define FD_MINMAP 4096
+
+#define FD_PRELEN 12
+#define FD_MAGIC  0x01020304
+#define FD_OMAGIC 0x04030201
+
+#define FDF_MAP   1
+#define FDF_OTHER 2
+
+typedef struct fdhead *FDHead;
+
+struct fdhead {
+    wordcode start;		/* offset to function definition */
+    wordcode len;		/* length of wordcode/strings */
+    wordcode npats;		/* number of patterns needed */
+    wordcode strs;		/* offset to strings */
+    wordcode hlen;		/* header length (incl. name) */
+    wordcode tail;		/* offset to name tail */
+};
+
+#define fdheaderlen(f) (((Wordcode) (f))[FD_PRELEN])
+
+#define fdmagic(f)       (((Wordcode) (f))[0])
+#define fdbyte(f, i)     ((wordcode) (((unsigned char *) (((Wordcode) (f)) + 1))[i]))
+#define fdflags(f)       fdbyte(f, 0)
+#define fdother(f)       (fdbyte(f, 1) + (fdbyte(f, 2) << 8) + (fdbyte(f, 3) << 16))
+#define fdsetother(f, o) \
+    do { \
+        fdbyte(f, 1) = (o & 0xff); \
+        fdbyte(f, 2) = (o >> 8) & 0xff; \
+        fdbyte(f, 3) = (o >> 16) & 0xff; \
+    } while (0)
+#define fdversion(f)     ((char *) ((f) + 2))
+
+#define firstfdhead(f) ((FDHead) (((Wordcode) (f)) + FD_PRELEN))
+#define nextfdhead(f)  ((FDHead) (((Wordcode) (f)) + (f)->hlen))
+
+#define fdname(f)      ((char *) (((FDHead) (f)) + 1))
+
+/* Try to find the description for the given function name. */
+
+static FDHead
+dump_find_func(Wordcode h, char *name)
+{
+    FDHead n, e = (FDHead) (h + fdheaderlen(h));
+
+    for (n = firstfdhead(h); n < e; n = nextfdhead(n))
+	if (!strcmp(name, fdname(n) + n->tail))
+	    return n;
+
+    return NULL;
+}
+
+/**/
+int
+bin_zcompile(char *nam, char **args, char *ops, int func)
+{
+    int map;
+
+    if (ops['t']) {
+	Wordcode f;
+
+	if (!*args) {
+	    zerrnam(nam, "too few arguments", NULL, 0);
+	    return 1;
+	}
+	if (!(f = load_dump_header(*args))) {
+	    zerrnam(nam, "invalid dump file: %s", *args, 0);
+	    return 1;
+	}
+	if (args[1]) {
+	    for (args++; *args; args++)
+		if (!dump_find_func(f, *args))
+		    return 1;
+	    return 0;
+	} else {
+	    FDHead h, e = (FDHead) (f + fdheaderlen(f));
+
+	    printf("function dump file (%s) for zsh-%s\n",
+		   ((fdflags(f) & FDF_MAP) ? "mapped" : "read"), fdversion(f));
+	    for (h = firstfdhead(f); h < e; h = nextfdhead(h))
+		printf("%s\n", fdname(h));
+	    return 0;
+	}
+    }
+    if (!*args) {
+	zerrnam(nam, "too few arguments", NULL, 0);
+	return 1;
+    }
+    map = (ops['m'] ? 2 : (ops['r'] ? 0 : 1));
+
+    if (!args[1])
+	return build_dump(nam, dyncat(*args, FD_EXT), args, ops['U'], map);
+
+    return build_dump(nam, *args, args + 1, ops['U'], map);
+}
+
+/* Load the header of a dump file. Returns NULL if the file isn't a
+ * valid dump file. */
+
+/**/
+static Wordcode
+load_dump_header(char *name)
+{
+    int fd;
+    wordcode buf[FD_PRELEN + 1];
+
+    if ((fd = open(name, O_RDONLY)) < 0)
+	return NULL;
+
+    if (read(fd, buf, (FD_PRELEN + 1) * sizeof(wordcode)) !=
+	((FD_PRELEN + 1) * sizeof(wordcode)) ||
+	strcmp(ZSH_VERSION, fdversion(buf))) {
+	close(fd);
+	return NULL;
+    } else {
+	int len;
+	Wordcode head;
+
+	if (fdmagic(buf) == FD_MAGIC) {
+	    len = fdheaderlen(buf) * sizeof(wordcode);
+	    head = (Wordcode) zhalloc(len);
+	}
+	else {
+	    int o = fdother(buf);
+
+	    if (lseek(fd, o, 0) == -1 ||
+		read(fd, buf, (FD_PRELEN + 1) * sizeof(wordcode)) !=
+		((FD_PRELEN + 1) * sizeof(wordcode))) {
+		close(fd);
+		return NULL;
+	    }
+	    len = fdheaderlen(buf) * sizeof(wordcode);
+	    head = (Wordcode) zhalloc(len);
+	}
+	memcpy(head, buf, (FD_PRELEN + 1) * sizeof(wordcode));
+
+	if (read(fd, head + (FD_PRELEN + 1),
+		 len - ((FD_PRELEN + 1) * sizeof(wordcode))) !=
+	    len - ((FD_PRELEN + 1) * sizeof(wordcode))) {
+	    close(fd);
+	    return NULL;
+	}
+	close(fd);
+	return head;
+    }
+}
+
+/* Swap the bytes in a wordcode. */
+
+static void
+fdswap(Wordcode p, int n)
+{
+    wordcode c;
+
+    for (; n--; p++) {
+	c = *p;
+	*p = (((c & 0xff) << 24) |
+	      ((c & 0xff00) << 8) |
+	      ((c & 0xff0000) >> 8) |
+	      ((c & 0xff000000) >> 24));
+    }
+}
+
+/* Write a dump file. */
+
+/**/
+static int
+build_dump(char *nam, char *dump, char **files, int ali, int map)
+{
+    int dfd, fd, hlen, tlen, flen, tmp, ona = noaliases, other = 0, ohlen;
+    LinkList progs;
+    LinkNode node;
+    struct fdhead head;
+    wordcode pre[FD_PRELEN];
+    char *file, **ofiles = files, **oofiles = files, *name, *tail;
+    Eprog prog;
+
+    if ((dfd = open(dump, O_WRONLY|O_CREAT, 0600)) < 0) {
+	zerrnam(nam, "can't write dump file: %s", dump, 0);
+	return 1;
+    }
+    progs = newlinklist();
+    noaliases = ali;
+
+    for (hlen = FD_PRELEN, tlen = 0; *files; files++) {
+	if ((fd = open(*files, O_RDONLY)) < 0 ||
+	    (flen = lseek(fd, 0, 2)) == -1) {
+	    if (fd >= 0)
+		close(fd);
+	    close(dfd);
+	    zerrnam(nam, "can't open file: %s", *files, 0);
+	    noaliases = ona;
+	    return 1;
+	}
+	file = (char *) zalloc(flen + 1);
+	file[flen] = '\0';
+	lseek(fd, 0, 0);
+	if (read(fd, file, flen) != flen) {
+	    close(fd);
+	    close(dfd);
+	    zfree(file, flen);
+	    zerrnam(nam, "can't read file: %s", *files, 0);
+	    noaliases = ona;
+	    return 1;
+	}
+	close(fd);
+	file = metafy(file, flen, META_REALLOC);
+
+	if (!(prog = parse_string(file, 1)) || errflag) {
+	    close(dfd);
+	    zfree(file, flen);
+	    zerrnam(nam, "can't read file: %s", *files, 0);
+	    noaliases = ona;
+	    return 1;
+	}
+	zfree(file, flen);
+
+	addlinknode(progs, prog);
+
+	flen = (strlen(*files) + sizeof(wordcode)) / sizeof(wordcode);
+	hlen += (sizeof(head) / sizeof(wordcode)) + flen;
+
+	tlen += (prog->len - (prog->npats * sizeof(Patprog)) +
+		 sizeof(wordcode) - 1) / sizeof(wordcode);
+    }
+    noaliases = ona;
+
+    tlen = (tlen + hlen) * sizeof(wordcode);
+    if (map == 1)
+	map = (tlen >= FD_MINMAP);
+
+    for (ohlen = hlen; ; hlen = ohlen) {
+	fdmagic(pre) = (other ? FD_OMAGIC : FD_MAGIC);
+	fdflags(pre) = (map ? FDF_MAP : 0) | other;
+	fdsetother(pre, tlen);
+	strcpy(fdversion(pre), ZSH_VERSION);
+	write(dfd, pre, FD_PRELEN * sizeof(wordcode));
+
+	for (node = firstnode(progs), ofiles = oofiles; node;
+	     ofiles++, incnode(node)) {
+	    prog = (Eprog) getdata(node);
+	    head.start = hlen;
+	    hlen += (prog->len - (prog->npats * sizeof(Patprog)) +
+		     sizeof(wordcode) - 1) / sizeof(wordcode);
+	    head.len = prog->len - (prog->npats * sizeof(Patprog));
+	    head.npats = prog->npats;
+	    head.strs = prog->strs - ((char *) prog->prog);
+	    head.hlen = (sizeof(struct fdhead) / sizeof(wordcode)) +
+		(strlen(*ofiles) + sizeof(wordcode)) / sizeof(wordcode);
+	    for (name = tail = *ofiles; *name; name++)
+		if (*name == '/')
+		    tail = name + 1;
+	    head.tail = tail - *ofiles;
+	    if (other)
+		fdswap((Wordcode) &head, sizeof(head) / sizeof(wordcode));
+	    write(dfd, &head, sizeof(head));
+	    tmp = strlen(*ofiles) + 1;
+	    write(dfd, *ofiles, tmp);
+	    if ((tmp &= (sizeof(wordcode) - 1)))
+		write(dfd, &head, sizeof(wordcode) - tmp);
+	}
+	for (node = firstnode(progs); node; incnode(node)) {
+	    prog = (Eprog) getdata(node);
+	    tmp = (prog->len - (prog->npats * sizeof(Patprog)) +
+		   sizeof(wordcode) - 1) / sizeof(wordcode);
+	    if (other)
+		fdswap(prog->prog, (((Wordcode) prog->strs) - prog->prog));
+	    write(dfd, prog->prog, tmp * sizeof(wordcode));
+	}
+	if (other)
+	    break;
+	other = FDF_OTHER;
+    }
+    close(dfd);
+    return 0;
+}
+
+#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP) && defined(HAVE_MUNMAP)
+
+#include <sys/mman.h>
+
+#if defined(MAP_SHARED) && defined(PROT_READ)
+
+#define USE_MMAP 1
+
+#endif
+#endif
+
+#ifdef USE_MMAP
+
+/* List of dump files mapped. */
+
+static FuncDump dumps;
+
+/* Load a dump file (i.e. map it). */
+
+static void
+load_dump_file(char *dump, int other, int len)
+{
+    FuncDump d;
+    Wordcode addr;
+    int fd, off;
+
+    if (other) {
+	static size_t pgsz = 0;
+
+	if (!pgsz) {
+
+#ifdef _SC_PAGESIZE
+	    pgsz = sysconf(_SC_PAGESIZE);     /* SVR4 */
+#else
+# ifdef _SC_PAGE_SIZE
+	    pgsz = sysconf(_SC_PAGE_SIZE);    /* HPUX */
+# else
+	    pgsz = getpagesize();
+# endif
+#endif
+
+	    pgsz--;
+	}
+	off = len & ~pgsz;
+    } else
+	off = 0;
+
+    if ((fd = open(dump, O_RDONLY)) < 0)
+	return;
+
+    fd = movefd(fd);
+
+    if ((addr = (Wordcode) mmap(NULL, len, PROT_READ, MAP_SHARED, fd, off)) ==
+	((Wordcode) -1)) {
+	close(fd);
+	return;
+    }
+    d = (FuncDump) zalloc(sizeof(*d));
+    d->next = dumps;
+    dumps = d;
+    d->name = ztrdup(dump);
+    d->fd = fd;
+    d->map = addr + (other ? (len - off) / sizeof(wordcode) : 0);
+    d->addr = addr;
+    d->len = len;
+    d->count = 0;
+}
+
+/* See if `dump' is the name of a dump file and it has the definition
+ * for the function `name'. If so, return an eprog for it. */
+
+/**/
+Eprog
+try_dump_file(char *dump, char *name, char *func)
+{
+    int isrec = 0;
+    Wordcode d;
+    FDHead h;
+    FuncDump f;
+
+ rec:
+
+    d = NULL;
+    for (f = dumps; f; f = f->next)
+	if (!strcmp(dump, f->name)) {
+	    d = f->map;
+	    break;
+	}
+    if (!f && (isrec || !(d = load_dump_header(dump)))) {
+	if (!isrec) {
+	    struct stat stc, stn;
+	    char *p = (char *) zhalloc(strlen(dump) + strlen(name) +
+				       strlen(FD_EXT) + 2);
+
+	    sprintf(p, "%s/%s%s", dump, name, FD_EXT);
+
+	    /* Ignore the dump file if it is older than the normal one. */
+	    if (stat(p, &stc) || stat(func, &stn) || stn.st_mtime > stc.st_mtime)
+		return NULL;
+
+	    if (!(d = load_dump_header(dump = p)))
+		return NULL;
+
+	} else
+	    return NULL;
+    }
+    if ((h = dump_find_func(d, name))) {
+	/* Found the name. If the file is already mapped, return the eprog,
+	 * otherwise map it and just go up. */
+	if (f) {
+	    Eprog prog = (Eprog) zalloc(sizeof(*prog));
+	    Patprog *pp;
+	    int np;
+
+	    prog->alloc = EA_MAP;
+	    prog->len = h->len;
+	    prog->npats = np = h->npats;
+	    prog->pats = pp = (Patprog *) zalloc(np * sizeof(Patprog));
+	    prog->prog = f->map + h->start;
+	    prog->strs = ((char *) prog->prog) + h->strs;
+	    prog->shf = NULL;
+	    prog->dump = f;
+
+	    incrdumpcount(f);
+
+	    while (np--)
+		*pp++ = dummy_patprog1;
+
+	    return prog;
+	} else if (fdflags(d) & FDF_MAP) {
+	    load_dump_file(dump, (fdflags(d) & FDF_OTHER), fdother(d));
+	    isrec = 1;
+	    goto rec;
+	} else {
+	    Eprog prog;
+	    Patprog *pp;
+	    int np, fd, po = h->npats * sizeof(Patprog);
+
+	    if ((fd = open(dump, O_RDONLY)) < 0 ||
+		lseek(fd, ((h->start * sizeof(wordcode)) +
+			   ((fdflags(d) & FDF_OTHER) ? fdother(d) : 0)), 0) < 0) {
+		if (fd >= 0)
+		    close(fd);
+		return NULL;
+	    }
+	    d = (Wordcode) zalloc(h->len + po);
+
+	    if (read(fd, ((char *) d) + po, h->len) != h->len) {
+		close(fd);
+		zfree(d, h->len);
+
+		return NULL;
+	    }
+	    close(fd);
+
+	    prog = (Eprog) zalloc(sizeof(*prog));
+
+	    prog->alloc = EA_MAP;
+	    prog->len = h->len + po;
+	    prog->npats = np = h->npats;
+	    prog->pats = pp = (Patprog *) d;
+	    prog->prog = (Wordcode) (((char *) d) + po);
+	    prog->strs = ((char *) prog->prog) + h->strs;
+	    prog->shf = NULL;
+	    prog->dump = f;
+
+	    while (np--)
+		*pp++ = dummy_patprog1;
+
+	    return prog;
+	}
+    }
+    return NULL;
+}
+
+/* Increment the reference counter for a dump file. */
+
+/**/
+void
+incrdumpcount(FuncDump f)
+{
+    f->count++;
+}
+
+/* Decrement the reference counter for a dump file. If zero, unmap the file. */
+
+/**/
+void
+decrdumpcount(FuncDump f)
+{
+    f->count--;
+    if (!f->count) {
+	FuncDump p, q;
+
+	for (q = NULL, p = dumps; p && p != f; q = p, p = p->next);
+	if (p) {
+	    if (q)
+		q->next = p->next;
+	    else
+		dumps = p->next;
+	    munmap((void *) f->addr, f->len);
+	    zclose(f->fd);
+	    zfree(f, sizeof(*f));
+	}
+    }
+}
+
+#else
+
+Eprog
+try_dump_file(char *dump, char *name, char *func)
+{
+    return NULL;
+}
+
+void
+incrdumpcount(FuncDump f)
+{
+}
+
+void
+decrdumpcount(FuncDump f)
+{
+}
+
+#endif
diff --git a/Src/text.c b/Src/text.c
index 235064efc..ab052b22a 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -378,8 +378,8 @@ gettext2(Estate state)
 		    n = tpush(code, 1);
 		    n->u._funcdef.strs = state->strs;
 		    n->u._funcdef.end = end;
-		    state->strs = (char *) (p + (*state->pc));
-		    state->pc += 2;
+		    state->strs += *state->pc;
+		    state->pc += 3;
 		}
 	    } else {
 		state->strs = s->u._funcdef.strs;
diff --git a/Src/utils.c b/Src/utils.c
index 6d91200a0..db404ec26 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -1704,7 +1704,7 @@ spacesplit(char *s, int allownull, int heap)
 {
     char *t, **ret, **ptr;
     int l = sizeof(*ret) * (wordcount(s, NULL, -!allownull) + 1);
-    char *(*dup)(char *) = (heap ? dupstring : ztrdup);
+    char *(*dup)(const char *) = (heap ? dupstring : ztrdup);
 
     ptr = ret = (heap ? (char **) hcalloc(l) : (char **) zcalloc(l));
 
diff --git a/Src/zsh.h b/Src/zsh.h
index 332bae9fd..77de1ec61 100644
--- a/Src/zsh.h
+++ b/Src/zsh.h
@@ -476,24 +476,40 @@ struct value {
 #define MAX_ARRLEN    262144
 
 /********************************************/
-/* Defintions for byte code                 */
+/* Defintions for word code                 */
 /********************************************/
 
 typedef unsigned int wordcode;
 typedef wordcode *Wordcode;
 
+typedef struct funcdump *FuncDump;
 typedef struct eprog *Eprog;
 
+struct funcdump {
+    FuncDump next;		/* next in list */
+    char *name;			/* path name */
+    int fd;			/* file descriptor */
+    Wordcode map;		/* pointer to header */
+    Wordcode addr;		/* mapped region */
+    int len;			/* length */
+    int count;			/* reference count */
+};
+
 struct eprog {
-    int heap;			/* != 0 if in heap memory */
+    int alloc;			/* EA_* below */
     int len;			/* total block length */
     int npats;			/* Patprog cache size */
     Patprog *pats;		/* the memory block, the patterns */
     Wordcode prog;		/* memory block ctd, the code */
     char *strs;			/* memory block ctd, the strings */
     Shfunc shf;			/* shell function for autoload */
+    FuncDump dump;		/* dump file this is in */
 };
 
+#define EA_REAL 0
+#define EA_HEAP 1
+#define EA_MAP  2
+
 typedef struct estate *Estate;
 
 struct estate {
@@ -508,6 +524,7 @@ struct eccstr {
     Eccstr next;
     char *str;
     wordcode offs;
+    int nfunc;
 };
 
 #define EC_NODUP  0