Bug 1154950 - Share permanent atom and well-known symbol marking; r=sfink
authorTerrence Cole <terrence@mozilla.com>
Tue, 14 Apr 2015 13:28:46 -0700
changeset 240392 037b2e086aa60bb6259bc2498edca05e033a72d3
parent 240391 6f7ff9108025932601de3b1bee9412704b54af91
child 240393 fefff614bc04cdd388ada3f690b192c710fda218
push id28636
push userkwierso@gmail.com
push dateThu, 23 Apr 2015 00:16:12 +0000
treeherdermozilla-central@a5af73b32ac8 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssfink
bugs1154950
milestone40.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1154950 - Share permanent atom and well-known symbol marking; r=sfink
js/src/gc/Barrier.h
js/src/gc/Marking.cpp
js/src/gc/Marking.h
js/src/jsatom.cpp
js/src/vm/String.cpp
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -585,17 +585,18 @@ class ImmutableTenuredPtr
         return Handle<T>::fromMarkedLocation(&value);
     }
 
     void init(T ptr) {
         MOZ_ASSERT(ptr->isTenured());
         value = ptr;
     }
 
-    const T * address() { return &value; }
+    T get() const { return value; }
+    const T* address() { return &value; }
 };
 
 /*
  * A pre- and post-barriered heap pointer, for use inside the JS engine.
  *
  * Unlike HeapPtr<T>, it can be used in memory that is not managed by the GC,
  * i.e. in C++ containers.  It is, however, somewhat slower, so should only be
  * used in contexts where this ability is necessary.
--- a/js/src/gc/Marking.cpp
+++ b/js/src/gc/Marking.cpp
@@ -364,16 +364,38 @@ void
 js::TraceCrossCompartmentEdge(JSTracer* trc, JSObject* src, BarrieredBase<T>* dst, const char* name)
 {
     if (ShouldMarkCrossCompartment(trc, src, dst->get()))
         DispatchToTracer(trc, dst->unsafeGet(), name);
 }
 template void js::TraceCrossCompartmentEdge<Value>(JSTracer*, JSObject*, BarrieredBase<Value>*,
                                                    const char*);
 
+template <typename T>
+void
+js::TraceProcessGlobalRoot(JSTracer* trc, T* thing, const char* name)
+{
+    JS_ROOT_MARKING_ASSERT(trc);
+    MOZ_ASSERT(ThingIsPermanentAtomOrWellKnownSymbol(thing));
+
+    // We have to mark permanent atoms and well-known symbols through a special
+    // method because the default DoMarking implementation automatically skips
+    // them. Fortunately, atoms (permanent and non) cannot refer to other GC
+    // things so they do not need to go through the mark stack and may simply
+    // be marked directly.  Moreover, well-known symbols can refer only to
+    // permanent atoms, so likewise require no subsquent marking.
+    CheckMarkedThing(trc, thing);
+    if (trc->isMarkingTracer())
+        thing->markIfUnmarked(gc::BLACK);
+    else
+        DoCallback(trc->asCallbackTracer(), ConvertToBase(&thing), name);
+}
+template void js::TraceProcessGlobalRoot<JSAtom>(JSTracer*, JSAtom*, const char*);
+template void js::TraceProcessGlobalRoot<JS::Symbol>(JSTracer*, JS::Symbol*, const char*);
+
 // This method is responsible for dynamic dispatch to the real tracer
 // implementation. Consider replacing this choke point with virtual dispatch:
 // a sufficiently smart C++ compiler may be able to devirtualize some paths.
 template <typename T>
 void
 DispatchToTracer(JSTracer* trc, T* thingp, const char* name)
 {
 #define IS_SAME_TYPE_OR(name, type, _) mozilla::IsSame<type*, T>::value ||
@@ -530,53 +552,16 @@ js::GCMarker::mark(T* thing)
 {
     JS_COMPARTMENT_ASSERT(runtime(), thing);
     MOZ_ASSERT(!IsInsideNursery(gc::TenuredCell::fromPointer(thing)));
     return gc::ParticipatesInCC<T>::value
            ? gc::TenuredCell::fromPointer(thing)->markIfUnmarked(markColor())
            : gc::TenuredCell::fromPointer(thing)->markIfUnmarked(gc::BLACK);
 }
 
-namespace js {
-namespace gc {
-
-void
-MarkPermanentAtom(JSTracer* trc, JSAtom* atom, const char* name)
-{
-    MOZ_ASSERT(atom->isPermanent());
-
-    // We have to mark permanent atoms through a special method because the
-    // default DoMarking implementation automatically skips them. Fortunatly,
-    // atoms cannot refer to other GC things, so they do not need to go through
-    // the mark stack and may simply be marked directly.
-    CheckMarkedThing(trc, atom);
-    if (trc->isMarkingTracer())
-        atom->markIfUnmarked();
-    else
-        DoCallback(trc->asCallbackTracer(), reinterpret_cast<JSString**>(&atom), name);
-}
-
-void
-MarkWellKnownSymbol(JSTracer* trc, JS::Symbol* sym)
-{
-    if (!sym)
-        return;
-    MOZ_ASSERT(sym->isWellKnownSymbol());
-
-    // As per permanent atoms, the normal marking path is not adequate.
-    CheckMarkedThing(trc, sym);
-    if (trc->isMarkingTracer()) {
-        // Permanent atoms are marked before well-known symbols.
-        MOZ_ASSERT(sym->description()->isMarked());
-        sym->markIfUnmarked();
-    } else {
-        DoCallback(trc->asCallbackTracer(), &sym, "wellKnownSymbol");
-    }
-}
-
 template <typename T>
 static inline void
 CheckIsMarkedThing(T* thingp)
 {
 #define IS_SAME_TYPE_OR(name, type, _) mozilla::IsSame<type*, T>::value ||
     static_assert(
             FOR_EACH_GC_LAYOUT(IS_SAME_TYPE_OR)
             false, "Only the base cell layout types are allowed into marking/tracing internals");
@@ -717,16 +702,19 @@ IsAboutToBeFinalizedInternal<jsid>(jsid*
     } else if (JSID_IS_SYMBOL(*idp)) {
         JS::Symbol* sym = JSID_TO_SYMBOL(*idp);
         rv = IsAboutToBeFinalizedInternal(&sym);
         *idp = SYMBOL_TO_JSID(sym);
     }
     return rv;
 }
 
+namespace js {
+namespace gc {
+
 template <typename T>
 bool
 IsMarkedUnbarriered(T* thingp)
 {
     return IsMarkedInternal(ConvertToBase(thingp));
 }
 
 template <typename T>
--- a/js/src/gc/Marking.h
+++ b/js/src/gc/Marking.h
@@ -51,25 +51,24 @@ TraceCrossCompartmentEdge(JSTracer* trc,
                           const char* name);
 
 // As above but with manual barriers.
 template <typename T>
 void
 TraceManuallyBarrieredCrossCompartmentEdge(JSTracer* trc, JSObject* src, T* dst,
                                            const char* name);
 
-namespace gc {
-
-/*** Object Marking ***/
-
+// Permanent atoms and well-known symbols are shared between runtimes and must
+// use a separate marking path so that we can filter them out of normal heap
+// tracing.
+template <typename T>
 void
