Bug 979293 - Add a FrozenAtomSet to clarify how |permanentAtoms| works. r=bhackett.

This clarifies the two phases -- (a) initialization and (b) read-only use
-- that |permanentAtoms| goes through. It also gives some type-based protection
against potential misuse.
This commit is contained in:
Nicholas Nethercote
2015-02-25 19:11:28 -08:00
parent 4636a025ad
commit 5d2e8ade06
5 changed files with 60 additions and 20 deletions

View File

@@ -97,6 +97,10 @@ const char js_with_str[] = "with";
// which create a small number of atoms.
static const uint32_t JS_STRING_HASH_COUNT = 64;
AtomSet::Ptr js::FrozenAtomSet::readonlyThreadsafeLookup(const AtomSet::Lookup &l) const {
return mSet->readonlyThreadsafeLookup(l);
}
struct CommonNameInfo
{
const char *str;
@@ -110,6 +114,9 @@ JSRuntime::initializeAtoms(JSContext *cx)
if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT))
return false;
// |permanentAtoms| hasn't been created yet.
MOZ_ASSERT(!permanentAtoms);
if (parentRuntime) {
staticStrings = parentRuntime->staticStrings;
commonNames = parentRuntime->commonNames;
@@ -119,10 +126,6 @@ JSRuntime::initializeAtoms(JSContext *cx)
return true;
}
permanentAtoms = cx->new_<AtomSet>();
if (!permanentAtoms || !permanentAtoms->init(JS_STRING_HASH_COUNT))
return false;
staticStrings = cx->new_<StaticStrings>();
if (!staticStrings || !staticStrings->init(cx))
return false;
@@ -221,8 +224,8 @@ js::MarkPermanentAtoms(JSTracer *trc)
rt->staticStrings->trace(trc);
if (rt->permanentAtoms) {
for (AtomSet::Enum e(*rt->permanentAtoms); !e.empty(); e.popFront()) {
const AtomStateEntry &entry = e.front();
for (FrozenAtomSet::Range r(rt->permanentAtoms->all()); !r.empty(); r.popFront()) {
const AtomStateEntry &entry = r.front();
JSAtom *atom = entry.asPtr();
MarkPermanentAtom(trc, atom, "permanent_table");
@@ -264,21 +267,22 @@ JSRuntime::sweepAtoms()
}
bool
JSRuntime::transformToPermanentAtoms()
JSRuntime::transformToPermanentAtoms(JSContext *cx)
{
MOZ_ASSERT(!parentRuntime);
// All static strings were created as permanent atoms, now move the contents
// of the atoms table into permanentAtoms and mark each as permanent.
MOZ_ASSERT(permanentAtoms && permanentAtoms->empty());
MOZ_ASSERT(!permanentAtoms);
permanentAtoms = cx->new_<FrozenAtomSet>(atoms_); // takes ownership of atoms_
AtomSet *temp = atoms_;
atoms_ = permanentAtoms;
permanentAtoms = temp;
atoms_ = cx->new_<AtomSet>();
if (!atoms_ || !atoms_->init(JS_STRING_HASH_COUNT))
return false;
for (AtomSet::Enum e(*permanentAtoms); !e.empty(); e.popFront()) {
AtomStateEntry entry = e.front();
for (FrozenAtomSet::Range r(permanentAtoms->all()); !r.empty(); r.popFront()) {
AtomStateEntry entry = r.front();
JSAtom *atom = entry.asPtr();
atom->morphIntoPermanentAtom();
}
@@ -296,6 +300,7 @@ AtomIsInterned(JSContext *cx, JSAtom *atom)
AtomHasher::Lookup lookup(atom);
/* Likewise, permanent strings are considered to be interned. */
MOZ_ASSERT(cx->isPermanentAtomsInitialized());
AtomSet::Ptr p = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
if (p)
return true;
@@ -320,9 +325,16 @@ AtomizeAndCopyChars(ExclusiveContext *cx, const CharT *tbchars, size_t length, I
AtomHasher::Lookup lookup(tbchars, length);
AtomSet::Ptr pp = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
if (pp)
return pp->asPtr();
// Note: when this function is called while the permanent atoms table is
// being initialized (in initializeAtoms()), |permanentAtoms| is not yet
// initialized so this lookup is always skipped. Only once
// transformToPermanentAtoms() is called does |permanentAtoms| get
// initialized and then this lookup will go ahead.
if (cx->isPermanentAtomsInitialized()) {
AtomSet::Ptr pp = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
if (pp)
return pp->asPtr();
}
AutoLockForExclusiveAccess lock(cx);
@@ -377,6 +389,7 @@ js::AtomizeString(ExclusiveContext *cx, JSString *str,
AtomHasher::Lookup lookup(&atom);
/* Likewise, permanent atoms are always interned. */
MOZ_ASSERT(cx->isPermanentAtomsInitialized());
AtomSet::Ptr p = cx->permanentAtoms().readonlyThreadsafeLookup(lookup);
if (p)
return &atom;