Fixed memory leaks

This commit is contained in:
rogerl%netscape.com 2003-06-16 07:20:59 +00:00
parent add1f28f92
commit 19ee9a581c
11 changed files with 146 additions and 100 deletions

View File

@ -157,6 +157,10 @@ namespace MetaData {
void BytecodeContainer::saveFrame(Frame *f) { saveObject(f); }
void BytecodeContainer::addRegExp(RegExpInstance *x, size_t pos) { emitOp(eRegExp, pos); saveObject(x); addShort((uint16)(mObjectList.size() - 1)); }
BytecodeContainer::~BytecodeContainer()
{
}
}
}

View File

@ -99,7 +99,7 @@ public:
#endif
{ }
BytecodeContainer::~BytecodeContainer() { }
BytecodeContainer::~BytecodeContainer();
void mark();

View File

@ -199,7 +199,7 @@ namespace JavaScript
// If lengthKnown is false, this is the serialPos of this Item instead of a length
bool hasKind(Kind k) const {return kind == k;}
explicit Item(Kind kind): kind(kind), lengthKnown(true) {}
explicit Item(Kind kind): kind(kind), lengthKnown(true), length(0) {}
Item(Kind kind, uint32 length): kind(kind), lengthKnown(true), length(length) {}
Item(Kind kind, uint32 length, uint32 beginSerialPos):
kind(kind), lengthKnown(false), length(length), totalLength(beginSerialPos) {}

View File