-MarkPermanentAtom(JSTracer* trc, JSAtom* atom, const char* name);
+TraceProcessGlobalRoot(JSTracer* trc, T* thing, const char* name);
 
-void
-MarkWellKnownSymbol(JSTracer* trc, JS::Symbol* sym);
+namespace gc {
 
 /* Return true if the pointer is nullptr, or if it is a tagged pointer to
  * nullptr.
  */
 MOZ_ALWAYS_INLINE bool
 IsNullTaggedPointer(void* p)
 {
     return uintptr_t(p) < 32;
--- a/js/src/jsatom.cpp
+++ b/js/src/jsatom.cpp
@@ -221,32 +221,32 @@ js::MarkPermanentAtoms(JSTracer* trc)
     if (rt->staticStrings)
         rt->staticStrings->trace(trc);
 
     if (rt->permanentAtoms) {
         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");
+            TraceProcessGlobalRoot(trc, atom, "permanent_table");
         }
     }
 }
 
 void
 js::MarkWellKnownSymbols(JSTracer* trc)
 {
     JSRuntime* rt = trc->runtime();
 
     if (rt->parentRuntime)
         return;
 
     if (WellKnownSymbols* wks = rt->wellKnownSymbols) {
         for (size_t i = 0; i < JS::WellKnownSymbolLimit; i++)
-            MarkWellKnownSymbol(trc, wks->get(i));
+            TraceProcessGlobalRoot(trc, wks->get(i).get(), "well_known_symbol");
     }
 }
 
 void
 JSRuntime::sweepAtoms()
 {
     if (!atoms_)
         return;
--- a/js/src/vm/String.cpp
+++ b/js/src/vm/String.cpp
@@ -804,24 +804,24 @@ StaticStrings::init(JSContext* cx)
 }
 
 void
 StaticStrings::trace(JSTracer* trc)
 {
     /* These strings never change, so barriers are not needed. */
 
     for (uint32_t i = 0; i < UNIT_STATIC_LIMIT; i++)
-        MarkPermanentAtom(trc, unitStaticTable[i], "unit-static-string");
+        TraceProcessGlobalRoot(trc, unitStaticTable[i], "unit-static-string");
 
     for (uint32_t i = 0; i < NUM_SMALL_CHARS * NUM_SMALL_CHARS; i++)
-        MarkPermanentAtom(trc, length2StaticTable[i], "length2-static-string");
+        TraceProcessGlobalRoot(trc, length2StaticTable[i], "length2-static-string");
 
     /* This may mark some strings more than once, but so be it. */
     for (uint32_t i = 0; i < INT_STATIC_LIMIT; i++)
-        MarkPermanentAtom(trc, intStaticTable[i], "int-static-string");
+        TraceProcessGlobalRoot(trc, intStaticTable[i], "int-static-string");
 }
 
 template <typename CharT>
 /* static */ bool
 StaticStrings::isStatic(const CharT* chars, size_t length)
 {
     switch (length) {
       case 1: {