Bug 1684673 - Use an AutoTArray for atom arrays in attributes (class / part). r=smaug
authorEmilio Cobos Álvarez <emilio@crisal.io>
Mon, 04 Jan 2021 17:56:33 +0000
changeset 561924 a41340d05455017826f66c78bf142e5aa53dbd16
parent 561923 3cd4564f4138d9958c1712b3c133115bdb50b2e7
child 561925 0aca729356b37e74d278c87504c077c898062529
push id133480
push userealvarez@mozilla.com
push dateMon, 04 Jan 2021 17:59:19 +0000
treeherderautoland@a41340d05455 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1684673
milestone86.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 1684673 - Use an AutoTArray for atom arrays in attributes (class / part). r=smaug These are never empty, and storing 4 elements inline seems worth it given we also heap-allocate the array itself. Depends on D100592 Differential Revision: https://phabricator.services.mozilla.com/D100593
dom/base/nsDOMTokenList.cpp
dom/base/nsDOMTokenList.h
servo/components/style/gecko/snapshot_helpers.rs
servo/ports/geckolib/glue.rs
xpcom/ds/AtomArray.h
--- a/dom/base/nsDOMTokenList.cpp
+++ b/dom/base/nsDOMTokenList.cpp
@@ -48,16 +48,31 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsDOMTo
 
 const nsAttrValue* nsDOMTokenList::GetParsedAttr() {
   if (!mElement) {
     return nullptr;
   }
   return mElement->GetAttrInfo(kNameSpaceID_None, mAttrAtom).mValue;
 }
 
+static void RemoveDuplicatesInternal(AtomArray* aArray, uint32_t aStart) {
+  nsDataHashtable<nsPtrHashKey<nsAtom>, bool> tokens;
+
+  for (uint32_t i = 0; i < aArray->Length(); i++) {
+    nsAtom* atom = aArray->ElementAt(i);
+    // No need to check the hashtable below aStart
+    if (i >= aStart && tokens.Get(atom)) {
+      aArray->RemoveElementAt(i);
+      i--;
+    } else {
+      tokens.Put(atom, true);
+    }
+  }
+}
+
 void nsDOMTokenList::RemoveDuplicates(const nsAttrValue* aAttr) {
   if (!aAttr || aAttr->Type() != nsAttrValue::eAtomArray) {
     return;
   }
 
   BloomFilter<8, nsAtom> filter;
   AtomArray* array = aAttr->GetAtomArrayValue();
   for (uint32_t i = 0; i < array->Length(); i++) {
@@ -67,32 +82,16 @@ void nsDOMTokenList::RemoveDuplicates(co
       RemoveDuplicatesInternal(array, i);
       return;
     } else {
       filter.add(atom);
     }
   }
 }
 
