Bug 1447951 - Store nsDynamicAtom's chars after the end of the object. r=froydnj
authorNicholas Nethercote <nnethercote@mozilla.com>
Fri, 22 Jun 2018 09:38:42 +1000
changeset 477525 b67973aeb2af232a387f926e0103a140c98f8865
parent 477524 6c29e4fc89c79a9a710eaa349f138cc84115ffd8
child 477526 a1eb2582c7d29e2d6182e7eadaec56a91d6fe4ff
push id9385
push userdluca@mozilla.com
push dateFri, 22 Jun 2018 15:47:18 +0000
treeherdermozilla-beta@82a9a1027e2b [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1447951
milestone62.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 1447951 - Store nsDynamicAtom's chars after the end of the object. r=froydnj This reduces memory usage because we only need one allocation instead of two for the dynamic atom and its chars, and because we don't need to store a refcount and a size. It precludes sharing of chars between dynamic atoms, but we weren't benefiting much from that anyway. This reduces per-process memory usage by up to several hundred KiB on my Linux64 box. One consequence of this change is that we need to allocate + copy in DOMString::SetKnownLiveAtom(), which could make some things slower.
dom/bindings/DOMString.h
parser/html/nsHtml5AtomTable.cpp
parser/html/nsHtml5String.h
servo/components/style/gecko_string_cache/mod.rs
toolkit/components/aboutmemory/tests/test_memoryReporters.xul
xpcom/base/nsMemoryReporterManager.cpp
xpcom/ds/nsAtom.h
xpcom/ds/nsAtomTable.cpp
xpcom/ds/nsAtomTable.h
xpcom/tests/gtest/TestAtoms.cpp
--- a/dom/bindings/DOMString.h
+++ b/dom/bindings/DOMString.h
@@ -216,20 +216,20 @@ public:
     MOZ_ASSERT(mState == State::Empty, "We're already set to a value");
     MOZ_ASSERT(!mStringBuffer, "Setting stringbuffer twice?");
     MOZ_ASSERT(aAtom || aNullHandling != eNullNotExpected);
     if (aNullHandling == eNullNotExpected || aAtom) {
       if (aAtom->IsStatic()) {
         // Static atoms are backed by literals.
         SetLiteralInternal(aAtom->GetUTF16String(), aAtom->GetLength());
       } else {
-        // Dynamic atoms always have a string buffer and never have 0 length,
-        // because nsGkAtoms::_empty is a static atom.
-        SetKnownLiveStringBuffer(
-          aAtom->AsDynamic()->GetStringBuffer(), aAtom->GetLength());
+        // Dynamic atoms own their own chars, and never have 0 length because
+        // nsGkAtoms::_empty is a static atom.
+        MOZ_ASSERT(aAtom->GetLength() > 0);
+        AsAString().Assign(aAtom->AsDynamic()->String(), aAtom->GetLength());
       }
     } else if (aNullHandling == eTreatNullAsNull) {
       SetNull();
     }
   }
 
   void SetNull()
   {
--- a/parser/html/nsHtml5AtomTable.cpp
+++ b/parser/html/nsHtml5AtomTable.cpp
@@ -2,30 +2,30 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "nsHtml5AtomTable.h"
 #include "nsThreadUtils.h"
 
 nsHtml5AtomEntry::nsHtml5AtomEntry(KeyTypePointer aStr)
   : nsStringHashKey(aStr)
-  , mAtom(new nsDynamicAtom(*aStr))
+  , mAtom(nsDynamicAtom::Create(*aStr))
 {
 }
 
 nsHtml5AtomEntry::nsHtml5AtomEntry(const nsHtml5AtomEntry& aOther)
   : nsStringHashKey(aOther)
   , mAtom(nullptr)
 {
   NS_NOTREACHED("nsHtml5AtomTable is broken and tried to copy an entry");
 }
 
 nsHtml5AtomEntry::~nsHtml5AtomEntry()
 {
-  delete mAtom;
+  nsDynamicAtom::Destroy(mAtom);
 }
 
 nsHtml5AtomTable::nsHtml5AtomTable()
   : mRecentlyUsedParserAtoms{}
 {
 #ifdef DEBUG
   mPermittedLookupEventTarget = mozilla::GetCurrentThreadSerialEventTarget();
 #endif
--- a/parser/html/nsHtml5String.h
+++ b/parser/html/nsHtml5String.h
@@ -1,17 +1,18 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsHtml5String_h
 #define nsHtml5String_h
 
+#include "nsAtom.h"
 #include "nsString.h"
-#include "nsAtom.h"
+#include "nsStringBuffer.h"
 
 class nsHtml5TreeBuilder;
 
 /**
  * A pass-by-value type that can represent
  *  * nullptr
  *  * empty string
  *  * Non-empty string as exactly-sized (capacity is length) `nsStringBuffer*`
--- a/servo/components/style/gecko_string_cache/mod.rs
+++ b/servo/components/style/gecko_string_cache/mod.rs
@@ -117,17 +117,18 @@ impl WeakAtom {
             let string_offset = unsafe { (*atom_ptr).mStringOffset };
             let string_offset = -(string_offset as isize);
             let u8_ptr = atom_ptr as *const u8;
             // It is safe to use offset() here because both addresses are within
             // the same struct, e.g. mozilla::detail::gGkAtoms.
             unsafe { u8_ptr.offset(string_offset) as *const u16 }
         } else {
             let atom_ptr = self.as_ptr() as *const nsDynamicAtom;
-            unsafe { (*(atom_ptr)).mString }
+            // Dynamic atom chars are stored at the end of the object.
+            unsafe { atom_ptr.offset(1) as *const u16 }
         };
         unsafe { slice::from_raw_parts(string, self.len() as usize) }
     }
 
     // NOTE: don't expose this, since it's slow, and easy to be misused.
     fn chars(&self) -> DecodeUtf16<Cloned<slice::Iter<u16>>> {
         char::decode_utf16(self.as_slice().iter().cloned())
     }
--- a/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
+++ b/toolkit/components/aboutmemory/tests/test_memoryReporters.xul
@@ -96,18 +96,18 @@
     } else if (aPath.search(/^explicit\/js-non-window\/.*realm\(/) >= 0) {
       present.jsNonWindowRealms = true;
     } else if (aPath.search(/^explicit\/window-objects\/top\(.*\/js-realm\(/) >= 0) {
       present.windowObjectsJsRealms = true;
     } else if (aPath.search(/^explicit\/storage\/sqlite\/places.sqlite/) >= 0) {
       present.places = true;
     } else if (aPath.search(/^explicit\/images/) >= 0) {
       present.images = true;
-    } else if (aPath.search(/^explicit\/atoms\/dynamic\/atom-objects$/) >= 0) {
-      present.dynamicAtomObjects = true;
+    } else if (aPath.search(/^explicit\/atoms\/dynamic-objects-and-chars$/) >= 0) {
+      present.dynamicObjectsAndChars = true;
     } else if (/\[System Principal\].*this-is-a-sandbox-name/.test(aPath)) {
       // A system compartment with a location (such as a sandbox) should
       // show that location.
       present.sandboxLocation = true;
     } else if (aPath.includes(bigStringPrefix)) {
       present.bigString = true;
     } else if (aPath.includes("!)(*&")) {
       present.smallString1 = true;
@@ -254,17 +254,17 @@
     }
     checkSizeReasonable("js-main-runtime-gc-heap-committed/used/gc-things",
                         jsGcHeapUsedGcThingsTotal);
 
     ok(present.jsNonWindowRealms,           "js-non-window realms are present");
     ok(present.windowObjectsJsRealms,       "window-objects/.../js realms are present");
     ok(present.places,                      "places is present");
     ok(present.images,                      "images is present");
-    ok(present.dynamicAtomObjects,          "dynamic/atom-objects is present");
+    ok(present.dynamicObjectsAndChars,      "dynamic-objects-and-chars is present");
     ok(present.sandboxLocation,             "sandbox locations are present");
     ok(present.bigString,                   "large string is present");
     ok(present.smallString1,                "small string 1 is present");
     ok(present.smallString2,                "small string 2 is present");
 
     ok(!present.anonymizedWhenUnnecessary,
        "anonymized paths are not present when unnecessary. Failed case: " +
        present.anonymizedWhenUnnecessary);
--- a/xpcom/base/nsMemoryReporterManager.cpp
+++ b/xpcom/base/nsMemoryReporterManager.cpp
@@ -1416,25 +1416,20 @@ public:
     AtomsSizes sizes;
     NS_AddSizeOfAtoms(MallocSizeOf, sizes);
 
     MOZ_COLLECT_REPORT(
       "explicit/atoms/table", KIND_HEAP, UNITS_BYTES, sizes.mTable,
       "Memory used by the atom table.");
 
     MOZ_COLLECT_REPORT(
-      "explicit/atoms/dynamic/atom-objects", KIND_HEAP, UNITS_BYTES,
-      sizes.mDynamicAtomObjects,
-      "Memory used by dynamic atom objects.");
-
-    MOZ_COLLECT_REPORT(
-      "explicit/atoms/dynamic/unshared-buffers", KIND_HEAP, UNITS_BYTES,
-      sizes.mDynamicUnsharedBuffers,
-      "Memory used by unshared string buffers pointed to by dynamic atom "
-      "objects.");
+      "explicit/atoms/dynamic-objects-and-chars", KIND_HEAP, UNITS_BYTES,
+      sizes.mDynamicAtoms,
+      "Memory used by dynamic atom objects and chars (which are stored "
+      "at the end of each atom object).");
 
     return NS_OK;
   }
 };
 NS_IMPL_ISUPPORTS(AtomTablesReporter, nsIMemoryReporter)
 
 #ifdef DEBUG
 
--- a/xpcom/ds/nsAtom.h
+++ b/xpcom/ds/nsAtom.h
@@ -4,18 +4,18 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsAtom_h
 #define nsAtom_h
 
 #include "nsISupportsImpl.h"
 #include "nsString.h"
-#include "nsStringBuffer.h"
 #include "mozilla/HashFunctions.h"
+#include "mozilla/UniquePtr.h"
 
 namespace mozilla {
 struct AtomsSizes;
 }
 
 class nsStaticAtom;
 class nsDynamicAtom;
 
@@ -162,45 +162,42 @@ private:
 class nsDynamicAtom : public nsAtom
 {
 public:
   // We can't use NS_INLINE_DECL_THREADSAFE_REFCOUNTING because the refcounting
   // of this type is special.
   MozExternalRefCountType AddRef();
   MozExternalRefCountType Release();
 
-  ~nsDynamicAtom();
-
-  const char16_t* String() const { return mString; }
-
-  // The caller must *not* mutate the string buffer, otherwise all hell will
-  // break loose.
-  nsStringBuffer* GetStringBuffer() const
+  const char16_t* String() const
   {
-    // See the comment on |mString|'s declaration.
-    MOZ_ASSERT(IsDynamic());
-    return nsStringBuffer::FromData(const_cast<char16_t*>(mString));
+    return reinterpret_cast<const char16_t*>(this + 1);
   }
 
 private:
   friend class nsAtomTable;
   friend class nsAtomSubTable;
   // XXX: we'd like to remove nsHtml5AtomEntry. See bug 1392185.
   friend class nsHtml5AtomEntry;
 
-  // Construction is done by |friend|s.
-  // The first constructor is for dynamic normal atoms, the second is for
-  // dynamic HTML5 atoms.
+  // These shouldn't be used directly, even by friend classes. The
+  // Create()/Destroy() methods use them.
+  static nsDynamicAtom* CreateInner(const nsAString& aString, uint32_t aHash);
   nsDynamicAtom(const nsAString& aString, uint32_t aHash);
-  explicit nsDynamicAtom(const nsAString& aString);
+  ~nsDynamicAtom() {}
+
+  // Creation/destruction is done by friend classes. The first Create() is for
+  // dynamic normal atoms, the second is for dynamic HTML5 atoms.
+  static nsDynamicAtom* Create(const nsAString& aString, uint32_t aHash);
+  static nsDynamicAtom* Create(const nsAString& aString);
+  static void Destroy(nsDynamicAtom* aAtom);
 
   mozilla::ThreadSafeAutoRefCnt mRefCnt;
-  // Note: this points to the chars in an nsStringBuffer, which is obtained
-  // with nsStringBuffer::FromData(mString).
-  const char16_t* const mString;
+
+  // The atom's chars are stored at the end of the struct.
 };
 
 // The four forms of NS_Atomize (for use with |RefPtr<nsAtom>|) return the
 // atom for the string given. At any given time there will always be one atom
 // representing a given string. Atoms are intended to make string comparison
 // cheaper by simplifying it to pointer equality. A pointer to the atom that
 // does not own a reference is not guaranteed to be valid.
 
--- a/xpcom/ds/nsAtomTable.cpp
+++ b/xpcom/ds/nsAtomTable.cpp
@@ -25,17 +25,17 @@
 #include "nsString.h"
 #include "nsThreadUtils.h"
 #include "nsUnicharUtils.h"
 #include "PLDHashTable.h"
 #include "prenv.h"
 
 // There are two kinds of atoms handled by this module.
 //
-// - Dynamic: the atom itself is heap allocated, as is the nsStringBuffer it
+// - Dynamic: the atom itself is heap allocated, as is the char buffer it
 //   points to. |gAtomTable| holds weak references to dynamic atoms. When the
 //   refcount of a dynamic atom drops to zero, we increment a static counter.
 //   When that counter reaches a certain threshold, we iterate over the atom
 //   table, removing and deleting dynamic atoms with refcount zero. This allows
 //   us to avoid acquiring the atom table lock during normal refcounting.
 //
 // - Static: both the atom and its chars are statically allocated and
 //   immutable, so it ignores all AddRef/Release calls.
@@ -58,67 +58,59 @@ enum class GCKind {
 // (and thus turned into unused state), and decremented when an unused
 // atom gets a reference again. The atom table relies on this value to
 // schedule GC. This value can temporarily go below zero when multiple
 // threads are operating the same atom, so it has to be signed so that
 // we wouldn't use overflow value for comparison.
 // See nsAtom::AddRef() and nsAtom::Release().
 static Atomic<int32_t, ReleaseAcquire> gUnusedAtomCount(0);
 
-static char16_t*
-FromStringBuffer(const nsAString& aString)
-{
-  char16_t* str;
-  size_t length = aString.Length();
-  RefPtr<nsStringBuffer> buf = nsStringBuffer::FromString(aString);
-  if (buf) {
-    str = static_cast<char16_t*>(buf->Data());
-  } else {
-    const size_t size = (length + 1) * sizeof(char16_t);
-    buf = nsStringBuffer::Alloc(size);
-    if (MOZ_UNLIKELY(!buf)) {
-      NS_ABORT_OOM(size); // OOM because atom allocations should be small.
-    }
-    str = static_cast<char16_t*>(buf->Data());
-    CopyUnicodeTo(aString, 0, str, length);
-    str[length] = char16_t(0);
-  }
-
-  MOZ_ASSERT(buf && buf->StorageSize() >= (length + 1) * sizeof(char16_t),
-             "enough storage");
-
-  // Take ownership of the string buffer.
-  mozilla::Unused << buf.forget();
-
-  return str;
-}
-
 nsDynamicAtom::nsDynamicAtom(const nsAString& aString, uint32_t aHash)
   : nsAtom(AtomKind::DynamicNormal, aString, aHash)
   , mRefCnt(1)
-  , mString(FromStringBuffer(aString))
 {
-  MOZ_ASSERT(mHash == HashString(mString, mLength));
-
-  MOZ_ASSERT(mString[mLength] == char16_t(0), "null terminated");
-  MOZ_ASSERT(Equals(aString), "correct data");
 }
 
-nsDynamicAtom::nsDynamicAtom(const nsAString& aString)
-  : nsAtom(AtomKind::DynamicHTML5, aString, 0)
-  , mRefCnt(1)
-  , mString(FromStringBuffer(aString))
+nsDynamicAtom*
+nsDynamicAtom::CreateInner(const nsAString& aString, uint32_t aHash)
 {
-  MOZ_ASSERT(mString[mLength] == char16_t(0), "null terminated");
-  MOZ_ASSERT(Equals(aString), "correct data");
+  // We tack the chars onto the end of the nsDynamicAtom object.
+  size_t numCharBytes = (aString.Length() + 1) * sizeof(char16_t);
+  size_t numTotalBytes = sizeof(nsDynamicAtom) + numCharBytes;
+
+  nsDynamicAtom* atom = (nsDynamicAtom*)moz_xmalloc(numTotalBytes);
+  new (atom) nsDynamicAtom(aString, aHash);
+  memcpy(const_cast<char16_t*>(atom->String()),
+         PromiseFlatString(aString).get(), numCharBytes);
+
+  MOZ_ASSERT(atom->String()[atom->GetLength()] == char16_t(0));
+  MOZ_ASSERT(atom->Equals(aString));
+
+  return atom;
 }
 
-nsDynamicAtom::~nsDynamicAtom()
+nsDynamicAtom*
+nsDynamicAtom::Create(const nsAString& aString, uint32_t aHash)
 {
-  GetStringBuffer()->Release();
+  nsDynamicAtom* atom = CreateInner(aString, aHash);
+  MOZ_ASSERT(atom->mHash == HashString(atom->String(), atom->GetLength()));
+  return atom;
+}
+
+nsDynamicAtom*
+nsDynamicAtom::Create(const nsAString& aString)
+{
+  return CreateInner(aString, /* hash */ 0);
+}
+
+void
+nsDynamicAtom::Destroy(nsDynamicAtom* aAtom)
+{
+  aAtom->~nsDynamicAtom();
+  free(aAtom);
 }
 
 const nsStaticAtom*
 nsAtom::AsStatic() const
 {
   MOZ_ASSERT(IsStatic());
   return static_cast<const nsStaticAtom*>(this);
 }
