Bug 832217 - Construct RegExpShared in the same compartment as the RegExpStatics. r=billm

This commit is contained in:
Sean Stangl 2013-02-01 17:36:29 -08:00
parent a0a8f9ba33
commit 46f8dd6c33
6 changed files with 55 additions and 121 deletions

View File

@ -633,11 +633,12 @@ RegExpStatics::AutoRooter::trace(JSTracer *trc)
if (statics->matchesInput) if (statics->matchesInput)
MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics->matchesInput), MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics->matchesInput),
"RegExpStatics::AutoRooter matchesInput"); "RegExpStatics::AutoRooter matchesInput");
if (statics->lazySource)
MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics->lazySource),
"RegExpStatics::AutoRooter lazySource");
if (statics->pendingInput) if (statics->pendingInput)
MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics->pendingInput), MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics->pendingInput),
"RegExpStatics::AutoRooter pendingInput"); "RegExpStatics::AutoRooter pendingInput");
if (statics->regexp.initialized())
statics->regexp->trace(trc);
} }
void void

View File

@ -100,12 +100,6 @@ RegExpObject::setSticky(bool enabled)
setSlot(STICKY_FLAG_SLOT, BooleanValue(enabled)); setSlot(STICKY_FLAG_SLOT, BooleanValue(enabled));
} }
inline void
RegExpShared::writeBarrierPre()
{
JSString::writeBarrierPre(source);
}
/* This function should be deleted once bad Android platforms phase out. See bug 604774. */ /* This function should be deleted once bad Android platforms phase out. See bug 604774. */
inline bool inline bool
RegExpShared::isJITRuntimeEnabled(JSContext *cx) RegExpShared::isJITRuntimeEnabled(JSContext *cx)
@ -170,32 +164,18 @@ RegExpGuard::release()
} }
} }
RegExpHeapGuard::RegExpHeapGuard(RegExpShared &re)
{
init(re);
}
RegExpHeapGuard::~RegExpHeapGuard()
{
release();
}
inline void inline void
RegExpHeapGuard::init(RegExpShared &re) MatchPairs::checkAgainst(size_t inputLength)
{ {
JS_ASSERT(!initialized()); #ifdef DEBUG
re_ = &re; for (size_t i = 0; i < pairCount_; i++) {
re_->incRef(); const MatchPair &p = pair(i);
} JS_ASSERT(p.check());
if (p.isUndefined())
inline void continue;
RegExpHeapGuard::release() JS_ASSERT(size_t(p.limit) <= inputLength);
{
if (re_) {
re_->writeBarrierPre();
re_->decRef();
re_ = NULL;
} }
#endif
} }
} /* namespace js */ } /* namespace js */

View File

@ -159,20 +159,6 @@ MatchPairs::displace(size_t disp)
} }
} }
inline void
MatchPairs::checkAgainst(size_t inputLength)
{
#if DEBUG
for (size_t i = 0; i < pairCount_; i++) {
const MatchPair &p = pair(i);
JS_ASSERT(p.check());
if (p.isUndefined())
continue;
JS_ASSERT(size_t(p.limit) <= inputLength);
}
#endif
}
bool bool
ScopedMatchPairs::allocOrExpandArray(size_t pairCount) ScopedMatchPairs::allocOrExpandArray(size_t pairCount)
{ {
@ -312,7 +298,7 @@ RegExpObject::assignInitialShape(JSContext *cx)
return self->addDataProperty(cx, cx->names().sticky, STICKY_FLAG_SLOT, attrs); return self->addDataProperty(cx, cx->names().sticky, STICKY_FLAG_SLOT, attrs);
} }
inline bool bool
RegExpObject::init(JSContext *cx, HandleAtom source, RegExpFlag flags) RegExpObject::init(JSContext *cx, HandleAtom source, RegExpFlag flags)
{ {
Rooted<RegExpObject *> self(cx, this); Rooted<RegExpObject *> self(cx, this);
@ -645,17 +631,6 @@ RegExpCompartment::RegExpCompartment(JSRuntime *rt)
RegExpCompartment::~RegExpCompartment() RegExpCompartment::~RegExpCompartment()
{ {
JS_ASSERT(map_.empty()); JS_ASSERT(map_.empty());
/*
* RegExpStatics may have prevented a single RegExpShared from
* being collected during RegExpCompartment::sweep().
*/
for (PendingSet::Enum e(inUse_); !e.empty(); e.popFront()) {
RegExpShared *shared = e.front();
JS_ASSERT(shared->activeUseCount == 0);
js_delete(shared);
e.removeFront();
}
JS_ASSERT(inUse_.empty()); JS_ASSERT(inUse_.empty());
} }
@ -691,7 +666,7 @@ RegExpCompartment::sweep(JSRuntime *rt)
} }
} }
inline bool bool
RegExpCompartment::get(JSContext *cx, JSAtom *source, RegExpFlag flags, RegExpGuard *g) RegExpCompartment::get(JSContext *cx, JSAtom *source, RegExpFlag flags, RegExpGuard *g)
{ {
Key key(source, flags); Key key(source, flags);

View File

@ -109,6 +109,7 @@ CloneRegExpObject(JSContext *cx, JSObject *obj, JSObject *proto);
class RegExpShared class RegExpShared
{ {
friend class RegExpCompartment; friend class RegExpCompartment;
friend class RegExpStatics;
friend class RegExpGuard; friend class RegExpGuard;
typedef frontend::TokenStream TokenStream; typedef frontend::TokenStream TokenStream;
@ -124,7 +125,7 @@ class RegExpShared
/* /*
* Source to the RegExp, for lazy compilation. * Source to the RegExp, for lazy compilation.
* The source must be rooted while activeUseCount is non-zero * The source must be rooted while activeUseCount is non-zero
* via RegExpGuard, RegExpHeapGuard, or explicit calls to trace(). * via RegExpGuard or explicit calls to trace().
*/ */
JSAtom * source; JSAtom * source;
@ -156,7 +157,6 @@ class RegExpShared
void trace(JSTracer *trc) { void trace(JSTracer *trc) {
MarkStringUnbarriered(trc, &source, "regexpshared source"); MarkStringUnbarriered(trc, &source, "regexpshared source");
} }
inline void writeBarrierPre();
/* Static functions to expose some Yarr logic. */ /* Static functions to expose some Yarr logic. */
static inline bool isJITRuntimeEnabled(JSContext *cx); static inline bool isJITRuntimeEnabled(JSContext *cx);
@ -233,34 +233,6 @@ class RegExpGuard
RegExpShared &operator*() { return *re(); } RegExpShared &operator*() { return *re(); }
}; };
/* Equivalent of RegExpGuard, heap-allocated, with explicit tracing. */
class RegExpHeapGuard
{
RegExpShared *re_;
RegExpHeapGuard(const RegExpGuard &) MOZ_DELETE;
void operator=(const RegExpHeapGuard &) MOZ_DELETE;
public:
RegExpHeapGuard() : re_(NULL) { }
inline RegExpHeapGuard(RegExpShared &re);
inline ~RegExpHeapGuard();
public:
inline void init(RegExpShared &re);
inline void release();
void trace(JSTracer *trc) {
if (initialized())
re_->trace(trc);
}
bool initialized() const { return !!re_; }
RegExpShared *re() const { JS_ASSERT(initialized()); return re_; }
RegExpShared *operator->() { return re(); }
RegExpShared &operator*() { return *re(); }
};
class RegExpCompartment class RegExpCompartment
{ {
struct Key { struct Key {
@ -384,7 +356,7 @@ class RegExpObject : public JSObject
*/ */
UnrootedShape assignInitialShape(JSContext *cx); UnrootedShape assignInitialShape(JSContext *cx);
inline bool init(JSContext *cx, HandleAtom source, RegExpFlag flags); bool init(JSContext *cx, HandleAtom source, RegExpFlag flags);
/* /*
* Precondition: the syntax for |source| has already been validated. * Precondition: the syntax for |source| has already been validated.

View File

@ -21,16 +21,21 @@ class RegExpStatics
VectorMatchPairs matches; VectorMatchPairs matches;
HeapPtr<JSLinearString> matchesInput; HeapPtr<JSLinearString> matchesInput;
/* The previous RegExp input, used to resolve lazy state. */ /*
RegExpHeapGuard regexp; * The previous RegExp input, used to resolve lazy state.
size_t lastIndex; * A raw RegExpShared cannot be stored because it may be in
* a different compartment via evalcx().
*/
HeapPtr<JSAtom> lazySource;
RegExpFlag lazyFlags;
size_t lazyIndex;
/* The latest RegExp input, set before execution. */ /* The latest RegExp input, set before execution. */
HeapPtr<JSString> pendingInput; HeapPtr<JSString> pendingInput;
RegExpFlag flags; RegExpFlag flags;
/* /*
* If true, |matchesInput|, |regexp|, and |lastIndex| may be used * If true, |matchesInput| and the |lazy*| fields may be used
* to replay the last executed RegExp, and |matches| is invalid. * to replay the last executed RegExp, and |matches| is invalid.
*/ */
bool pendingLazyEvaluation; bool pendingLazyEvaluation;
@ -118,12 +123,12 @@ class RegExpStatics
* Changes to this function must also be reflected in * Changes to this function must also be reflected in
* RegExpStatics::AutoRooter::trace(). * RegExpStatics::AutoRooter::trace().
*/ */
if (pendingInput)
MarkString(trc, &pendingInput, "res->pendingInput");
if (matchesInput) if (matchesInput)
MarkString(trc, &matchesInput, "res->matchesInput"); MarkString(trc, &matchesInput, "res->matchesInput");
if (regexp.initialized()) if (lazySource)
regexp->trace(trc); MarkString(trc, &lazySource, "res->lazySource");
if (pendingInput)
MarkString(trc, &pendingInput, "res->pendingInput");
} }
/* Value creators. */ /* Value creators. */
@ -393,20 +398,16 @@ RegExpStatics::copyTo(RegExpStatics &dst)
if (!pendingLazyEvaluation) if (!pendingLazyEvaluation)
dst.matches.initArrayFrom(matches); dst.matches.initArrayFrom(matches);
if (regexp.initialized())
dst.regexp.init(*regexp);
else
dst.regexp.release();
dst.matchesInput = matchesInput; dst.matchesInput = matchesInput;
dst.lastIndex = lastIndex; dst.lazySource = lazySource;
dst.lazyFlags = lazyFlags;
dst.lazyIndex = lazyIndex;
dst.pendingInput = pendingInput; dst.pendingInput = pendingInput;
dst.flags = flags; dst.flags = flags;
dst.pendingLazyEvaluation = pendingLazyEvaluation; dst.pendingLazyEvaluation = pendingLazyEvaluation;
JS_ASSERT_IF(pendingLazyEvaluation, regexp.initialized()); JS_ASSERT_IF(pendingLazyEvaluation, lazySource);
JS_ASSERT_IF(pendingLazyEvaluation, matchesInput); JS_ASSERT_IF(pendingLazyEvaluation, matchesInput);
JS_ASSERT(regexp.initialized() == dst.regexp.initialized());
} }
inline void inline void
@ -436,11 +437,10 @@ RegExpStatics::updateLazily(JSContext *cx, JSLinearString *input,
BarrieredSetPair<JSString, JSLinearString>(cx->zone(), BarrieredSetPair<JSString, JSLinearString>(cx->zone(),
pendingInput, input, pendingInput, input,
matchesInput, input); matchesInput, input);
if (regexp.initialized())
regexp.release();
regexp.init(*shared);
this->lastIndex = lastIndex; lazySource = shared->source;
lazyFlags = shared->flags;
lazyIndex = lastIndex;
pendingLazyEvaluation = true; pendingLazyEvaluation = true;
} }
@ -452,8 +452,8 @@ RegExpStatics::updateFromMatchPairs(JSContext *cx, JSLinearString *input, MatchP
/* Unset all lazy state. */ /* Unset all lazy state. */
pendingLazyEvaluation = false; pendingLazyEvaluation = false;
this->regexp.release(); this->lazySource = NULL;
this->lastIndex = size_t(-1); this->lazyIndex = size_t(-1);
BarrieredSetPair<JSString, JSLinearString>(cx->zone(), BarrieredSetPair<JSString, JSLinearString>(cx->zone(),
pendingInput, input, pendingInput, input,
@ -474,8 +474,9 @@ RegExpStatics::clear()
matches.forgetArray(); matches.forgetArray();
matchesInput = NULL; matchesInput = NULL;
regexp.release(); lazySource = NULL;
lastIndex = size_t(-1); lazyFlags = RegExpFlag(0);
lazyIndex = size_t(-1);
pendingInput = NULL; pendingInput = NULL;
flags = RegExpFlag(0); flags = RegExpFlag(0);
pendingLazyEvaluation = false; pendingLazyEvaluation = false;
@ -536,9 +537,9 @@ RegExpStatics::checkInvariants()
{ {
#ifdef DEBUG #ifdef DEBUG
if (pendingLazyEvaluation) { if (pendingLazyEvaluation) {
JS_ASSERT(regexp.initialized()); JS_ASSERT(lazySource);
JS_ASSERT(pendingInput); JS_ASSERT(matchesInput);
JS_ASSERT(lastIndex != size_t(-1)); JS_ASSERT(lazyIndex != size_t(-1));
return; return;
} }

View File

@ -74,9 +74,14 @@ RegExpStatics::executeLazy(JSContext *cx)
if (!pendingLazyEvaluation) if (!pendingLazyEvaluation)
return true; return true;
JS_ASSERT(regexp.initialized()); JS_ASSERT(lazySource);
JS_ASSERT(matchesInput); JS_ASSERT(matchesInput);
JS_ASSERT(lastIndex != size_t(-1)); JS_ASSERT(lazyIndex != size_t(-1));
/* Retrieve or create the RegExpShared in this compartment. */
RegExpGuard g(cx);
if (!cx->compartment->regExps.get(cx, lazySource, lazyFlags, &g))
return false;
/* /*
* It is not necessary to call aboutToWrite(): evaluation of * It is not necessary to call aboutToWrite(): evaluation of
@ -87,7 +92,7 @@ RegExpStatics::executeLazy(JSContext *cx)
StableCharPtr chars(matchesInput->chars(), length); StableCharPtr chars(matchesInput->chars(), length);
/* Execute the full regular expression. */ /* Execute the full regular expression. */
RegExpRunStatus status = regexp->execute(cx, chars, length, &this->lastIndex, this->matches); RegExpRunStatus status = g->execute(cx, chars, length, &this->lazyIndex, this->matches);
if (status == RegExpRunStatus_Error) if (status == RegExpRunStatus_Error)
return false; return false;
@ -99,8 +104,8 @@ RegExpStatics::executeLazy(JSContext *cx)
/* Unset lazy state and remove rooted values that now have no use. */ /* Unset lazy state and remove rooted values that now have no use. */
pendingLazyEvaluation = false; pendingLazyEvaluation = false;
regexp.release(); lazySource = NULL;
lastIndex = size_t(-1); lazyIndex = size_t(-1);
return true; return true;
} }