From f299701a39e378d072a5c5d97396675ce735b414 Mon Sep 17 00:00:00 2001 From: dkf Date: Wed, 10 Jan 2007 15:30:59 +0000 Subject: Arrange for RE engine workspace to be held in TSD. This is safe, less C-stack-hungry than before, and faster than just using heap allocation. --- ChangeLog | 16 ++++++++++++---- generic/regcomp.c | 12 +++++++++--- generic/regcustom.h | 22 +++++++++++++++++++--- generic/regexec.c | 10 ++++++++-- generic/regguts.h | 13 +++++++++++++ 5 files changed, 61 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index b4bf470..34ae284 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,14 +1,22 @@ +2007-01-10 Donal K. Fellows + + * generic/regcomp.c (compile, freev): Define a strategy for + * generic/regexec.c (exec): managing the internal vars + * generic/regguts.h (AllocVars, FreeVars): of the RE engine to reduce + * generic/regcustom.h (AllocVars, FreeVars): C stack usage. This will + make Tcl as a whole much less likely to run out of stack space... + 2007-01-09 Donal K. Fellows - * generic/tclCompCmds.c (TclCompileLindexCmd): + * generic/tclCompCmds.c (TclCompileLindexCmd): * tests/lindex.test (lindex-9.2): Fix silly bug that ended up sometimes compiling list arguments in the wrong order. [Bug 1631364] 2007-01-03 Kevin Kenny - * generic/tclDate.c: Regenerated to recover a lost fix from - patthoyts. [Bug 1618523] - + * generic/tclDate.c: Regenerated to recover a lost fix from patthoyts. + [Bug 1618523] + 2006-12-26 Mo DeJong * generic/tclIO.c (Tcl_GetsObj): Avoid checking for for the LF in a diff --git a/generic/regcomp.c b/generic/regcomp.c index 0d6f066..049ad69 100644 --- a/generic/regcomp.c +++ b/generic/regcomp.c @@ -287,8 +287,7 @@ compile( size_t len, int flags) { - struct vars var; - struct vars *v = &var; + AllocVars(v); struct guts *g; int i; size_t j; @@ -300,12 +299,15 @@ compile( */ if (re == NULL || string == NULL) { + FreeVars(v); return REG_INVARG; } if ((flags®_QUOTE) && (flags&(REG_ADVANCED|REG_EXPANDED|REG_NEWLINE))) { + FreeVars(v); return REG_INVARG; } if (!(flags®_EXTENDED) && (flags®_ADVF)) { + FreeVars(v); return REG_INVARG; } @@ -525,6 +527,8 @@ freev( struct vars *v, int err) { + register int ret; + if (v->re != NULL) { rfree(v->re); } @@ -554,7 +558,9 @@ freev( } ERR(err); /* nop if err==0 */ - return v->err; + ret = v->err; + FreeVars(v); + return ret; } /* diff --git a/generic/regcustom.h b/generic/regcustom.h index 6abd24c..6b6b38c 100644 --- a/generic/regcustom.h +++ b/generic/regcustom.h @@ -11,12 +11,12 @@ * redistributions in source form retain this entire copyright notice and * indicate the origin and nature of any modifications. * - * I'd appreciate being given credit for this package in the documentation - * of software which uses it, but that is not a requirement. + * I'd appreciate being given credit for this package in the documentation of + * software which uses it, but that is not a requirement. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY - * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL * HENRY SPENCER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; @@ -116,5 +116,21 @@ typedef int celt; /* type to hold chr, MCCE number, or NOCELT */ #define REG_DEBUG /* */ #endif +/* method of allocating a local workspace */ +#if 1 +#define AllocVars(vPtr) \ + static Tcl_ThreadDataKey varsKey; \ + register struct vars *vPtr = (struct vars *) \ + Tcl_GetThreadData(&varsKey, sizeof(struct vars)) +#else +/* This strategy for allocating workspace is "more proper" in some sense, but + * quite a bit slower. Using TSD (as above) leads to code that is quite a bit + * faster in practice. */ +#define AllocVars(vPtr) \ + register struct vars *vPtr = (struct vars *) MALLOC(sizeof(struct vars)) +#define FreeVars(vPtr) \ + FREE(vPtr) +#endif + /* and pick up the standard header */ #include "regex.h" diff --git a/generic/regexec.c b/generic/regexec.c index 6862ef9..d39685c 100644 --- a/generic/regexec.c +++ b/generic/regexec.c @@ -170,8 +170,7 @@ exec( regmatch_t pmatch[], int flags) { - struct vars var; - register struct vars *v = &var; + AllocVars(v); int st; size_t n; int backref; @@ -185,9 +184,11 @@ exec( */ if (re == NULL || string == NULL || re->re_magic != REMAGIC) { + FreeVars(v); return REG_INVARG; } if (re->re_csize != sizeof(chr)) { + FreeVars(v); return REG_MIXED; } @@ -198,9 +199,11 @@ exec( v->re = re; v->g = (struct guts *)re->re_guts; if ((v->g->cflags®_EXPECT) && details == NULL) { + FreeVars(v); return REG_INVARG; } if (v->g->info®_UIMPOSSIBLE) { + FreeVars(v); return REG_NOMATCH; } backref = (v->g->info®_UBACKREF) ? 1 : 0; @@ -221,6 +224,7 @@ exec( MALLOC((v->g->nsub + 1) * sizeof(regmatch_t)); } if (v->pmatch == NULL) { + FreeVars(v); return REG_ESPACE; } v->nmatch = v->g->nsub + 1; @@ -247,6 +251,7 @@ exec( if (v->pmatch != pmatch && v->pmatch != mat) { FREE(v->pmatch); } + FreeVars(v); return REG_ESPACE; } } else { @@ -284,6 +289,7 @@ exec( if (v->mem != NULL && v->mem != mem) { FREE(v->mem); } + FreeVars(v); return st; } diff --git a/generic/regguts.h b/generic/regguts.h index 190d40b..991979e 100644 --- a/generic/regguts.h +++ b/generic/regguts.h @@ -399,6 +399,19 @@ struct guts { struct subre *lacons; /* lookahead-constraint vector */ int nlacons; /* size of lacons */ }; + +/* + * Magic for allocating a variable workspace. + */ + +#ifndef AllocVars +#define AllocVars(vPtr) \ + struct vars var; \ + register struct vars *vPtr = &var +#endif +#ifndef FreeVars +#define FreeVars(vPtr) ((void) 0) +#endif /* * Local Variables: -- cgit v0.12