@@ -142,17 +134,17 @@ nsAtom::ToString(nsAString& aString) con
 {
   // See the comment on |mString|'s declaration.
   if (IsStatic()) {
     // AssignLiteral() lets us assign without copying. This isn't a string
     // literal, but it's a static atom and thus has an unbounded lifetime,
     // which is what's important.
     aString.AssignLiteral(AsStatic()->String(), mLength);
   } else {
-    AsDynamic()->GetStringBuffer()->ToString(mLength, aString);
+    aString.Assign(AsDynamic()->String(), mLength);
   }
 }
 
 void
 nsAtom::ToUTF8String(nsACString& aBuf) const
 {
   MOZ_ASSERT(!IsDynamicHTML5(),
              "Called ToUTF8String() on a dynamic HTML5 atom");
@@ -163,20 +155,17 @@ void
 nsAtom::AddSizeOfIncludingThis(MallocSizeOf aMallocSizeOf, AtomsSizes& aSizes)
   const
 {
   MOZ_ASSERT(!IsDynamicHTML5(),
              "Called AddSizeOfIncludingThis() on a dynamic HTML5 atom");
 
   // Static atoms are in static memory, and so are not measured here.
   if (IsDynamic()) {
-    aSizes.mDynamicAtomObjects += aMallocSizeOf(this);
-    aSizes.mDynamicUnsharedBuffers +=
-      AsDynamic()->GetStringBuffer()->SizeOfIncludingThisIfUnshared(
-        aMallocSizeOf);
+    aSizes.mDynamicAtoms += aMallocSizeOf(this);
   }
 }
 
 char16ptr_t
 nsAtom::GetUTF16String() const
 {
   return IsStatic() ? AsStatic()->String() : AsDynamic()->String();
 }
@@ -496,17 +485,17 @@ nsAtomSubTable::GCLocked(GCKind aKind)
     if (entry->mAtom->IsStatic()) {
       continue;
     }
 
     nsAtom* atom = entry->mAtom;
     MOZ_ASSERT(!atom->IsDynamicHTML5());
     if (atom->IsDynamic() && atom->AsDynamic()->mRefCnt == 0) {
       i.Remove();
-      delete atom->AsDynamic();
+      nsDynamicAtom::Destroy(atom->AsDynamic());
       ++removedCount;
     }
 #ifdef NS_FREE_PERMANENT_DATA
     else if (aKind == GCKind::Shutdown && PR_GetEnv("XPCOM_MEM_BLOAT_LOG")) {
       // Only report leaking atoms in leak-checking builds in a run where we
       // are checking for leaks, during shutdown. If something is anomalous,
       // then we'll assert later in this function.
       nsAutoCString name;
@@ -701,22 +690,19 @@ nsAtomTable::Atomize(const nsACString& a
   AtomTableEntry* he = table.Add(key);
 
   if (he->mAtom) {
     RefPtr<nsAtom> atom = he->mAtom;
 
     return atom.forget();
   }
 
-  // This results in an extra addref/release of the nsStringBuffer.
-  // Unfortunately there doesn't seem to be any APIs to avoid that.
-  // Actually, now there is, sort of: ForgetSharedBuffer.
   nsString str;
   CopyUTF8toUTF16(aUTF8String, str);
-  RefPtr<nsAtom> atom = dont_AddRef(new nsDynamicAtom(str, hash));
+  RefPtr<nsAtom> atom = dont_AddRef(nsDynamicAtom::Create(str, hash));
 
   he->mAtom = atom;
 
   return atom.forget();
 }
 
 already_AddRefed<nsAtom>
 NS_Atomize(const nsACString& aUTF8String)
@@ -742,17 +728,17 @@ nsAtomTable::Atomize(const nsAString& aU
   AtomTableEntry* he = table.Add(key);
 
   if (he->mAtom) {
     RefPtr<nsAtom> atom = he->mAtom;
 
     return atom.forget();
   }
 
-  RefPtr<nsAtom> atom = dont_AddRef(new nsDynamicAtom(aUTF16String, hash));
+  RefPtr<nsAtom> atom = dont_AddRef(nsDynamicAtom::Create(aUTF16String, hash));
   he->mAtom = atom;
 
   return atom.forget();
 }
 
 already_AddRefed<nsAtom>
 NS_Atomize(const nsAString& aUTF16String)
 {
@@ -781,17 +767,18 @@ nsAtomTable::AtomizeMainThread(const nsA
 
   nsAtomSubTable& table = SelectSubTable(key);
   MutexAutoLock lock(table.mLock);
   AtomTableEntry* he = table.Add(key);
 
   if (he->mAtom) {
     retVal = he->mAtom;
   } else {
-    RefPtr<nsAtom> newAtom = dont_AddRef(new nsDynamicAtom(aUTF16String, hash));
+    RefPtr<nsAtom> newAtom =
+      dont_AddRef(nsDynamicAtom::Create(aUTF16String, hash));
     he->mAtom = newAtom;
     retVal = newAtom.forget();
   }
 
   sRecentlyUsedMainThreadAtoms[index] = he->mAtom;
   return retVal.forget();
 }
 
--- a/xpcom/ds/nsAtomTable.h
+++ b/xpcom/ds/nsAtomTable.h
@@ -12,23 +12,21 @@
 
 void NS_InitAtomTable();
 void NS_ShutdownAtomTable();
 
 namespace mozilla {
 struct AtomsSizes
 {
   size_t mTable;
-  size_t mDynamicAtomObjects;
-  size_t mDynamicUnsharedBuffers;
+  size_t mDynamicAtoms;
 
   AtomsSizes()
    : mTable(0)
-   , mDynamicAtomObjects(0)
-   , mDynamicUnsharedBuffers(0)
+   , mDynamicAtoms(0)
   {}
 };
 } // namespace mozilla
 
 void NS_AddSizeOfAtoms(mozilla::MallocSizeOf aMallocSizeOf,
                        mozilla::AtomsSizes& aSizes);
 
 #endif // nsAtomTable_h__
--- a/xpcom/tests/gtest/TestAtoms.cpp
+++ b/xpcom/tests/gtest/TestAtoms.cpp
@@ -49,26 +49,16 @@ TEST(Atoms, 16vs8)
 {
   for (unsigned int i = 0; i < ArrayLength(ValidStrings); ++i) {
     RefPtr<nsAtom> atom16 = NS_Atomize(ValidStrings[i].m16);
     RefPtr<nsAtom> atom8 = NS_Atomize(ValidStrings[i].m8);
     EXPECT_EQ(atom16, atom8);
   }
 }
 
-TEST(Atoms, BufferSharing)
-{
-  nsString unique;
-  unique.AssignLiteral("this is a unique string !@#$");
-
-  RefPtr<nsAtom> atom = NS_Atomize(unique);
-
-  EXPECT_EQ(unique.get(), atom->GetUTF16String());
-}
-
 TEST(Atoms, Null)
 {
   nsAutoString str(NS_LITERAL_STRING("string with a \0 char"));
   nsDependentString strCut(str.get());
 
   EXPECT_FALSE(str.Equals(strCut));
 
   RefPtr<nsAtom> atomCut = NS_Atomize(strCut);