mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 13:51:41 +00:00
Fixed memory leaks
This commit is contained in:
parent
add1f28f92
commit
19ee9a581c
@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -99,7 +99,7 @@ public:
|
||||
#endif
|
||||
{ }
|
||||
|
||||
BytecodeContainer::~BytecodeContainer() { }
|
||||
BytecodeContainer::~BytecodeContainer();
|
||||
|
||||
|
||||
void mark();
|
||||
|
@ -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) {}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
};
|
||||
|
||||
|
||||
|
@ -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, ®expClassVal, 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, ®expClassVal, 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, ®expClassVal, 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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user