@ -130,7 +130,6 @@ namespace MetaData {
// one that matches the handler's. The bytecode container, pc and
// sp are all reset appropriately, and execution continues.
HandlerData *hndlr = (HandlerData *)mTryStack.top();
// mTryStack.pop();
ActivationFrame *curAct = (activationStackEmpty()) ? NULL : (activationStackTop - 1);
js2val x = JS2VAL_UNDEFINED;
@ -507,6 +506,8 @@ namespace MetaData {
valueOf_StringAtom(world.identifiers["valueOf"]),
packageFrame(NULL),
parameterFrame(NULL),
parameterCount(0),
superConstructorCalled(false),
localFrame(NULL),
parameterSlots(NULL),
traceInstructions(false)
@ -527,6 +528,9 @@ namespace MetaData {
JS2Engine::~JS2Engine()
{
while (!mTryStack.empty()) {
popHandler();
}
delete [] execStack;
delete [] activationStack;
}

View File

@ -67,6 +67,7 @@ namespace MetaData {
Pragma::Flags flags = Pragma::js1;
Parser p(world, a, flags, str, fileName);
CompilationData *oldData = NULL;
BytecodeContainer *new_bCon = NULL;
try {
StmtNode *parsedStatements = p.parseProgram();
ASSERT(p.lexer.peek(true).hasKind(Token::end));
@ -84,6 +85,7 @@ namespace MetaData {
}
if (parsedStatements) {
oldData = startCompilationUnit(NULL, str, fileName);
new_bCon = bCon;
ValidateStmtList(parsedStatements);
result = ExecuteStmtList(RunPhase, parsedStatements);
}
@ -91,10 +93,14 @@ namespace MetaData {
catch (Exception &x) {
if (oldData)
restoreCompilationUnit(oldData);
if (new_bCon)
delete new_bCon;
throw x;
}
if (oldData)
restoreCompilationUnit(oldData);
if (new_bCon)
delete new_bCon;
return result;
}
@ -1063,6 +1069,8 @@ VariableMemberCommon:
if (multiname->listContains(ns.first)) {
(*lbeP)->bindingList.erase(i);
deletedOne = true;
if (ns.second->content->release())
delete ns.second->content;
break;
}
}

View File

@ -1150,6 +1150,7 @@ namespace MetaData {
}
bCon->setLabel(sw->breakLabelID);
delete frV;
}
break;
case StmtNode::While:
@ -4032,6 +4033,7 @@ static const uint8 urlCharType[256] =
// A 'forbidden' member, used to mark hidden bindings
forbiddenMember = new LocalMember(Member::ForbiddenMember, true);
forbiddenMember->acquire();
FunctionInstance *fInst = NULL;
DEFINE_ROOTKEEPER(this, rk1, fInst);
@ -4211,6 +4213,7 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
clear(); // don't blow off the contents of 'this' as the destructors for
// embedded objects will get messed up (as they run on exit).
delete engine;
delete forbiddenMember;
if (bCon) delete bCon;
}
@ -5064,7 +5067,6 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
LocalBindingEntry *lbe = *bi;
for (LocalBindingEntry::NS_Iterator i = lbe->begin(), end = lbe->end(); (i != end); i++) {
LocalBindingEntry::NamespaceBinding ns = *i;
/* if (ns.first->name) JS2Object::mark(ns.first->name); */
ns.second->content->mark();
}
}
@ -5167,6 +5169,9 @@ XXX see EvalAttributeExpression, where identifiers are being handled for now...
delete mSplitValue;
}
RegExpInstance::~RegExpInstance() { if (mRegExp) { js_DestroyRegExp(mRegExp); free(mRegExp);} }
/************************************************************************************
*
* InstanceMethod

View File

@ -182,6 +182,7 @@ private:
class Pond {
public:
Pond(size_t sz, Pond *nextPond);
~Pond() { delete [] pondBase; if (nextPond) delete nextPond; }
void *allocFromPond(JS2Metadata *meta, size_t sz, PondScum::ScumFlag flag);
uint32 returnToPond(PondScum *p);
@ -420,12 +421,16 @@ public:
InstanceGetterMember,
InstanceSetterMember };
Member(MemberKind kind) : memberKind(kind) { }
Member(MemberKind kind) : memberKind(kind), count(0) { }
virtual ~Member() { }
MemberKind memberKind;
virtual void mark() { }
void acquire() { count++; }
bool release() { ASSERT(count > 0); return ((--count) == 0); }
int count;
};
// A local member is either forbidden, a dynamic variable, a variable, a constructor method, a getter or a setter:
@ -538,12 +543,13 @@ public:
// the other binding is for writing only).
class LocalBinding {
public:
LocalBinding(AccessSet accesses, LocalMember *content, bool enumerable) : accesses(accesses), content(content), xplicit(false), enumerable(enumerable) { }
LocalBinding(AccessSet accesses, LocalMember *content, bool enumerable)
: accesses(accesses), content(content), xplicit(false), enumerable(enumerable) { content->acquire(); }
// The qualified name is to be inferred from the map where this binding is kept
// QualifiedName qname; // The qualified name bound by this binding
virtual ~LocalBinding() { /*delete content;*/ } // XXX what about aliases!!!
virtual ~LocalBinding() { if (content->release()) delete content; }
AccessSet accesses;
LocalMember *content; // The member to which this qualified name was bound
@ -616,8 +622,9 @@ public:
class InstanceBinding {
public:
InstanceBinding(AccessSet accesses, InstanceMember *content) : accesses(accesses), content(content) { }
virtual ~InstanceBinding() { delete content; }
InstanceBinding(AccessSet accesses, InstanceMember *content)
: accesses(accesses), content(content) { content->acquire(); }
virtual ~InstanceBinding() { if (content->release()) delete content; }
// The qualified name is to be inferred from the map where this binding is kept
// QualifiedName qname; // The qualified name bound by this binding
@ -1040,7 +1047,7 @@ public:
// that contains the RegExp object
class RegExpInstance : public SimpleInstance {
public:
RegExpInstance(JS2Metadata *meta, js2val parent, JS2Class *type) : SimpleInstance(meta, parent, type) { }
RegExpInstance(JS2Metadata *meta, js2val parent, JS2Class *type) : SimpleInstance(meta, parent, type), mRegExp(NULL) { }
void setLastIndex(JS2Metadata *meta, js2val a);
void setGlobal(JS2Metadata *meta, js2val a);
@ -1055,7 +1062,7 @@ public:
js2val getSource(JS2Metadata *meta);
JS2RegExp *mRegExp;
virtual ~RegExpInstance() { }
virtual ~RegExpInstance();
};

View File

@ -160,21 +160,21 @@ namespace MetaData {
const String *str = NULL;
DEFINE_ROOTKEEPER(meta, rk0, str);
js2val regexpClassVal = OBJECT_TO_JS2VAL(meta->regexpClass);
js2val result = JS2VAL_NULL;
js2val regexpClassVal = OBJECT_TO_JS2VAL(meta->regexpClass);
js2val result = JS2VAL_NULL;
if (argc == 0) {
js2val inputVal;
if (!meta->classClass->ReadPublic(meta, &regexpClassVal, meta->world.identifiers["input"], RunPhase, &inputVal))
ASSERT(false);
str = meta->toString(inputVal);
}
else
str = meta->toString(argv[0]);
js2val inputVal;
if (!meta->classClass->ReadPublic(meta, &regexpClassVal, meta->world.identifiers["input"], RunPhase, &inputVal))
ASSERT(false);
str = meta->toString(inputVal);
}
else
str = meta->toString(argv[0]);
uint32 index = 0;
js2val globalMultiline;
if (!meta->classClass->ReadPublic(meta, &regexpClassVal, meta->world.identifiers["multiline"], RunPhase, &globalMultiline))
ASSERT(false);
ASSERT(false);
if (meta->toBoolean(thisInst->getGlobal(meta))) {
js2val lastIndexVal = thisInst->getLastIndex(meta);
@ -187,59 +187,59 @@ namespace MetaData {
}
REMatchResult *match = REExecute(meta, thisInst->mRegExp, str->begin(), index, toUInt32(str->length()), meta->toBoolean(globalMultiline));
if (match) {
if (meta->toBoolean(thisInst->getGlobal(meta))) {
if (meta->toBoolean(thisInst->getGlobal(meta))) {
index = match->endIndex;
thisInst->setLastIndex(meta, meta->engine->allocNumber((float64)index));
}
// construct the result array and set $1.. in RegExp statics
ArrayInstance *A = NULL;
DEFINE_ROOTKEEPER(meta, rk, A);
if (test)
result = JS2VAL_TRUE;
else {
A = new (meta) ArrayInstance(meta, meta->arrayClass->prototype, meta->arrayClass);
result = OBJECT_TO_JS2VAL(A);
}
if (test)
result = JS2VAL_TRUE;
else {
A = new (meta) ArrayInstance(meta, meta->arrayClass->prototype, meta->arrayClass);
result = OBJECT_TO_JS2VAL(A);
}
js2val matchStr = meta->engine->allocString(str->substr((uint32)match->startIndex, (uint32)match->endIndex - match->startIndex));
DEFINE_ROOTKEEPER(meta, rk1, matchStr);
js2val inputStr = meta->engine->allocString(str);
js2val inputStr = meta->engine->allocString(str);
DEFINE_ROOTKEEPER(meta, rk2, inputStr);
if (!test)
meta->createDynamicProperty(A, meta->engine->numberToStringAtom((long)0), matchStr, ReadWriteAccess, false, true);
js2val parenStr = JS2VAL_VOID;
DEFINE_ROOTKEEPER(meta, rk3, parenStr);
if (match->parenCount == 0) // arrange to set the lastParen to "", not undefined (it's a non-ecma 1.2 thing)
parenStr = meta->engine->allocString("");
if (!test)
meta->createDynamicProperty(A, meta->engine->numberToStringAtom((long)0), matchStr, ReadWriteAccess, false, true);
js2val parenStr = JS2VAL_VOID;
DEFINE_ROOTKEEPER(meta, rk3, parenStr);
if (match->parenCount == 0) // arrange to set the lastParen to "", not undefined (it's a non-ecma 1.2 thing)
parenStr = meta->engine->allocString("");
for (int32 i = 0; i < match->parenCount; i++) {
if (match->parens[i].index != -1) {
parenStr = meta->engine->allocString(str->substr((uint32)(match->parens[i].index), (uint32)(match->parens[i].length)));
if (!test)
meta->createDynamicProperty(A, meta->engine->numberToStringAtom(toUInt32(i + 1)), parenStr, ReadWriteAccess, false, true);
if (i < 9) { // 0-->8 maps to $1 thru $9
char name[3] = "$0";
name[1] = '1' + i;
String staticName(widenCString(name));
meta->classClass->WritePublic(meta, regexpClassVal, meta->world.identifiers[staticName], true, parenStr);
}
}
else {
if (!test)
meta->createDynamicProperty(A, meta->engine->numberToStringAtom(toUInt32(i + 1)), JS2VAL_UNDEFINED, ReadWriteAccess, false, true);
if (i < 9) { // 0-->8 maps to $1 thru $9
char name[3] = "$0";
name[1] = '1' + i;
String staticName(widenCString(name));
meta->classClass->WritePublic(meta, regexpClassVal, meta->world.identifiers[staticName], true, JS2VAL_UNDEFINED);
}
}
meta->createDynamicProperty(A, meta->engine->numberToStringAtom(toUInt32(i + 1)), parenStr, ReadWriteAccess, false, true);
if (i < 9) { // 0-->8 maps to $1 thru $9
char name[3] = "$0";
name[1] = '1' + i;
String staticName(widenCString(name));
meta->classClass->WritePublic(meta, regexpClassVal, meta->world.identifiers[staticName], true, parenStr);
}
}
else {
if (!test)
meta->createDynamicProperty(A, meta->engine->numberToStringAtom(toUInt32(i + 1)), JS2VAL_UNDEFINED, ReadWriteAccess, false, true);
if (i < 9) { // 0-->8 maps to $1 thru $9
char name[3] = "$0";
name[1] = '1' + i;
String staticName(widenCString(name));
meta->classClass->WritePublic(meta, regexpClassVal, meta->world.identifiers[staticName], true, JS2VAL_UNDEFINED);
}
}
}
if (!test) {
setLength(meta, A, match->parenCount + 1);
if (!test) {
setLength(meta, A, match->parenCount + 1);
// add 'index' and 'input' properties to the result array
meta->createDynamicProperty(A, meta->world.identifiers["index"], meta->engine->allocNumber((float64)(match->startIndex)), ReadWriteAccess, false, true);
meta->createDynamicProperty(A, meta->world.identifiers["input"], inputStr, ReadWriteAccess, false, true);
}
meta->createDynamicProperty(A, meta->world.identifiers["index"], meta->engine->allocNumber((float64)(match->startIndex)), ReadWriteAccess, false, true);
meta->createDynamicProperty(A, meta->world.identifiers["input"], inputStr, ReadWriteAccess, false, true);
}
// set other RegExp statics
meta->classClass->WritePublic(meta, regexpClassVal, meta->world.identifiers["input"], true, inputStr);
meta->classClass->WritePublic(meta, regexpClassVal, meta->world.identifiers["lastMatch"], true, matchStr);
@ -250,21 +250,22 @@ namespace MetaData {
js2val rightContextVal = meta->engine->allocString(str->substr((uint32)match->endIndex, (uint32)str->length() - match->endIndex));
DEFINE_ROOTKEEPER(meta, rk5, rightContextVal);
meta->classClass->WritePublic(meta, regexpClassVal, meta->world.identifiers["rightContext"], true, rightContextVal);
free(match);
}
return result;
}
}
js2val RegExp_exec(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
return RegExp_exec_sub(meta, thisValue, argv, argc, false);
return RegExp_exec_sub(meta, thisValue, argv, argc, false);
}
js2val RegExp_test(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
js2val result = RegExp_exec_sub(meta, thisValue, argv, argc, true);
if (result != JS2VAL_TRUE)
result = JS2VAL_FALSE;
return result;
}
js2val result = RegExp_exec_sub(meta, thisValue, argv, argc, true);
if (result != JS2VAL_TRUE)
result = JS2VAL_FALSE;
return result;
}
js2val RegExp_Call(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
@ -326,19 +327,19 @@ namespace MetaData {
else
meta->reportError(Exception::syntaxError, "Failed to parse RegExp : '{0}'", meta->engine->errorPos(), "/" + *regexpStr + "/" + *flagStr); // XXX what about the RE parser error message?
return thisValue;
}
}
js2val RegExp_compile(JS2Metadata *meta, const js2val thisValue, js2val *argv, uint32 argc)
{
return RegExp_compile_sub(meta, thisValue, argv, argc, false);
}
return RegExp_compile_sub(meta, thisValue, argv, argc, false);
}
js2val RegExp_ConstructorOpt(JS2Metadata *meta, const js2val /* thisValue */, js2val *argv, uint32 argc, bool flat)
{
RegExpInstance *thisInst = new (meta) RegExpInstance(meta, meta->regexpClass->prototype, meta->regexpClass);
DEFINE_ROOTKEEPER(meta, rk, thisInst);
js2val thatValue = OBJECT_TO_JS2VAL(thisInst);
return RegExp_compile_sub(meta, thatValue, argv, argc, flat);
return RegExp_compile_sub(meta, thatValue, argv, argc, flat);
}
js2val RegExp_Constructor(JS2Metadata *meta, const js2val /* thisValue */, js2val *argv, uint32 argc)
@ -367,7 +368,7 @@ namespace MetaData {
struct {
char *name;
char *aliasName;
char *aliasName;
JS2Class *type;
} RegExpStaticVars[STATIC_VAR_COUNT] = {
{ "input", "$_", meta->stringClass },
@ -376,7 +377,7 @@ namespace MetaData {
{ "lastParen", "$+", meta->objectClass },
{ "leftContext", "$`", meta->stringClass },
{ "rightContext", "$'", meta->stringClass },
{ "$1", NULL, meta->objectClass },
{ "$2", NULL, meta->objectClass },
{ "$3", NULL, meta->objectClass },
@ -392,17 +393,17 @@ namespace MetaData {
meta->env->addFrame(meta->regexpClass);
for (i = 0; i < STATIC_VAR_COUNT; i++)
{
Variable *v = new Variable();
v->type = RegExpStaticVars[i].type;
if (RegExpStaticVars[i].type == meta->stringClass)
v->value = meta->engine->allocString("");
else
if (RegExpStaticVars[i].type == meta->booleanClass)
v->value = JS2VAL_FALSE;
Variable *v = new Variable();
v->type = RegExpStaticVars[i].type;
if (RegExpStaticVars[i].type == meta->stringClass)
v->value = meta->engine->allocString("");
else
if (RegExpStaticVars[i].type == meta->booleanClass)
v->value = JS2VAL_FALSE;
meta->defineLocalMember(meta->env, meta->world.identifiers[RegExpStaticVars[i].name], NULL, Attribute::NoOverride, false, ReadWriteAccess, v, 0, false);
if (RegExpStaticVars[i].aliasName)
meta->defineLocalMember(meta->env, meta->world.identifiers[RegExpStaticVars[i].aliasName], NULL, Attribute::NoOverride, false, ReadWriteAccess, v, 0, false);
}
if (RegExpStaticVars[i].aliasName)
meta->defineLocalMember(meta->env, meta->world.identifiers[RegExpStaticVars[i].aliasName], NULL, Attribute::NoOverride, false, ReadWriteAccess, v, 0, false);
}
meta->env->removeTopFrame();
NamespaceList publicNamespaceList;

View File

@ -2525,7 +2525,7 @@ js2val RegExp_exec(Context *cx, const js2val thisValue, js2val *argv, uint32 arg
String *parenStr = new String(str->substr((uint32)(match->parens[i].index), (uint32)(match->parens[i].length)));
JSValue::instance(result)->setProperty(cx, *numberToString(i + 1), NULL, JSValue::newString(parenStr));
}
else
else
JSValue::instance(result)->setProperty(cx, *numberToString(i + 1), NULL, kUndefinedValue);
}
// XXX SpiderMonkey also adds 'index' and 'input' properties to the result
@ -2544,7 +2544,7 @@ js2val RegExp_exec(Context *cx, const js2val thisValue, js2val *argv, uint32 arg
index = match->endIndex;
thisInst->setProperty(cx, cx->LastIndex_StringAtom, CURRENT_ATTR, JSValue::newNumber((float64)index));
}
free(match);
}
}
@ -2563,8 +2563,10 @@ static js2val RegExp_test(Context *cx, const js2val thisValue, js2val *argv, uin
RegExp_Type->getProperty(cx, cx->Multiline_StringAtom, CURRENT_ATTR);
js2val globalMultiline = cx->popValue();
REMatchState *match = REExecute(thisInst->mRegExp, str->begin(), 0, (int32)str->length(), JSValue::boolean(JSValue::toBoolean(cx, globalMultiline)));
if (match)
if (match) {
free(match);
return kTrueValue;
}
}
return kFalseValue;
}

