Bug 1356103 - Part 4: Add a mechanism for C++ functions to perform post-Servo traversal tasks. r=bholley draft
authorCameron McCormack <cam@mcc.id.au>
Sun, 30 Apr 2017 14:45:32 +0800
changeset 572576 e4c231fa09ec1eb15db9b4a8b40385bb6971d3f2
parent 572575 5d58bfbab0ad0d11c5bfc500e46bc0307beb98a4
child 572577 281e0b2118e6e79a6756636fff7373f316894c44
push id57115
push userbmo:cam@mcc.id.au
push dateThu, 04 May 2017 10:01:25 +0000
reviewersbholley
bugs1356103
milestone55.0a1
Bug 1356103 - Part 4: Add a mechanism for C++ functions to perform post-Servo traversal tasks. r=bholley MozReview-Commit-ID: 5Gx1qZzQxAK
layout/style/PostTraversalTask.cpp
layout/style/PostTraversalTask.h
layout/style/ServoStyleSet.cpp
layout/style/ServoStyleSet.h
layout/style/moz.build
new file mode 100644
--- /dev/null
+++ b/layout/style/PostTraversalTask.cpp
@@ -0,0 +1,16 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#include "PostTraversalTask.h"
+
+namespace mozilla {
+
+void
+PostTraversalTask::Run()
+{
+}
+
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/style/PostTraversalTask.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 mozilla_PostTraversalTask_h
+#define mozilla_PostTraversalTask_h
+
+/* a task to be performed immediately after a Servo traversal */
+
+namespace mozilla {
+
+/**
+ * A PostTraversalTask is a task to be performed immediately after a Servo
+ * traversal.  There are just a few tasks we need to perform, so we use this
+ * class rather than Runnables, to avoid virtual calls and some allocations.
+ *
+ * A PostTraversalTask is only safe to run immediately after the Servo
+ * traversal, since it can hold raw pointers to DOM objects.
+ */
+class PostTraversalTask
+{
+public:
+  void Run();
+
+private:
+  enum class Type
+  {
+    Dummy,
+  };
+
+  explicit PostTraversalTask(Type aType)
+    : mType(aType)
+    , mTarget(nullptr)
+  {
+  }
+
+  Type mType;
+  void* mTarget;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_PostTraversalTask_h
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -1101,9 +1101,26 @@ ServoStyleSet::RemoveSheetOfType(SheetTy
       uint32_t uniqueID = mEntries[aType][i].uniqueID;
       mEntries[aType].RemoveElementAt(i);
       return uniqueID;
     }
   }
   return 0;
 }
 
+void
+ServoStyleSet::RunPostTraversalTasks()
+{
+  MOZ_ASSERT(!IsInServoTraversal());
+
+  if (mPostTraversalTasks.IsEmpty()) {
+    return;
+  }
+
+  nsTArray<PostTraversalTask> tasks;
+  tasks.SwapElements(mPostTraversalTasks);
+
+  for (auto& task : tasks) {
+    task.Run();
+  }
+}
+
 ServoStyleSet* ServoStyleSet::sInServoTraversal = nullptr;
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -4,18 +4,20 @@
  * 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 mozilla_ServoStyleSet_h
 #define mozilla_ServoStyleSet_h
 
 #include "mozilla/EnumeratedArray.h"
 #include "mozilla/EventStates.h"
+#include "mozilla/PostTraversalTask.h"
 #include "mozilla/ServoBindingTypes.h"
 #include "mozilla/ServoElementSnapshot.h"
+#include "mozilla/ServoUtils.h"
 #include "mozilla/StyleSheetInlines.h"
 #include "mozilla/SheetType.h"
 #include "mozilla/UniquePtr.h"
 #include "MainThreadUtils.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsChangeHint.h"
 #include "nsIAtom.h"
@@ -308,32 +310,52 @@ public:
   already_AddRefed<ServoComputedValues>
   ResolveForDeclarations(ServoComputedValuesBorrowedOrNull aParentOrNull,
                          RawServoDeclarationBlockBorrowed aDeclarations);
 
   already_AddRefed<RawServoAnimationValue>
   ComputeAnimationValue(RawServoDeclarationBlock* aDeclaration,
                         const ServoComputedValuesWithParent& aComputedValues);
 
+  void AppendTask(PostTraversalTask aTask)
+  {
+    MOZ_ASSERT(IsInServoTraversal());
+
+    // We currently only use PostTraversalTasks while the Servo font metrics
+    // mutex is locked.  If we need to use them in other situations during
+    // a traversal, we should assert that we've taken appropriate
+    // synchronization measures.
+    AssertIsMainThreadOrServoFontMetricsLocked();
+
+    mPostTraversalTasks.AppendElement(aTask);
+  }
+
 private:
+  // On construction, sets sInServoTraversal to the given ServoStyleSet.
+  // On destruction, clears sInServoTraversal and calls RunPostTraversalTasks.
   class MOZ_STACK_CLASS AutoSetInServoTraversal
   {
   public:
     explicit AutoSetInServoTraversal(ServoStyleSet* aSet)
+      : mSet(aSet)
     {
       MOZ_ASSERT(!sInServoTraversal);
       MOZ_ASSERT(aSet);
       sInServoTraversal = aSet;
     }
 
     ~AutoSetInServoTraversal()
     {
       MOZ_ASSERT(sInServoTraversal);
       sInServoTraversal = nullptr;
+      mSet->RunPostTraversalTasks();
     }
+
+  private:
+    ServoStyleSet* mSet;
   };
 
   already_AddRefed<nsStyleContext> GetContext(already_AddRefed<ServoComputedValues>,
                                               nsStyleContext* aParentContext,
                                               nsIAtom* aPseudoTag,
                                               CSSPseudoElementType aPseudoType,
                                               dom::Element* aElementForAnimation);
 
@@ -373,16 +395,18 @@ private:
    */
   void PreTraverse(dom::Element* aRoot = nullptr);
   // Subset of the pre-traverse steps that involve syncing up data
   void PreTraverseSync();
 
   already_AddRefed<ServoComputedValues> ResolveStyleLazily(dom::Element* aElement,
                                                            nsIAtom* aPseudoTag);
 
+  void RunPostTraversalTasks();
+
   uint32_t FindSheetOfType(SheetType aType,
                            ServoStyleSheet* aSheet);
 
   uint32_t PrependSheetOfType(SheetType aType,
                               ServoStyleSheet* aSheet,
                               uint32_t aReuseUniqueID = 0);
 
   uint32_t AppendSheetOfType(SheetType aType,
@@ -416,14 +440,20 @@ private:
   bool mAuthorStyleDisabled;
 
   // Stores pointers to our cached style contexts for non-inheriting anonymous
   // boxes.
   EnumeratedArray<nsCSSAnonBoxes::NonInheriting,
                   nsCSSAnonBoxes::NonInheriting::_Count,
                   RefPtr<nsStyleContext>> mNonInheritingStyleContexts;
 
+  // Tasks to perform after a traversal, back on the main thread.
+  //
+  // These are similar to Servo's SequentialTasks, except that they are
+  // posted by C++ code running on style worker threads.
+  nsTArray<PostTraversalTask> mPostTraversalTasks;
+
   static ServoStyleSet* sInServoTraversal;
 };
 
 } // namespace mozilla
 
 #endif // mozilla_ServoStyleSet_h
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -88,16 +88,17 @@ EXPORTS.mozilla += [
     'DeclarationBlock.h',
     'DeclarationBlockInlines.h',
     'DocumentStyleRootIterator.h',
     'GenericSpecifiedValues.h',
     'GenericSpecifiedValuesInlines.h',
     'HandleRefPtr.h',
     'IncrementalClearCOMRuleArray.h',
     'LayerAnimationInfo.h',
+    'PostTraversalTask.h',
     'PreloadedStyleSheet.h',
     'RuleNodeCacheConditions.h',
     'RuleProcessorCache.h',
     'ServoArcTypeList.h',
     'ServoBindingList.h',
     'ServoBindings.h',
     'ServoBindingTypes.h',
     'ServoCSSRuleList.h',
@@ -214,16 +215,17 @@ UNIFIED_SOURCES += [
     'nsRuleNode.cpp',
     'nsStyleContext.cpp',
     'nsStyleCoord.cpp',
     'nsStyleSet.cpp',
     'nsStyleStruct.cpp',
     'nsStyleTransformMatrix.cpp',
     'nsStyleUtil.cpp',
     'nsTransitionManager.cpp',
+    'PostTraversalTask.cpp',
     'PreloadedStyleSheet.cpp',
     'RuleNodeCacheConditions.cpp',
     'RuleProcessorCache.cpp',
     'ServoBindings.cpp',
     'ServoCSSRuleList.cpp',
     'ServoDeclarationBlock.cpp',
     'ServoElementSnapshot.cpp',
     'ServoMediaList.cpp',