-void nsDOMTokenList::RemoveDuplicatesInternal(AtomArray* aArray,
-                                              uint32_t aStart) {
-  nsDataHashtable<nsPtrHashKey<nsAtom>, bool> tokens;
-
-  for (uint32_t i = 0; i < aArray->Length(); i++) {
-    nsAtom* atom = aArray->ElementAt(i);
-    // No need to check the hashtable below aStart
-    if (i >= aStart && tokens.Get(atom)) {
-      aArray->RemoveElementAt(i);
-      i--;
-    } else {
-      tokens.Put(atom, true);
-    }
-  }
-}
-
 uint32_t nsDOMTokenList::Length() {
   const nsAttrValue* attr = GetParsedAttr();
   if (!attr) {
     return 0;
   }
 
   RemoveDuplicates(attr);
   return attr->GetAtomCount();
--- a/dom/base/nsDOMTokenList.h
+++ b/dom/base/nsDOMTokenList.h
@@ -78,18 +78,16 @@ class nsDOMTokenList : public nsISupport
   void GetValue(nsAString& aResult);
   void SetValue(const nsAString& aValue, mozilla::ErrorResult& rv);
 
  protected:
   virtual ~nsDOMTokenList();
 
   nsresult CheckToken(const nsAString& aStr);
   nsresult CheckTokens(const nsTArray<nsString>& aStr);
-  void RemoveDuplicatesInternal(nsTArray<RefPtr<nsAtom>>* aArray,
-                                uint32_t aStart);
   void AddInternal(const nsAttrValue* aAttr, const nsTArray<nsString>& aTokens);
   void RemoveInternal(const nsAttrValue* aAttr,
                       const nsTArray<nsString>& aTokens);
   bool ReplaceInternal(const nsAttrValue* aAttr, const nsAString& aToken,
                        const nsAString& aNewToken);
   inline const nsAttrValue* GetParsedAttr();
 
   nsCOMPtr<Element> mElement;
--- a/servo/components/style/gecko/snapshot_helpers.rs
+++ b/servo/components/style/gecko/snapshot_helpers.rs
@@ -38,24 +38,26 @@ unsafe fn get_class_or_part_from_attr(at
         return Class::One(ptr::<nsAtom>(attr));
     }
     if base_type == structs::nsAttrValue_ValueBaseType_eOtherBase {
         let container = ptr::<structs::MiscContainer>(attr);
         debug_assert_eq!(
             (*container).mType,
             structs::nsAttrValue_ValueType_eAtomArray
         );
-        let array = (*container)
+        // NOTE: Bindgen doesn't deal with AutoTArray, so cast it below.
+        let array: *mut u8 = *(*container)
             .__bindgen_anon_1
             .mValue
             .as_ref()
             .__bindgen_anon_1
             .mAtomArray
             .as_ref();
-        return Class::More(&***array)
+        let array = array as *const structs::nsTArray<structs::RefPtr<nsAtom>>;
+        return Class::More(&**array)
     }
     debug_assert_eq!(base_type, structs::nsAttrValue_ValueBaseType_eStringBase);
     Class::None
 }
 
 #[inline(always)]
 unsafe fn get_id_from_attr(attr: &structs::nsAttrValue) -> &WeakAtom {
     debug_assert_eq!(
@@ -127,17 +129,18 @@ pub fn has_class_or_part(
     case_sensitivity: CaseSensitivity,
     attr: &structs::nsAttrValue,
 ) -> bool {
     match unsafe { get_class_or_part_from_attr(attr) } {
         Class::None => false,
         Class::One(atom) => unsafe { case_sensitivity.eq_atom(name, WeakAtom::new(atom)) },
         Class::More(atoms) => match case_sensitivity {
             CaseSensitivity::CaseSensitive => {
-                atoms.iter().any(|atom| atom.mRawPtr == name.as_ptr())
+                let name_ptr = name.as_ptr();
+                atoms.iter().any(|atom| atom.mRawPtr == name_ptr)
             },
             CaseSensitivity::AsciiCaseInsensitive => unsafe {
                 atoms
                     .iter()
                     .any(|atom| WeakAtom::new(atom.mRawPtr).eq_ignore_ascii_case(name))
             },
         },
     }
--- a/servo/ports/geckolib/glue.rs
+++ b/servo/ports/geckolib/glue.rs
@@ -55,17 +55,16 @@ use style::gecko_bindings::structs::nsCS
 use style::gecko_bindings::structs::nsCSSFontDesc;
 use style::gecko_bindings::structs::nsCSSPropertyID;
 use style::gecko_bindings::structs::nsChangeHint;
 use style::gecko_bindings::structs::nsCompatibility;
 use style::gecko_bindings::structs::nsStyleTransformMatrix::MatrixTransformOperator;
 use style::gecko_bindings::structs::nsTArray;
 use style::gecko_bindings::structs::nsTimingFunction;
 use style::gecko_bindings::structs::nsresult;
-use style::gecko_bindings::structs::AtomArray;
 use style::gecko_bindings::structs::CallerType;
 use style::gecko_bindings::structs::CompositeOperation;
 use style::gecko_bindings::structs::DeclarationBlockMutationClosure;
 use style::gecko_bindings::structs::IterationCompositeOperation;
 use style::gecko_bindings::structs::Loader;
 use style::gecko_bindings::structs::LoaderReusableStyleSheets;
 use style::gecko_bindings::structs::MallocSizeOf as GeckoMallocSizeOf;
 use style::gecko_bindings::structs::OriginFlags;
@@ -3693,17 +3692,17 @@ pub extern "C" fn Servo_ResolvePseudoSty
         Some(s) => s.into(),
         None => {
             debug_assert!(is_probe);
             Strong::null()
         },
     }
 }
 
-fn debug_atom_array(atoms: &AtomArray) -> String {
+fn debug_atom_array(atoms: &nsTArray<structs::RefPtr<nsAtom>>) -> String {
     let mut result = String::from("[");
     for atom in atoms.iter() {
         if atom.mRawPtr.is_null() {
             result += "(null), ";
         } else {
             let atom = unsafe { WeakAtom::new(atom.mRawPtr) };
             write!(result, "{}, ", atom).unwrap();
         }
@@ -3712,17 +3711,17 @@ fn debug_atom_array(atoms: &AtomArray) -
     result
 }
 
 #[no_mangle]
 pub extern "C" fn Servo_ComputedValues_ResolveXULTreePseudoStyle(
     element: &RawGeckoElement,
     pseudo_tag: *mut nsAtom,
     inherited_style: &ComputedValues,
-    input_word: &AtomArray,
+    input_word: &nsTArray<structs::RefPtr<nsAtom>>,
     raw_data: &RawServoStyleSet,
 ) -> Strong<ComputedValues> {
     let element = GeckoElement(element);
     let data = element
         .borrow_data()
         .expect("Calling ResolveXULTreePseudoStyle on unstyled element?");
 
     let pseudo = unsafe {
--- a/xpcom/ds/AtomArray.h
+++ b/xpcom/ds/AtomArray.h
@@ -8,12 +8,12 @@
 #define mozilla_AtomArray_h
 
 #include "mozilla/RefPtr.h"
 #include "nsTArray.h"
 
 class nsAtom;
 
 namespace mozilla {
-typedef nsTArray<RefPtr<nsAtom>> AtomArray;
+typedef AutoTArray<RefPtr<nsAtom>, 4> AtomArray;
 }
 
 #endif  // mozilla_AtomArray_h