View File

@ -134,8 +134,11 @@ static js2val String_search(JS2Metadata *meta, const js2val thisValue, js2val *a
JS2RegExp *re = (checked_cast<RegExpInstance *>(JS2VAL_TO_OBJECT(regexp)))->mRegExp;
REMatchResult *match = REExecute(meta, re, str->begin(), 0, (int32)str->length(), false);
if (match)
return meta->engine->allocNumber((float64)(match->startIndex));
if (match) {
js2val result = meta->engine->allocNumber((float64)(match->startIndex));
free(match);
return result;
}
else
return meta->engine->allocNumber(-1.0);
@ -197,6 +200,7 @@ static js2val String_match(JS2Metadata *meta, const js2val thisValue, js2val *ar
A = new (meta) ArrayInstance(meta, meta->arrayClass->prototype, meta->arrayClass);
meta->arrayClass->WritePublic(meta, OBJECT_TO_JS2VAL(A), meta->engine->numberToStringAtom(index), true, matchStr);
index++;
free(match);
}
thisInst->setLastIndex(meta, meta->engine->allocNumber((float64)lastIndex));
return OBJECT_TO_JS2VAL(A);
@ -308,7 +312,9 @@ static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val *
while (true) {
match = REExecute(meta, re, S->begin(), lastIndex, toInt32(S->length()), false);
if (match) {
if (!match)
break;
else {
String insertString;
uint32 start = 0;
while (true) {
@ -331,9 +337,8 @@ static js2val String_replace(JS2Metadata *meta, const js2val thisValue, js2val *
// and then add the replacement string
newString += insertString;
}
else
break;
lastIndex = match->endIndex; // use lastIndex to grab remainder after break
free(match);
if ((re->flags & JSREG_GLOB) == 0)
break;
}

View File

@ -2792,7 +2792,8 @@ REMatchResult *REExecute(JS2Metadata *meta, JS2RegExp *re, const jschar *str, ui
REGlobalData gData;
REMatchState *x, *result;
const jschar *cp;
uint32 start;
uint32 start, p;
REMatchResult *returnValue = NULL;
start = index;
if (start > length)
@ -2812,17 +2813,21 @@ REMatchResult *REExecute(JS2Metadata *meta, JS2RegExp *re, const jschar *str, ui
result = MatchRegExp(&gData, x);
if (!gData.ok)
return NULL;
goto out;
if (!result)
return NULL;
goto out;
REMatchResult *returnValue = (REMatchResult *)malloc(sizeof(REMatchResult) + (re->parenCount - 1) * sizeof(RECapture));
returnValue = (REMatchResult *)malloc(sizeof(REMatchResult) + (re->parenCount - 1) * sizeof(RECapture));
returnValue->startIndex = gData.start + gData.skipped;
returnValue->endIndex = result->cp - str;
returnValue->parenCount = re->parenCount;
for (uint32 p = 0; p < re->parenCount; p++) {
for (p = 0; p < re->parenCount; p++) {
returnValue->parens[p] = result->parens[p];
}
out:
free(x);
free(gData.stateStack);
free(gData.backTrackStack);
return returnValue;
}
@ -2831,7 +2836,8 @@ REMatchResult *REMatch(JS2Metadata *meta, JS2RegExp *re, const jschar *str, uint
REGlobalData gData;
REMatchState *x, *result;
const jschar *cp;
uint32 j;
uint32 j, p;
REMatchResult *returnValue = NULL;
cp = JSSTRING_CHARS(str);
gData.cpbegin = cp;
@ -2849,17 +2855,21 @@ REMatchResult *REMatch(JS2Metadata *meta, JS2RegExp *re, const jschar *str, uint
x->parens[j].index = -1;
result = executeREBytecode(&gData, x, false);
if (!gData.ok)
return NULL;
goto out;
if (!result)
return NULL;
goto out;
REMatchResult *returnValue = (REMatchResult *)malloc(sizeof(REMatchResult) + (re->parenCount - 1) * sizeof(RECapture));
returnValue = (REMatchResult *)malloc(sizeof(REMatchResult) + (re->parenCount - 1) * sizeof(RECapture));
returnValue->startIndex = gData.skipped;
returnValue->endIndex = result->cp - str;
returnValue->parenCount = re->parenCount;
for (uint32 p = 0; p < re->parenCount; p++) {
for (p = 0; p < re->parenCount; p++) {
returnValue->parens[p] = result->parens[p];
}
out:
free(x);
free(gData.stateStack);
free(gData.backTrackStack);
return returnValue;
}