diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 8ec5eb5556f..7155ba2ccb5 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -114,7 +114,7 @@ js::CreateRegExpMatchResult(JSContext *cx, HandleString string, MatchPairs &matc } RegExpRunStatus -ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, RegExpShared &re, +ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, RegExpShared &re, RegExpObject ®exp, JSLinearString *input, StableCharPtr chars, size_t length, size_t *lastIndex, MatchConduit &matches) { @@ -126,7 +126,7 @@ ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, RegExpShared &re, /* Only one MatchPair slot provided: execute short-circuiting regexp. */ status = re.executeMatchOnly(cx, chars, length, lastIndex, *matches.u.pair); if (status == RegExpRunStatus_Success && res) - res->updateLazily(cx, input, &re, lastIndex_orig); + res->updateLazily(cx, input, ®exp, lastIndex_orig); } else { /* Vector of MatchPairs provided: execute full regexp. */ status = re.execute(cx, chars, length, lastIndex, *matches.u.pairs); @@ -151,7 +151,7 @@ js::ExecuteRegExpLegacy(JSContext *cx, RegExpStatics *res, RegExpObject &reobj, MatchConduit conduit(&matches); RegExpRunStatus status = - ExecuteRegExpImpl(cx, res, *shared, input, chars, length, lastIndex, conduit); + ExecuteRegExpImpl(cx, res, *shared, reobj, input, chars, length, lastIndex, conduit); if (status == RegExpRunStatus_Error) return false; @@ -591,7 +591,7 @@ js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string, Match /* Steps 8-21. */ size_t lastIndexInt(i); RegExpRunStatus status = - ExecuteRegExpImpl(cx, res, *re, stableInput, chars, length, &lastIndexInt, matches); + ExecuteRegExpImpl(cx, res, *re, *reobj, stableInput, chars, length, &lastIndexInt, matches); if (status == RegExpRunStatus_Error) return RegExpRunStatus_Error; diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index e88a3141337..524c8889009 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -332,6 +332,7 @@ DeclMarkerImpl(Object, DebugScopeObject) DeclMarkerImpl(Object, GlobalObject) DeclMarkerImpl(Object, JSObject) DeclMarkerImpl(Object, JSFunction) +DeclMarkerImpl(Object, RegExpObject) DeclMarkerImpl(Object, ScopeObject) DeclMarkerImpl(Script, JSScript) DeclMarkerImpl(Shape, Shape) diff --git a/js/src/gc/Marking.h b/js/src/gc/Marking.h index a11f2ddfdf3..072623dbadd 100644 --- a/js/src/gc/Marking.h +++ b/js/src/gc/Marking.h @@ -97,6 +97,7 @@ DeclMarker(Object, DebugScopeObject) DeclMarker(Object, GlobalObject) DeclMarker(Object, JSObject) DeclMarker(Object, JSFunction) +DeclMarker(Object, RegExpObject) DeclMarker(Object, ScopeObject) DeclMarker(Script, JSScript) DeclMarker(Shape, Shape) diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index 0ea4a45130a..f2142e7ec80 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -674,6 +674,9 @@ Shape::Range::AutoRooter::trace(JSTracer *trc) void RegExpStatics::AutoRooter::trace(JSTracer *trc) { + if (statics->regexp) + MarkObjectRoot(trc, reinterpret_cast(&statics->regexp), + "RegExpStatics::AutoRooter regexp"); if (statics->matchesInput) MarkStringRoot(trc, reinterpret_cast(&statics->matchesInput), "RegExpStatics::AutoRooter matchesInput"); diff --git a/js/src/jsstr.cpp b/js/src/jsstr.cpp index ea566643a7f..4aa5e3659c3 100644 --- a/js/src/jsstr.cpp +++ b/js/src/jsstr.cpp @@ -2308,114 +2308,6 @@ BuildDollarReplacement(JSContext *cx, JSString *textstrArg, JSLinearString *reps return true; } -struct StringRange -{ - size_t start; - size_t length; - - StringRange(size_t s, size_t l) - : start(s), length(l) - { } -}; - -static JSString * -AppendSubstrings(JSContext *cx, Handle stableStr, - const StringRange *ranges, size_t rangesLen) -{ - JS_ASSERT(rangesLen); - - /* For single substrings, construct a dependent string. */ - if (rangesLen == 1) - return js_NewDependentString(cx, stableStr, ranges[0].start, ranges[0].length); - - /* Collect substrings into a rope. */ - RopeBuilder rope(cx); - for (size_t i = 0; i < rangesLen; i++) { - const StringRange &sr = ranges[i]; - - RootedString substr(cx, js_NewDependentString(cx, stableStr, sr.start, sr.length)); - if (!substr) - return NULL; - - /* Appending to the rope permanently roots the substring. */ - rope.append(substr); - } - - return rope.result(); -} - -static bool -str_replace_regexp_remove(JSContext *cx, CallArgs args, HandleString str, RegExpShared &re) -{ - Rooted stableStr(cx, str->ensureStable(cx)); - if (!stableStr) - return false; - - Vector ranges; - - StableCharPtr chars = stableStr->chars(); - size_t charsLen = stableStr->length(); - - MatchPair match; - size_t startIndex = 0; /* Index used for iterating through the string. */ - size_t lastIndex = 0; /* Index after last successful match. */ - - /* Accumulate StringRanges for unmatched substrings. */ - while (startIndex <= charsLen) { - if (!JS_CHECK_OPERATION_LIMIT(cx)) - return false; - - RegExpRunStatus status = re.executeMatchOnly(cx, chars, charsLen, &startIndex, match); - if (status == RegExpRunStatus_Error) - return false; - if (status == RegExpRunStatus_Success_NotFound) - break; - - /* Include the latest unmatched substring. */ - if (size_t(match.start) > lastIndex) { - if (!ranges.append(StringRange(lastIndex, match.start - lastIndex))) - return false; - } - - lastIndex = startIndex; - - /* Non-global removal executes at most once. */ - if (!re.global()) - break; - - if (match.isEmpty()) - lastIndex++; - } - - /* If unmatched, return the input string. */ - if (!lastIndex) { - args.rval().setString(str); - return true; - } - - /* The last successful match updates the RegExpStatics. */ - cx->regExpStatics()->updateLazily(cx, stableStr, &re, lastIndex); - - /* Include any remaining part of the string. */ - if (lastIndex < charsLen) { - if (!ranges.append(StringRange(lastIndex, charsLen - lastIndex))) - return false; - } - - /* Handle the empty string before calling .begin(). */ - if (ranges.empty()) { - args.rval().setString(cx->runtime->emptyString); - return true; - } - - JSString *result = AppendSubstrings(cx, stableStr, ranges.begin(), ranges.length()); - if (!result) - return false; - - args.rval().setString(result); - return true; -} - static inline bool str_replace_regexp(JSContext *cx, CallArgs args, ReplaceData &rdata) { @@ -2428,12 +2320,6 @@ str_replace_regexp(JSContext *cx, CallArgs args, ReplaceData &rdata) RegExpStatics *res = cx->regExpStatics(); RegExpShared &re = rdata.g.regExp(); - /* Optimize removal. */ - if (rdata.repstr && rdata.repstr->length() == 0 && !rdata.dollar) { - JS_ASSERT(!rdata.lambda && !rdata.elembase); - return str_replace_regexp_remove(cx, args, rdata.str, re); - } - Value tmp; if (!DoMatch(cx, res, rdata.str, re, ReplaceRegExpCallback, &rdata, REPLACE_ARGS, &tmp)) return false; diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index b74c48db20c..e2d9a786a7c 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -122,8 +122,8 @@ MatchPairs::initArray(size_t pairCount) /* Initialize all MatchPair objects to invalid locations. */ for (size_t i = 0; i < pairCount; i++) { - pairs_[i].start = -1; - pairs_[i].limit = -1; + pairs_[i].start = size_t(-1); + pairs_[i].limit = size_t(-1); } return true; @@ -645,18 +645,6 @@ RegExpCompartment::RegExpCompartment(JSRuntime *rt) RegExpCompartment::~RegExpCompartment() { JS_ASSERT(map_.empty()); - - /* - * RegExpStatics may have prevented a single RegExpShared from - * being collected during RegExpCompartment::sweep(). - */ - if (!inUse_.empty()) { - PendingSet::Enum e(inUse_); - RegExpShared *shared = e.front(); - JS_ASSERT(shared->activeUseCount == 0); - js_delete(shared); - e.removeFront(); - } JS_ASSERT(inUse_.empty()); } diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index f3d70e4b0b7..b2607a1509f 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -198,31 +198,22 @@ class RegExpShared class RegExpGuard { RegExpShared *re_; - - private: RegExpGuard(const RegExpGuard &) MOZ_DELETE; void operator=(const RegExpGuard &) MOZ_DELETE; - public: RegExpGuard() : re_(NULL) {} RegExpGuard(RegExpShared &re) : re_(&re) { re_->incRef(); } - ~RegExpGuard() { release(); } - - public: void init(RegExpShared &re) { - JS_ASSERT(!initialized()); + JS_ASSERT(!re_); re_ = &re; re_->incRef(); } - void release() { - if (re_) { + ~RegExpGuard() { + if (re_) re_->decRef(); - re_ = NULL; - } } - bool initialized() const { return !!re_; } RegExpShared *re() const { JS_ASSERT(initialized()); return re_; } RegExpShared *operator->() { return re(); } @@ -234,12 +225,9 @@ class RegExpCompartment struct Key { JSAtom *atom; uint16_t flag; - Key() {} Key(JSAtom *atom, RegExpFlag flag) - : atom(atom), flag(flag) - { } - + : atom(atom), flag(flag) {} typedef Key Lookup; static HashNumber hash(const Lookup &l) { return DefaultHasher::hash(l.atom) ^ (l.flag << 1); diff --git a/js/src/vm/RegExpStatics-inl.h b/js/src/vm/RegExpStatics-inl.h index 142bb870572..239b67c782f 100644 --- a/js/src/vm/RegExpStatics-inl.h +++ b/js/src/vm/RegExpStatics-inl.h @@ -27,6 +27,15 @@ SizeOfRegExpStaticsData(const JSObject *obj, JSMallocSizeOfFun mallocSizeOf) return mallocSizeOf(obj->getPrivate()); } +inline +RegExpStatics::RegExpStatics() + : pendingLazyEvaluation(false), + bufferLink(NULL), + copied(false) +{ + clear(); +} + inline bool RegExpStatics::createDependent(JSContext *cx, size_t start, size_t end, Value *out) { @@ -222,20 +231,15 @@ RegExpStatics::copyTo(RegExpStatics &dst) if (!pendingLazyEvaluation) dst.matches.initArrayFrom(matches); - if (regexpGuard.initialized()) - dst.regexpGuard.init(*regexpGuard); - else - dst.regexpGuard.release(); - dst.matchesInput = matchesInput; + dst.regexp = regexp; dst.lastIndex = lastIndex; dst.pendingInput = pendingInput; dst.flags = flags; dst.pendingLazyEvaluation = pendingLazyEvaluation; - JS_ASSERT_IF(pendingLazyEvaluation, regexpGuard.initialized()); + JS_ASSERT_IF(pendingLazyEvaluation, regexp); JS_ASSERT_IF(pendingLazyEvaluation, matchesInput); - JS_ASSERT(regexpGuard.initialized() == dst.regexpGuard.initialized()); } inline void @@ -257,20 +261,17 @@ RegExpStatics::restore() inline void RegExpStatics::updateLazily(JSContext *cx, JSLinearString *input, - RegExpShared *shared, size_t lastIndex) + RegExpObject *regexp, size_t lastIndex) { - JS_ASSERT(input && shared); + JS_ASSERT(input && regexp); aboutToWrite(); BarrieredSetPair(cx->compartment, pendingInput, input, matchesInput, input); - if (regexpGuard.initialized()) - regexpGuard.release(); - regexpGuard.init(*shared); - - this->lastIndex = lastIndex; pendingLazyEvaluation = true; + this->regexp = regexp; + this->lastIndex = lastIndex; } inline bool @@ -281,7 +282,7 @@ RegExpStatics::updateFromMatchPairs(JSContext *cx, JSLinearString *input, MatchP /* Unset all lazy state. */ pendingLazyEvaluation = false; - this->regexpGuard.release(); + this->regexp = NULL; this->lastIndex = size_t(-1); BarrieredSetPair(cx->compartment, @@ -300,14 +301,11 @@ inline void RegExpStatics::clear() { aboutToWrite(); - - matches.forgetArray(); - matchesInput = NULL; - regexpGuard.release(); - lastIndex = size_t(-1); - pendingInput = NULL; flags = RegExpFlag(0); + pendingInput = NULL; pendingLazyEvaluation = false; + matchesInput = NULL; + matches.forgetArray(); } inline void @@ -365,9 +363,8 @@ RegExpStatics::checkInvariants() { #ifdef DEBUG if (pendingLazyEvaluation) { - JS_ASSERT(regexpGuard.initialized()); + JS_ASSERT(regexp); JS_ASSERT(pendingInput); - JS_ASSERT(lastIndex != size_t(-1)); return; } diff --git a/js/src/vm/RegExpStatics.cpp b/js/src/vm/RegExpStatics.cpp index e87557045c9..3834c02e03a 100644 --- a/js/src/vm/RegExpStatics.cpp +++ b/js/src/vm/RegExpStatics.cpp @@ -74,7 +74,7 @@ RegExpStatics::executeLazy(JSContext *cx) if (!pendingLazyEvaluation) return true; - JS_ASSERT(regexpGuard.initialized()); + JS_ASSERT(regexp); JS_ASSERT(matchesInput); JS_ASSERT(lastIndex != size_t(-1)); @@ -87,14 +87,17 @@ RegExpStatics::executeLazy(JSContext *cx) StableCharPtr chars(matchesInput->chars(), length); /* Execute the full regular expression. */ - RegExpRunStatus status = regexpGuard->execute(cx, chars, length, &this->lastIndex, this->matches); + RegExpGuard shared; + if (!regexp->getShared(cx, &shared)) + return false; + + RegExpRunStatus status = shared->execute(cx, chars, length, &this->lastIndex, this->matches); if (status == RegExpRunStatus_Error) return false; /* Unset lazy state and remove rooted values that now have no use. */ pendingLazyEvaluation = false; - regexpGuard.release(); - lastIndex = size_t(-1); + regexp = NULL; return true; } diff --git a/js/src/vm/RegExpStatics.h b/js/src/vm/RegExpStatics.h index 9a6a7e0c3e4..aa742ccf6a3 100644 --- a/js/src/vm/RegExpStatics.h +++ b/js/src/vm/RegExpStatics.h @@ -15,7 +15,6 @@ #include "js/Vector.h" #include "vm/MatchPairs.h" -#include "vm/RegExpObject.h" namespace js { @@ -26,7 +25,7 @@ class RegExpStatics HeapPtr matchesInput; /* The previous RegExp input, used to resolve lazy state. */ - RegExpGuard regexpGuard; /* Strong reference to RegExpShared. */ + HeapPtr regexp; size_t lastIndex; /* The latest RegExp input, set before execution. */ @@ -34,7 +33,7 @@ class RegExpStatics RegExpFlag flags; /* - * If true, |matchesInput|, |regexpGuard|, and |lastIndex| may be used + * If true, |matchesInput|, |regexp|, and |lastIndex| may be used * to replay the last executed RegExp, and |matches| is invalid. */ bool pendingLazyEvaluation; @@ -43,10 +42,6 @@ class RegExpStatics RegExpStatics *bufferLink; bool copied; - public: - RegExpStatics() : bufferLink(NULL), copied(false) { clear(); } - static JSObject *create(JSContext *cx, GlobalObject *parent); - private: bool executeLazy(JSContext *cx); @@ -83,9 +78,14 @@ class RegExpStatics friend class PreserveRegExpStatics; public: + inline RegExpStatics(); + + static JSObject *create(JSContext *cx, GlobalObject *parent); + /* Mutators. */ + inline void updateLazily(JSContext *cx, JSLinearString *input, - RegExpShared *shared, size_t lastIndex); + RegExpObject *regexp, size_t lastIndex); inline bool updateFromMatchPairs(JSContext *cx, JSLinearString *input, MatchPairs &newPairs); inline void setMultiline(JSContext *cx, bool enabled); @@ -118,6 +118,8 @@ class RegExpStatics } void mark(JSTracer *trc) { + if (regexp) + gc::MarkObject(trc, ®exp, "res->regexp"); if (pendingInput) MarkString(trc, &pendingInput, "res->pendingInput"); if (matchesInput)