Bug 915482 (part 1) - Move most of gc/Barrier-inl.h into gc/Barrier.h. r=terrence.
authorNicholas Nethercote <nnethercote@mozilla.com>
Wed, 11 Sep 2013 16:51:17 -0700
changeset 146764 5a4bb20926182672204818cd5e30461a6521bd60
parent 146763 cc9df767c70b7007b0243aaf6fd340d8376e4503
child 146765 f304767ded19005e9d08c2e427a001b22006f381
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
reviewersterrence
bugs915482
milestone26.0a1
Bug 915482 (part 1) - Move most of gc/Barrier-inl.h into gc/Barrier.h. r=terrence.
js/public/Id.h
js/src/gc/Barrier-inl.h
js/src/gc/Barrier.h
js/src/jsapi.h
--- a/js/public/Id.h
+++ b/js/public/Id.h
@@ -17,16 +17,17 @@
 // entry points expecting a jsid and do not need to handle JSID_VOID in hooks
 // receiving a jsid except when explicitly noted in the API contract.
 //
 // A jsid is not implicitly convertible to or from a jsval; JS_ValueToId or
 // JS_IdToValue must be used instead.
 
 #include "jstypes.h"
 
+#include "js/RootingAPI.h"
 #include "js/TypeDecls.h"
 #include "js/Utility.h"
 
 #ifdef JS_USE_JSID_STRUCT_TYPES
 struct jsid
 {
     size_t asBits;
     bool operator==(jsid rhs) const { return asBits == rhs.asBits; }
@@ -155,9 +156,35 @@ extern JS_PUBLIC_DATA(const jsid) JSID_E
 #else
 # define JSID_VOID ((jsid)JSID_TYPE_VOID)
 # define JSID_EMPTY ((jsid)JSID_TYPE_OBJECT)
 #endif
 
 extern JS_PUBLIC_DATA(const JS::Handle<jsid>) JSID_VOIDHANDLE;
 extern JS_PUBLIC_DATA(const JS::Handle<jsid>) JSID_EMPTYHANDLE;
 
+namespace js {
+
+inline bool
+IsPoisonedId(jsid iden)
+{
+    if (JSID_IS_STRING(iden))
+        return JS::IsPoisonedPtr(JSID_TO_STRING(iden));
+    if (JSID_IS_OBJECT(iden))
+        return JS::IsPoisonedPtr(JSID_TO_OBJECT(iden));
+    return false;
+}
+
+template <> struct GCMethods<jsid>
+{
+    static jsid initial() { return JSID_VOID; }
+    static ThingRootKind kind() { return THING_ROOT_ID; }
+    static bool poisoned(jsid id) { return IsPoisonedId(id); }
+    static bool needsPostBarrier(jsid id) { return false; }
+#ifdef JSGC_GENERATIONAL
+    static void postBarrier(jsid *idp) {}
+    static void relocate(jsid *idp) {}
+#endif
+};
+
+}
+
 #endif /* js_Id_h */
--- a/js/src/gc/Barrier-inl.h
+++ b/js/src/gc/Barrier-inl.h
@@ -13,144 +13,16 @@
 
 #include "gc/Marking.h"
 #include "gc/StoreBuffer.h"
 
 #include "vm/String-inl.h"
 
 namespace js {
 
-/*
- * This is a post barrier for HashTables whose key is a GC pointer. Any
- * insertion into a HashTable not marked as part of the runtime, with a GC
- * pointer as a key, must call this immediately after each insertion.
- */
-template <class Map, class Key>
-inline void
-HashTableWriteBarrierPost(JSRuntime *rt, Map *map, const Key &key)
-{
-#ifdef JSGC_GENERATIONAL
-    if (key && IsInsideNursery(rt, key))
-        rt->gcStoreBuffer.putGeneric(gc::HashKeyRef<Map, Key>(map, key));
-#endif
-}
-
-inline
-EncapsulatedId::~EncapsulatedId()
-{
-    pre();
-}
-
-inline EncapsulatedId &
-EncapsulatedId::operator=(const EncapsulatedId &v)
-{
-    if (v.value != value)
-        pre();
-    JS_ASSERT(!IsPoisonedId(v.value));
-    value = v.value;
-    return *this;
-}
-
-inline void
-EncapsulatedId::pre()
-{
-#ifdef JSGC_INCREMENTAL
-    if (JSID_IS_OBJECT(value)) {
-        JSObject *obj = JSID_TO_OBJECT(value);
-        Zone *zone = obj->zone();
-        if (zone->needsBarrier()) {
-            js::gc::MarkObjectUnbarriered(zone->barrierTracer(), &obj, "write barrier");
-            JS_ASSERT(obj == JSID_TO_OBJECT(value));
-        }
-    } else if (JSID_IS_STRING(value)) {
-        JSString *str = JSID_TO_STRING(value);
-        Zone *zone = str->zone();
-        if (zone->needsBarrier()) {
-            js::gc::MarkStringUnbarriered(zone->barrierTracer(), &str, "write barrier");
-            JS_ASSERT(str == JSID_TO_STRING(value));
-        }
-    }
-#endif
-}
-
-inline
-RelocatableId::~RelocatableId()
-{
-    pre();
-}
-
-inline RelocatableId &
-RelocatableId::operator=(jsid id)
-{
-    if (id != value)
-        pre();
-    JS_ASSERT(!IsPoisonedId(id));
-    value = id;
-    return *this;
-}
-
-inline RelocatableId &
-RelocatableId::operator=(const RelocatableId &v)
-{
-    if (v.value != value)
-        pre();
-    JS_ASSERT(!IsPoisonedId(v.value));
-    value = v.value;
-    return *this;
-}
-
-inline
-HeapId::HeapId(jsid id)
-    : EncapsulatedId(id)
-{
-    JS_ASSERT(!IsPoisonedId(id));
-    post();
-}
-
-inline
-HeapId::~HeapId()
-{
-    pre();
-}
-
-inline void
-HeapId::init(jsid id)
-{
-    JS_ASSERT(!IsPoisonedId(id));
-    value = id;
-    post();
-}
-
-inline void
-HeapId::post()
-{
-}
-
-inline HeapId &
-HeapId::operator=(jsid id)
-{
-    if (id != value)
-        pre();
-    JS_ASSERT(!IsPoisonedId(id));
-    value = id;
-    post();
-    return *this;
-}
-
-inline HeapId &
-HeapId::operator=(const HeapId &v)
-{
-    if (v.value != value)
-        pre();
-    JS_ASSERT(!IsPoisonedId(v.value));
-    value = v.value;
-    post();
-    return *this;
-}
-
 inline const Value &
 ReadBarrieredValue::get() const
 {
     if (value.isObject())
         JSObject::readBarrier(&value.toObject());
     else if (value.isString())
         JSString::readBarrier(value.toString());
     else
--- a/js/src/gc/Barrier.h
+++ b/js/src/gc/Barrier.h
@@ -119,30 +119,69 @@
 namespace js {
 
 class PropertyName;
 
 namespace gc {
 // Direct value access used by the write barriers and the jits.
 void
 MarkValueUnbarriered(JSTracer *trc, Value *v, const char *name);
+
+// These two declarations are also present in gc/Marking.h, via the DeclMarker
+// macro.  Not great, but hard to avoid.
+void
+MarkObjectUnbarriered(JSTracer *trc, JSObject **obj, const char *name);
+void
+MarkStringUnbarriered(JSTracer *trc, JSString **str, const char *name);
 }
 
+// Note: these functions must be equivalent to the zone() functions implemented
+// by all the subclasses of Cell.
+
 JS::Zone *
 ZoneOfObject(const JSObject &obj);
 
+static inline JS::shadow::Zone *
+ShadowZoneOfObject(JSObject *obj)
+{
+    return JS::shadow::Zone::asShadowZone(ZoneOfObject(*obj));
+}
+
+static inline JS::shadow::Zone *
+ShadowZoneOfString(JSString *str)
+{
+    return JS::shadow::Zone::asShadowZone(reinterpret_cast<const js::gc::Cell *>(str)->tenuredZone());
+}
+
 JS_ALWAYS_INLINE JS::Zone *
 ZoneOfValue(const JS::Value &value)
 {
     JS_ASSERT(value.isMarkable());
     if (value.isObject())
         return ZoneOfObject(value.toObject());
     return static_cast<js::gc::Cell *>(value.toGCThing())->tenuredZone();
 }
 
+/*
+ * This is a post barrier for HashTables whose key is a GC pointer. Any
+ * insertion into a HashTable not marked as part of the runtime, with a GC
+ * pointer as a key, must call this immediately after each insertion.
+ */
+template <class Map, class Key>
+inline void
+HashTableWriteBarrierPost(JSRuntime *rt, Map *map, const Key &key)
+{
+#ifdef JSGC_GENERATIONAL
+    if (key && IsInsideNursery(rt, key)) {
+        JS::shadow::Runtime *shadowRuntime = JS::shadow::Runtime::asShadowRuntime(rt);
+        shadowRuntime->gcStoreBufferPtr()->putGeneric(gc::HashKeyRef<Map, Key>(map, key));
+    }
+#endif
+}
+
 template<class T, typename Unioned = uintptr_t>
 class EncapsulatedPtr
 {
   protected:
     union {
         T *value;
         Unioned other;
     };
@@ -818,57 +857,120 @@ class EncapsulatedId
     jsid value;
 
   private:
     EncapsulatedId(const EncapsulatedId &v) MOZ_DELETE;
 
   public:
     explicit EncapsulatedId() : value(JSID_VOID) {}
     explicit EncapsulatedId(jsid id) : value(id) {}
-    ~EncapsulatedId();
+    ~EncapsulatedId() { pre(); }
 
-    inline EncapsulatedId &operator=(const EncapsulatedId &v);
+    EncapsulatedId &operator=(const EncapsulatedId &v) {
+        if (v.value != value)
+            pre();
+        JS_ASSERT(!IsPoisonedId(v.value));
+        value = v.value;
+        return *this;
+    }
 
     bool operator==(jsid id) const { return value == id; }
     bool operator!=(jsid id) const { return value != id; }
 
     jsid get() const { return value; }
     jsid *unsafeGet() { return &value; }
     void unsafeSet(jsid newId) { value = newId; }
     operator jsid() const { return value; }
 
   protected:
-    inline void pre();
+    void pre() {
+#ifdef JSGC_INCREMENTAL
+        if (JSID_IS_OBJECT(value)) {
+            JSObject *obj = JSID_TO_OBJECT(value);
+            JS::shadow::Zone *shadowZone = ShadowZoneOfObject(obj);
+            if (shadowZone->needsBarrier()) {
+                js::gc::MarkObjectUnbarriered(shadowZone->barrierTracer(), &obj, "write barrier");
+                JS_ASSERT(obj == JSID_TO_OBJECT(value));
+            }
+        } else if (JSID_IS_STRING(value)) {
+            JSString *str = JSID_TO_STRING(value);
+            JS::shadow::Zone *shadowZone = ShadowZoneOfString(str);
+            if (shadowZone->needsBarrier()) {
+                js::gc::MarkStringUnbarriered(shadowZone->barrierTracer(), &str, "write barrier");
+                JS_ASSERT(str == JSID_TO_STRING(value));
+            }
+        }
+#endif
+    }
 };
 
 class RelocatableId : public EncapsulatedId
 {
   public:
     explicit RelocatableId() : EncapsulatedId() {}
     explicit inline RelocatableId(jsid id) : EncapsulatedId(id) {}
-    inline ~RelocatableId();
+    ~RelocatableId() { pre(); }
 
-    inline RelocatableId &operator=(jsid id);
-    inline RelocatableId &operator=(const RelocatableId &v);
+    RelocatableId &operator=(jsid id) {
+        if (id != value)
+            pre();
+        JS_ASSERT(!IsPoisonedId(id));
+        value = id;
+        return *this;
+    }
+
+    RelocatableId &operator=(const RelocatableId &v) {
+        if (v.value != value)
+            pre();
+        JS_ASSERT(!IsPoisonedId(v.value));
+        value = v.value;
+        return *this;
+    }
 };
 
 class HeapId : public EncapsulatedId
 {
   public:
     explicit HeapId() : EncapsulatedId() {}
-    explicit inline HeapId(jsid id);
-    inline ~HeapId();
+
+    explicit HeapId(jsid id)
+      : EncapsulatedId(id)
+    {
+        JS_ASSERT(!IsPoisonedId(id));
+        post();
+    }
+
+    ~HeapId() { pre(); }
+
+    void init(jsid id) {
+        JS_ASSERT(!IsPoisonedId(id));
+        value = id;
+        post();
+    }
 
-    inline void init(jsid id);
+    HeapId &operator=(jsid id) {
+        if (id != value)
+            pre();
+        JS_ASSERT(!IsPoisonedId(id));
+        value = id;
+        post();
+        return *this;
+    }
 
-    inline HeapId &operator=(jsid id);
-    inline HeapId &operator=(const HeapId &v);
+    HeapId &operator=(const HeapId &v) {
+        if (v.value != value)
+            pre();
+        JS_ASSERT(!IsPoisonedId(v.value));
+        value = v.value;
+        post();
+        return *this;
+    }
 
   private:
-    inline void post();
+    void post() {};
 
     HeapId(const HeapId &v) MOZ_DELETE;
 };
 
 /*
  * Incremental GC requires that weak pointers have read barriers. This is mostly
  * an issue for empty shapes stored in JSCompartment. The problem happens when,
  * during an incremental GC, some JS code stores one of the compartment's empty
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1354,38 +1354,16 @@ JS_BeginRequest(JSContext *cx);
 extern JS_PUBLIC_API(void)
 JS_EndRequest(JSContext *cx);
 
 extern JS_PUBLIC_API(bool)
 JS_IsInRequest(JSRuntime *rt);
 
 namespace js {
 
-inline bool
-IsPoisonedId(jsid iden)
-{
-    if (JSID_IS_STRING(iden))
-        return JS::IsPoisonedPtr(JSID_TO_STRING(iden));
-    if (JSID_IS_OBJECT(iden))
-        return JS::IsPoisonedPtr(JSID_TO_OBJECT(iden));
-    return false;
-}
-
-template <> struct GCMethods<jsid>
-{
-    static jsid initial() { return JSID_VOID; }
-    static ThingRootKind kind() { return THING_ROOT_ID; }
-    static bool poisoned(jsid id) { return IsPoisonedId(id); }
-    static bool needsPostBarrier(jsid id) { return false; }
-#ifdef JSGC_GENERATIONAL
-    static void postBarrier(jsid *idp) {}
-    static void relocate(jsid *idp) {}
-#endif
-};
-
 void
 AssertHeapIsIdle(JSRuntime *rt);
 
 void
 AssertHeapIsIdle(JSContext *cx);
 
 } /* namespace js */