summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2007-01-10 15:30:59 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2007-01-10 15:30:59 (GMT)
commitf299701a39e378d072a5c5d97396675ce735b414 (patch)
treea89fe1c2a582e5bc126b2ec3cf259c3c61a28a55 /generic
parent0461303eb629c1a59984468e671be1d59c424aae (diff)
downloadtcl-f299701a39e378d072a5c5d97396675ce735b414.zip
tcl-f299701a39e378d072a5c5d97396675ce735b414.tar.gz
tcl-f299701a39e378d072a5c5d97396675ce735b414.tar.bz2
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.
Diffstat (limited to 'generic')
-rw-r--r--generic/regcomp.c12
-rw-r--r--generic/regcustom.h22
-rw-r--r--generic/regexec.c10
-rw-r--r--generic/regguts.h13
4 files changed, 49 insertions, 8 deletions
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&REG_QUOTE) && (flags&(REG_ADVANCED|REG_EXPANDED|REG_NEWLINE))) {
+ FreeVars(v);
return REG_INVARG;
}
if (!(flags&REG_EXTENDED) && (flags&REG_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&REG_EXPECT) && details == NULL) {
+ FreeVars(v);
return REG_INVARG;
}
if (v->g->info&REG_UIMPOSSIBLE) {
+ FreeVars(v);
return REG_NOMATCH;
}
backref = (v->g->info&REG_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: