mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1010441 - Keep RegExpShared and RegExp jitcode around when preserving jitcode in a compartment, r=billm.
This commit is contained in:
parent
566a392ad9
commit
fe7b4baa60
@ -569,7 +569,7 @@ class AutoScriptVector : public AutoVectorRooter<JSScript *>
|
||||
};
|
||||
|
||||
/*
|
||||
* Cutsom rooting behavior for internal and external clients.
|
||||
* Custom rooting behavior for internal and external clients.
|
||||
*/
|
||||
class JS_PUBLIC_API(CustomAutoRooter) : private AutoGCRooter
|
||||
{
|
||||
|
@ -645,8 +645,6 @@ JSCompartment::clearTables()
|
||||
{
|
||||
global_ = nullptr;
|
||||
|
||||
regExps.clearTables();
|
||||
|
||||
// No scripts should have run in this compartment. This is used when
|
||||
// merging a compartment that has been used off thread into another
|
||||
// compartment and zone.
|
||||
@ -658,6 +656,7 @@ JSCompartment::clearTables()
|
||||
JS_ASSERT(!debugScopes);
|
||||
JS_ASSERT(!gcWeakMapList);
|
||||
JS_ASSERT(enumerators->next() == enumerators);
|
||||
JS_ASSERT(regExps.empty());
|
||||
|
||||
types.clearTables();
|
||||
if (baseShapes.initialized())
|
||||
|
@ -89,7 +89,7 @@ RegExpObjectBuilder::build(HandleAtom source, RegExpShared &shared)
|
||||
if (!reobj_->init(cx, source, shared.getFlags()))
|
||||
return nullptr;
|
||||
|
||||
reobj_->setShared(cx, shared);
|
||||
reobj_->setShared(shared);
|
||||
return reobj_;
|
||||
}
|
||||
|
||||
@ -102,6 +102,14 @@ RegExpObjectBuilder::build(HandleAtom source, RegExpFlag flags)
|
||||
return reobj_->init(cx, source, flags) ? reobj_.get() : nullptr;
|
||||
}
|
||||
|
||||
static inline void
|
||||
MaybeTraceRegExpShared(JSContext *cx, RegExpShared *shared)
|
||||
{
|
||||
Zone *zone = cx->zone();
|
||||
if (zone->needsBarrier())
|
||||
shared->trace(zone->barrierTracer());
|
||||
}
|
||||
|
||||
RegExpObject *
|
||||
RegExpObjectBuilder::clone(Handle<RegExpObject *> other)
|
||||
{
|
||||
@ -127,9 +135,12 @@ RegExpObjectBuilder::clone(Handle<RegExpObject *> other)
|
||||
}
|
||||
|
||||
RegExpGuard g(cx);
|
||||
if (!other->getShared(cx, &g))
|
||||
if (!other->getShared(cx->asJSContext(), &g))
|
||||
return nullptr;
|
||||
g.re()->prepareForUse(cx);
|
||||
|
||||
// Copying a RegExpShared from one object to another requires a read
|
||||
// barrier, as the shared pointer in an object may be weak.
|
||||
MaybeTraceRegExpShared(cx->asJSContext(), g.re());
|
||||
|
||||
Rooted<JSAtom *> source(cx, other->getSource());
|
||||
return build(source, *g);
|
||||
@ -217,16 +228,29 @@ VectorMatchPairs::allocOrExpandArray(size_t pairCount)
|
||||
|
||||
/* RegExpObject */
|
||||
|
||||
static void
|
||||
regexp_trace(JSTracer *trc, JSObject *obj)
|
||||
/* static */ void
|
||||
RegExpObject::trace(JSTracer *trc, JSObject *obj)
|
||||
{
|
||||
/*
|
||||
* We have to check both conditions, since:
|
||||
* 1. During TraceRuntime, isHeapBusy() is true
|
||||
* 2. When a write barrier executes, IS_GC_MARKING_TRACER is true.
|
||||
*/
|
||||
if (trc->runtime()->isHeapBusy() && IS_GC_MARKING_TRACER(trc))
|
||||
RegExpShared *shared = obj->as<RegExpObject>().maybeShared();
|
||||
if (!shared)
|
||||
return;
|
||||
|
||||
// When tracing through the object normally, we have the option of
|
||||
// unlinking the object from its RegExpShared so that the RegExpShared may
|
||||
// be collected. To detect this we need to test all the following
|
||||
// conditions, since:
|
||||
// 1. During TraceRuntime, isHeapBusy() is true, but the tracer might not
|
||||
// be a marking tracer.
|
||||
// 2. When a write barrier executes, IS_GC_MARKING_TRACER is true, but
|
||||
// isHeapBusy() will be false.
|
||||
if (trc->runtime()->isHeapBusy() &&
|
||||
IS_GC_MARKING_TRACER(trc) &&
|
||||
!obj->tenuredZone()->isPreservingCode())
|
||||
{
|
||||
obj->setPrivate(nullptr);
|
||||
} else {
|
||||
shared->trace(trc);
|
||||
}
|
||||
}
|
||||
|
||||
const Class RegExpObject::class_ = {
|
||||
@ -245,7 +269,7 @@ const Class RegExpObject::class_ = {
|
||||
nullptr, /* call */
|
||||
nullptr, /* hasInstance */
|
||||
nullptr, /* construct */
|
||||
regexp_trace
|
||||
RegExpObject::trace
|
||||
};
|
||||
|
||||
RegExpObject *
|
||||
@ -294,7 +318,7 @@ RegExpObject::createNoStatics(ExclusiveContext *cx, HandleAtom source, RegExpFla
|
||||
}
|
||||
|
||||
bool
|
||||
RegExpObject::createShared(ExclusiveContext *cx, RegExpGuard *g)
|
||||
RegExpObject::createShared(JSContext *cx, RegExpGuard *g)
|
||||
{
|
||||
Rooted<RegExpObject*> self(cx, this);
|
||||
|
||||
@ -302,7 +326,7 @@ RegExpObject::createShared(ExclusiveContext *cx, RegExpGuard *g)
|
||||
if (!cx->compartment()->regExps.get(cx, getSource(), getFlags(), g))
|
||||
return false;
|
||||
|
||||
self->setShared(cx, **g);
|
||||
self->setShared(**g);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -400,9 +424,8 @@ RegExpObject::toString(JSContext *cx) const
|
||||
|
||||
/* RegExpShared */
|
||||
|
||||
RegExpShared::RegExpShared(JSAtom *source, RegExpFlag flags, uint64_t gcNumber)
|
||||
: source(source), flags(flags), parenCount(0), canStringMatch(false),
|
||||
activeUseCount(0), gcNumberWhenUsed(gcNumber)
|
||||
RegExpShared::RegExpShared(JSAtom *source, RegExpFlag flags)
|
||||
: source(source), flags(flags), parenCount(0), canStringMatch(false), marked_(false)
|
||||
{
|
||||
#ifdef JS_YARR
|
||||
bytecode = nullptr;
|
||||
@ -426,6 +449,21 @@ RegExpShared::~RegExpShared()
|
||||
js_delete(tables[i]);
|
||||
}
|
||||
|
||||
void
|
||||
RegExpShared::trace(JSTracer *trc)
|
||||
{
|
||||
if (IS_GC_MARKING_TRACER(trc))
|
||||
marked_ = true;
|
||||
|
||||
if (source)
|
||||
MarkString(trc, &source, "RegExpShared source");
|
||||
|
||||
#if !defined(JS_YARR) && defined(JS_ION)
|
||||
if (jitCode)
|
||||
MarkJitCode(trc, &jitCode, "RegExpShared code");
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef JS_YARR
|
||||
|
||||
void
|
||||
@ -854,13 +892,19 @@ RegExpShared::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
/* RegExpCompartment */
|
||||
|
||||
RegExpCompartment::RegExpCompartment(JSRuntime *rt)
|
||||
: map_(rt), inUse_(rt), matchResultTemplateObject_(nullptr)
|
||||
: set_(rt), matchResultTemplateObject_(nullptr)
|
||||
{}
|
||||
|
||||
RegExpCompartment::~RegExpCompartment()
|
||||
{
|
||||
JS_ASSERT_IF(map_.initialized(), map_.empty());
|
||||
JS_ASSERT_IF(inUse_.initialized(), inUse_.empty());
|
||||
// Because of stray mark bits being set (see RegExpCompartment::sweep)
|
||||
// there might still be RegExpShared instances which haven't been deleted.
|
||||
if (set_.initialized()) {
|
||||
for (Set::Enum e(set_); !e.empty(); e.popFront()) {
|
||||
RegExpShared *shared = e.front();
|
||||
js_delete(shared);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSObject *
|
||||
@ -900,7 +944,7 @@ RegExpCompartment::createMatchResultTemplateObject(JSContext *cx)
|
||||
bool
|
||||
RegExpCompartment::init(JSContext *cx)
|
||||
{
|
||||
if (!map_.init(0) || !inUse_.init(0)) {
|
||||
if (!set_.init(0)) {
|
||||
if (cx)
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
@ -909,20 +953,29 @@ RegExpCompartment::init(JSContext *cx)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* See the comment on RegExpShared lifetime in RegExpObject.h. */
|
||||
void
|
||||
RegExpCompartment::sweep(JSRuntime *rt)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
for (Map::Range r = map_.all(); !r.empty(); r.popFront())
|
||||
JS_ASSERT(inUse_.has(r.front().value()));
|
||||
#endif
|
||||
|
||||
map_.clear();
|
||||
|
||||
for (PendingSet::Enum e(inUse_); !e.empty(); e.popFront()) {
|
||||
for (Set::Enum e(set_); !e.empty(); e.popFront()) {
|
||||
RegExpShared *shared = e.front();
|
||||
if (shared->activeUseCount == 0 && shared->gcNumberWhenUsed < rt->gc.startNumber) {
|
||||
|
||||
// Sometimes RegExpShared instances are marked without the
|
||||
// compartment being subsequently cleared. This can happen if a GC is
|
||||
// restarted while in progress (i.e. performing a full GC in the
|
||||
// middle of an incremental GC) or if a RegExpShared referenced via the
|
||||
// stack is traced but is not in a zone being collected.
|
||||
//
|
||||
// Because of this we only treat the marked_ bit as a hint, and destroy
|
||||
// the RegExpShared if it was accidentally marked earlier but wasn't
|
||||
// marked by the current trace.
|
||||
bool keep = shared->marked() && !IsStringAboutToBeFinalized(shared->source.unsafeGet());
|
||||
#if !defined(JS_YARR) && defined(JS_ION)
|
||||
if (keep && shared->jitCode)
|
||||
keep = !IsJitCodeAboutToBeFinalized(shared->jitCode.unsafeGet());
|
||||
#endif
|
||||
if (keep) {
|
||||
shared->clearMarked();
|
||||
} else {
|
||||
js_delete(shared);
|
||||
e.removeFront();
|
||||
}
|
||||
@ -935,42 +988,32 @@ RegExpCompartment::sweep(JSRuntime *rt)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RegExpCompartment::clearTables()
|
||||
{
|
||||
JS_ASSERT(inUse_.empty());
|
||||
map_.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
RegExpCompartment::get(ExclusiveContext *cx, JSAtom *source, RegExpFlag flags, RegExpGuard *g)
|
||||
RegExpCompartment::get(JSContext *cx, JSAtom *source, RegExpFlag flags, RegExpGuard *g)
|
||||
{
|
||||
Key key(source, flags);
|
||||
Map::AddPtr p = map_.lookupForAdd(key);
|
||||
Set::AddPtr p = set_.lookupForAdd(key);
|
||||
if (p) {
|
||||
g->init(*p->value());
|
||||
// Trigger a read barrier on existing RegExpShared instances fetched
|
||||
// from the table (which only holds weak references).
|
||||
MaybeTraceRegExpShared(cx, *p);
|
||||
|
||||
g->init(**p);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t gcNumber = cx->zone()->gcNumber();
|
||||
ScopedJSDeletePtr<RegExpShared> shared(cx->new_<RegExpShared>(source, flags, gcNumber));
|
||||
ScopedJSDeletePtr<RegExpShared> shared(cx->new_<RegExpShared>(source, flags));
|
||||
if (!shared)
|
||||
return false;
|
||||
|
||||
/* Add to RegExpShared sharing hashmap. */
|
||||
if (!map_.add(p, key, shared)) {
|
||||
if (!set_.add(p, shared)) {
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add to list of all RegExpShared objects in this RegExpCompartment. */
|
||||
if (!inUse_.put(shared)) {
|
||||
map_.remove(key);
|
||||
js_ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
// Trace RegExpShared instances created during an incremental GC.
|
||||
MaybeTraceRegExpShared(cx, shared);
|
||||
|
||||
/* Since error deletes |shared|, only guard |shared| on success. */
|
||||
g->init(*shared.forget());
|
||||
return true;
|
||||
}
|
||||
@ -989,9 +1032,8 @@ size_t
|
||||
RegExpCompartment::sizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf)
|
||||
{
|
||||
size_t n = 0;
|
||||
n += map_.sizeOfExcludingThis(mallocSizeOf);
|
||||
n += inUse_.sizeOfExcludingThis(mallocSizeOf);
|
||||
for (PendingSet::Enum e(inUse_); !e.empty(); e.popFront()) {
|
||||
n += set_.sizeOfExcludingThis(mallocSizeOf);
|
||||
for (Set::Enum e(set_); !e.empty(); e.popFront()) {
|
||||
RegExpShared *shared = e.front();
|
||||
n += shared->sizeOfIncludingThis(mallocSizeOf);
|
||||
}
|
||||
|
@ -95,37 +95,19 @@ CloneRegExpObject(JSContext *cx, JSObject *obj);
|
||||
* A RegExpShared is the compiled representation of a regexp. A RegExpShared is
|
||||
* potentially pointed to by multiple RegExpObjects. Additionally, C++ code may
|
||||
* have pointers to RegExpShareds on the stack. The RegExpShareds are kept in a
|
||||
* cache so that they can be reused when compiling the same regex string.
|
||||
* table so that they can be reused when compiling the same regex string.
|
||||
*
|
||||
* During a GC, the trace hook for RegExpObject clears any pointers to
|
||||
* RegExpShareds so that there will be no dangling pointers when they are
|
||||
* deleted. However, some RegExpShareds are not deleted:
|
||||
*
|
||||
* 1. Any RegExpShared with pointers from the C++ stack is not deleted.
|
||||
* 2. Any RegExpShared which has been embedded into jitcode is not deleted.
|
||||
* This rarely comes into play, as jitcode is usually purged before the
|
||||
* RegExpShared are sweeped.
|
||||
* 3. Any RegExpShared that was installed in a RegExpObject during an
|
||||
* incremental GC is not deleted. This is because the RegExpObject may have
|
||||
* been traced through before the new RegExpShared was installed, in which
|
||||
* case deleting the RegExpShared would turn the RegExpObject's reference
|
||||
* into a dangling pointer
|
||||
*
|
||||
* The activeUseCount and gcNumberWhenUsed fields are used to track these
|
||||
* conditions.
|
||||
*
|
||||
* There are two tables used to track RegExpShareds. map_ implements the cache
|
||||
* and is cleared on every GC. inUse_ logically owns all RegExpShareds in the
|
||||
* compartment and attempts to delete all RegExpShareds that aren't kept alive
|
||||
* by the above conditions on every GC sweep phase. It is necessary to use two
|
||||
* separate tables since map_ *must* be fully cleared on each GC since the Key
|
||||
* points to a JSAtom that can become garbage.
|
||||
* During a GC, RegExpShared instances are marked and swept like GC things.
|
||||
* Usually, RegExpObjects clear their pointers to their RegExpShareds rather
|
||||
* than explicitly tracing them, so that the RegExpShared and any jitcode can
|
||||
* be reclaimed quicker. However, the RegExpShareds are traced through by
|
||||
* objects when we are preserving jitcode in their zone, to avoid the same
|
||||
* recompilation inefficiencies as normal Ion and baseline compilation.
|
||||
*/
|
||||
class RegExpShared
|
||||
{
|
||||
friend class RegExpCompartment;
|
||||
friend class RegExpStatics;
|
||||
friend class RegExpGuard;
|
||||
|
||||
typedef frontend::TokenStream TokenStream;
|
||||
|
||||
@ -140,16 +122,13 @@ class RegExpShared
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Source to the RegExp, for lazy compilation.
|
||||
* The source must be rooted while activeUseCount is non-zero
|
||||
* via RegExpGuard or explicit calls to trace().
|
||||
*/
|
||||
JSAtom * source;
|
||||
/* Source to the RegExp, for lazy compilation. */
|
||||
HeapPtrAtom source;
|
||||
|
||||
RegExpFlag flags;
|
||||
size_t parenCount;
|
||||
bool canStringMatch;
|
||||
bool marked_;
|
||||
|
||||
#ifdef JS_YARR
|
||||
|
||||
@ -171,10 +150,6 @@ class RegExpShared
|
||||
// Tables referenced by JIT code.
|
||||
Vector<uint8_t *, 0, SystemAllocPolicy> tables;
|
||||
|
||||
/* Lifetime-preserving variables: see class-level comment above. */
|
||||
size_t activeUseCount;
|
||||
uint64_t gcNumberWhenUsed;
|
||||
|
||||
/* Internal functions. */
|
||||
bool compile(JSContext *cx, bool matchOnly, const jschar *sampleChars, size_t sampleLength);
|
||||
bool compile(JSContext *cx, HandleAtom pattern, bool matchOnly, const jschar *sampleChars, size_t sampleLength);
|
||||
@ -186,7 +161,7 @@ class RegExpShared
|
||||
#endif
|
||||
|
||||
public:
|
||||
RegExpShared(JSAtom *source, RegExpFlag flags, uint64_t gcNumber);
|
||||
RegExpShared(JSAtom *source, RegExpFlag flags);
|
||||
~RegExpShared();
|
||||
|
||||
#ifdef JS_YARR
|
||||
@ -208,18 +183,6 @@ class RegExpShared
|
||||
static bool checkSyntax(ExclusiveContext *cx, TokenStream *tokenStream, JSLinearString *source);
|
||||
#endif // JS_YARR
|
||||
|
||||
/* Called when a RegExpShared is installed into a RegExpObject. */
|
||||
void prepareForUse(ExclusiveContext *cx) {
|
||||
gcNumberWhenUsed = cx->zone()->gcNumber();
|
||||
JSString::writeBarrierPre(source);
|
||||
#ifndef JS_YARR
|
||||
#ifdef JS_ION
|
||||
if (jitCode)
|
||||
jit::JitCode::writeBarrierPre(jitCode);
|
||||
#endif
|
||||
#endif // !JS_YARR
|
||||
}
|
||||
|
||||
/* Primary interface: run this regular expression on the given string. */
|
||||
RegExpRunStatus execute(JSContext *cx, const jschar *chars, size_t length,
|
||||
size_t *lastIndex, MatchPairs &matches);
|
||||
@ -242,12 +205,10 @@ class RegExpShared
|
||||
return parenCount;
|
||||
}
|
||||
|
||||
void incRef() { activeUseCount++; }
|
||||
void decRef() { JS_ASSERT(activeUseCount > 0); activeUseCount--; }
|
||||
|
||||
/* Accounts for the "0" (whole match) pair. */
|
||||
size_t pairCount() const { return getParenCount() + 1; }
|
||||
|
||||
JSAtom *getSource() const { return source; }
|
||||
RegExpFlag getFlags() const { return flags; }
|
||||
bool ignoreCase() const { return flags & IgnoreCaseFlag; }
|
||||
bool global() const { return flags & GlobalFlag; }
|
||||
@ -289,6 +250,11 @@ class RegExpShared
|
||||
|
||||
#endif // JS_YARR
|
||||
|
||||
void trace(JSTracer *trc);
|
||||
|
||||
bool marked() const { return marked_; }
|
||||
void clearMarked() { JS_ASSERT(marked_); marked_ = false; }
|
||||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf);
|
||||
};
|
||||
|
||||
@ -322,31 +288,15 @@ class RegExpGuard : public JS::CustomAutoRooter
|
||||
void init(RegExpShared &re) {
|
||||
JS_ASSERT(!initialized());
|
||||
re_ = &re;
|
||||
re_->incRef();
|
||||
}
|
||||
|
||||
void release() {
|
||||
if (re_) {
|
||||
re_->decRef();
|
||||
re_ = nullptr;
|
||||
}
|
||||
re_ = nullptr;
|
||||
}
|
||||
|
||||
virtual void trace(JSTracer *trc) {
|
||||
if (!re_)
|
||||
return;
|
||||
if (re_->source) {
|
||||
MarkStringRoot(trc, reinterpret_cast<JSString**>(&re_->source),
|
||||
"RegExpGuard source");
|
||||
}
|
||||
#ifndef JS_YARR
|
||||
#ifdef JS_ION
|
||||
if (re_->jitCode) {
|
||||
MarkJitCodeRoot(trc, reinterpret_cast<jit::JitCode**>(&re_->jitCode),
|
||||
"RegExpGuard code");
|
||||
}
|
||||
#endif
|
||||
#endif // !JS_YARR
|
||||
if (re_)
|
||||
re_->trace(trc);
|
||||
}
|
||||
|
||||
bool initialized() const { return !!re_; }
|
||||
@ -365,6 +315,9 @@ class RegExpCompartment
|
||||
Key(JSAtom *atom, RegExpFlag flag)
|
||||
: atom(atom), flag(flag)
|
||||
{ }
|
||||
Key(RegExpShared *shared)
|
||||
: atom(shared->getSource()), flag(shared->getFlags())
|
||||
{ }
|
||||
|
||||
typedef Key Lookup;
|
||||
static HashNumber hash(const Lookup &l) {
|
||||
@ -375,20 +328,12 @@ class RegExpCompartment
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Cache to reuse RegExpShareds with the same source/flags/etc. The cache
|
||||
* is entirely cleared on each GC.
|
||||
*/
|
||||
typedef HashMap<Key, RegExpShared *, Key, RuntimeAllocPolicy> Map;
|
||||
Map map_;
|
||||
|
||||
/*
|
||||
* The set of all RegExpShareds in the compartment. On every GC, every
|
||||
* RegExpShared that is not actively being used is deleted and removed from
|
||||
* the set.
|
||||
* RegExpShared that was not marked is deleted and removed from the set.
|
||||
*/
|
||||
typedef HashSet<RegExpShared *, DefaultHasher<RegExpShared*>, RuntimeAllocPolicy> PendingSet;
|
||||
PendingSet inUse_;
|
||||
typedef HashSet<RegExpShared *, Key, RuntimeAllocPolicy> Set;
|
||||
Set set_;
|
||||
|
||||
/*
|
||||
* This is the template object where the result of re.exec() is based on,
|
||||
@ -405,9 +350,10 @@ class RegExpCompartment
|
||||
|
||||
bool init(JSContext *cx);
|
||||
void sweep(JSRuntime *rt);
|
||||
void clearTables();
|
||||
|
||||
bool get(ExclusiveContext *cx, JSAtom *source, RegExpFlag flags, RegExpGuard *g);
|
||||
bool empty() { return set_.empty(); }
|
||||
|
||||
bool get(JSContext *cx, JSAtom *source, RegExpFlag flags, RegExpGuard *g);
|
||||
|
||||
/* Like 'get', but compile 'maybeOpt' (if non-null). */
|
||||
bool get(JSContext *cx, HandleAtom source, JSString *maybeOpt, RegExpGuard *g);
|
||||
@ -512,7 +458,7 @@ class RegExpObject : public JSObject
|
||||
g->init(*maybeShared());
|
||||
}
|
||||
|
||||
bool getShared(ExclusiveContext *cx, RegExpGuard *g) {
|
||||
bool getShared(JSContext *cx, RegExpGuard *g) {
|
||||
if (RegExpShared *shared = maybeShared()) {
|
||||
g->init(*shared);
|
||||
return true;
|
||||
@ -520,11 +466,13 @@ class RegExpObject : public JSObject
|
||||
return createShared(cx, g);
|
||||
}
|
||||
|
||||
void setShared(ExclusiveContext *cx, RegExpShared &shared) {
|
||||
shared.prepareForUse(cx);
|
||||
void setShared(RegExpShared &shared) {
|
||||
JS_ASSERT(!maybeShared());
|
||||
JSObject::setPrivate(&shared);
|
||||
}
|
||||
|
||||
static void trace(JSTracer *trc, JSObject *obj);
|
||||
|
||||
private:
|
||||
friend class RegExpObjectBuilder;
|
||||
|
||||
@ -547,7 +495,7 @@ class RegExpObject : public JSObject
|
||||
* Precondition: the syntax for |source| has already been validated.
|
||||
* Side effect: sets the private field.
|
||||
*/
|
||||
bool createShared(ExclusiveContext *cx, RegExpGuard *g);
|
||||
bool createShared(JSContext *cx, RegExpGuard *g);
|
||||
RegExpShared *maybeShared() const {
|
||||
return static_cast<RegExpShared *>(JSObject::getPrivate());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user