Bug 1304913 - Have Servo manage node data directly without FFI calls. r=Manishearth
authorBobby Holley <bobbyholley@gmail.com>
Wed, 21 Sep 2016 15:42:45 -0700
changeset 315211 dfc1afe56b75b0eb563e1fe8ed74af7d51b8ebe0
parent 315210 06baf9c96c5b2f45df49941ef00f190c79445295
child 315212 16daeb9b4e1773b3159932ac362c09a66441ceb2
push id32563
push userihsiao@mozilla.com
push dateMon, 26 Sep 2016 11:18:33 +0000
treeherderautoland@eb840c87b5fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersManishearth
bugs1304913
milestone52.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 1304913 - Have Servo manage node data directly without FFI calls. r=Manishearth MozReview-Commit-ID: H8f8VP18TbM
dom/base/Element.cpp
dom/base/nsGenericDOMDataNode.cpp
dom/base/nsINode.cpp
dom/base/nsINode.h
layout/base/ServoRestyleManager.cpp
layout/base/nsCSSFrameConstructor.cpp
layout/style/ServoBindingList.h
layout/style/ServoBindings.cpp
layout/style/ServoBindings.h
layout/style/ServoTypes.h
layout/style/moz.build
layout/style/nsStyleStruct.h
--- a/dom/base/Element.cpp
+++ b/dom/base/Element.cpp
@@ -1737,17 +1737,17 @@ Element::BindToTree(nsIDocument* aDocume
   // It would be cleanest to mark nodes as dirty when (a) they're created and
   // (b) they're unbound from a tree. However, we can't easily do (a) right now,
   // because IsStyledByServo() is not always easy to check at node creation time,
   // and the bits have different meaning in the non-IsStyledByServo case.
   //
   // So for now, we just mark nodes as dirty when they're inserted into a
   // document or shadow tree.
   if (IsStyledByServo() && IsInComposedDoc()) {
-    MOZ_ASSERT(!ServoData().get());
+    MOZ_ASSERT(!HasServoData());
     SetIsDirtyForServo();
   }
 
   // XXXbz script execution during binding can trigger some of these
   // postcondition asserts....  But we do want that, since things will
   // generally be quite broken when that happens.
   NS_POSTCONDITION(aDocument == GetUncomposedDoc(), "Bound to wrong document");
   NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
@@ -1852,20 +1852,20 @@ Element::UnbindFromTree(bool aDeep, bool
     DeleteProperty(nsGkAtoms::animationsProperty);
   }
 
   ClearInDocument();
 
   // Computed styled data isn't useful for detached nodes, and we'll need to
   // recomputed it anyway if we ever insert the nodes back into a document.
   if (IsStyledByServo()) {
-    ServoData().reset();
+    ClearServoData();
   } else {
 #ifdef MOZ_STYLO
-    MOZ_ASSERT(!ServoData());
+    MOZ_ASSERT(!HasServoData());
 #endif
   }
 
   // Editable descendant count only counts descendants that
   // are in the uncomposed document.
   ResetEditableDescendantCount();
 
   if (aNullParent || !mParent->IsInShadowTree()) {
--- a/dom/base/nsGenericDOMDataNode.cpp
+++ b/dom/base/nsGenericDOMDataNode.cpp
@@ -562,17 +562,17 @@ nsGenericDOMDataNode::BindToTree(nsIDocu
   // It would be cleanest to mark nodes as dirty when (a) they're created and
   // (b) they're unbound from a tree. However, we can't easily do (a) right now,
   // because IsStyledByServo() is not always easy to check at node creation time,
   // and the bits have different meaning in the non-IsStyledByServo case.
   //
   // So for now, we just mark nodes as dirty when they're inserted into a
   // document or shadow tree.
   if (IsStyledByServo() && IsInComposedDoc()) {
-    MOZ_ASSERT(!ServoData().get());
+    MOZ_ASSERT(!HasServoData());
     SetIsDirtyForServo();
   }
 
   NS_POSTCONDITION(aDocument == GetUncomposedDoc(), "Bound to wrong document");
   NS_POSTCONDITION(aParent == GetParent(), "Bound to wrong parent");
   NS_POSTCONDITION(aBindingParent == GetBindingParent(),
                    "Bound to wrong binding parent");
 
@@ -600,20 +600,20 @@ nsGenericDOMDataNode::UnbindFromTree(boo
     }
     SetParentIsContent(false);
   }
   ClearInDocument();
 
   // Computed styled data isn't useful for detached nodes, and we'll need to
   // recomputed it anyway if we ever insert the nodes back into a document.
   if (IsStyledByServo()) {
-    ServoData().reset();
+    ClearServoData();
   } else {
 #ifdef MOZ_STYLO
-    MOZ_ASSERT(!ServoData());
+    MOZ_ASSERT(!HasServoData());
 #endif
   }
 
   if (aNullParent || !mParent->IsInShadowTree()) {
     UnsetFlags(NODE_IS_IN_SHADOW_TREE);
 
     // Begin keeping track of our subtree root.
     SetSubtreeRootPointer(aNullParent ? this : mParent->SubtreeRoot());
--- a/dom/base/nsINode.cpp
+++ b/dom/base/nsINode.cpp
@@ -147,16 +147,19 @@ nsINode::nsSlots::Unlink()
 }
 
 //----------------------------------------------------------------------
 
 nsINode::~nsINode()
 {
   MOZ_ASSERT(!HasSlots(), "nsNodeUtils::LastRelease was not called?");
   MOZ_ASSERT(mSubtreeRoot == this, "Didn't restore state properly?");
+#ifdef MOZ_STYLO
+  ClearServoData();
+#endif
 }
 
 void*
 nsINode::GetProperty(uint16_t aCategory, nsIAtom *aPropertyName,
                      nsresult *aStatus) const
 {
   return OwnerDoc()->PropertyTable(aCategory)->GetProperty(this, aPropertyName,
                                                            aStatus);
--- a/dom/base/nsINode.h
+++ b/dom/base/nsINode.h
@@ -3,16 +3,17 @@
 /* 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 nsINode_h___
 #define nsINode_h___
 
 #include "mozilla/Likely.h"
+#include "mozilla/ServoTypes.h"
 #include "mozilla/UniquePtr.h"
 #include "nsCOMPtr.h"               // for member, local
 #include "nsGkAtoms.h"              // for nsGkAtoms::baseURIProperty
 #include "nsIDOMNode.h"
 #include "mozilla/dom/NodeInfo.h"            // member (in nsCOMPtr)
 #include "nsIVariant.h"             // for use in GetUserData()
 #include "nsNodeInfoManager.h"      // for use in NodePrincipal()
 #include "nsPropertyTable.h"        // for typedefs
@@ -48,31 +49,17 @@ class nsINode;
 class nsINodeList;
 class nsIPresShell;
 class nsIPrincipal;
 class nsIURI;
 class nsNodeSupportsWeakRefTearoff;
 class nsNodeWeakReference;
 class nsDOMMutationObserver;
 
-// We declare the bare minimum infrastructure here to allow us to have a
-// UniquePtr<ServoNodeData> on nsINode.
-struct ServoNodeData;
-extern "C" void Servo_NodeData_Drop(ServoNodeData*);
-namespace mozilla {
-template<>
-class DefaultDelete<ServoNodeData>
-{
-public:
-  void operator()(ServoNodeData* aPtr) const
-  {
-    Servo_NodeData_Drop(aPtr);
-  }
-};
-} // namespace mozilla
+extern "C" void Servo_Node_ClearNodeData(nsINode*);
 
 namespace mozilla {
 class EventListenerManager;
 namespace dom {
 /**
  * @return true if aChar is what the DOM spec defines as 'space character'.
  * http://dom.spec.whatwg.org/#space-character
  */
@@ -2085,19 +2072,27 @@ public:
   void SetOn##name_(mozilla::dom::EventHandlerNonNull* listener);
 #define TOUCH_EVENT EVENT
 #define DOCUMENT_ONLY_EVENT EVENT
 #include "mozilla/EventNameList.h"
 #undef DOCUMENT_ONLY_EVENT
 #undef TOUCH_EVENT
 #undef EVENT
 
-  mozilla::UniquePtr<ServoNodeData>& ServoData() {
+  bool HasServoData() {
 #ifdef MOZ_STYLO
-    return mServoNodeData;
+    return !!mServoData.Get();
+#else
+    MOZ_CRASH("Accessing servo node data in non-stylo build");
+#endif
+  }
+
+  void ClearServoData() {
+#ifdef MOZ_STYLO
+    Servo_Node_ClearNodeData(this);
 #else
     MOZ_CRASH("Accessing servo node data in non-stylo build");
 #endif
   }
 
 protected:
   static bool Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb);
   static void Unlink(nsINode *tmp);
@@ -2132,18 +2127,18 @@ protected:
     // object itself, or is reset by ClearSubtreeRootPointer.
     nsINode* MOZ_NON_OWNING_REF mSubtreeRoot;
   };
 
   // Storage for more members that are usually not needed; allocated lazily.
   nsSlots* mSlots;
 
 #ifdef MOZ_STYLO
-  // Layout data managed by Servo.
-  mozilla::UniquePtr<ServoNodeData> mServoNodeData;
+  // Per-node data managed by Servo.
+  mozilla::ServoCell<ServoNodeData*> mServoData;
 #endif
 };
 
 inline nsIDOMNode* GetAsDOMNode(nsINode* aNode)
 {
   return aNode ? aNode->AsDOMNode() : nullptr;
 }
 
--- a/layout/base/ServoRestyleManager.cpp
+++ b/layout/base/ServoRestyleManager.cpp
@@ -381,17 +381,17 @@ ServoRestyleManager::ContentInserted(nsI
     //
     // Either way the whole tree is dirty, so we should style the document.
     MOZ_ASSERT(aChild == aChild->OwnerDoc()->GetRootElement());
     MOZ_ASSERT(aChild->IsDirtyForServo());
     StyleSet()->StyleDocument(/* aLeaveDirtyBits = */ false);
     return;
   }
 
-  if (!aContainer->ServoData().get()) {
+  if (!aContainer->HasServoData()) {
     // This can happen with display:none. Bug 1297249 tracks more investigation
     // and assertions here.
     return;
   }
 
   // Style the new subtree because we will most likely need it during subsequent
   // frame construction. Bug 1298281 tracks deferring this work in the lazy
   // frame construction case.
@@ -412,17 +412,17 @@ ServoRestyleManager::RestyleForAppend(ns
   // Bug 1297899 tracks this work.
   //
 }
 
 void
 ServoRestyleManager::ContentAppended(nsIContent* aContainer,
                                      nsIContent* aFirstNewContent)
 {
-  if (!aContainer->ServoData().get()) {
+  if (!aContainer->HasServoData()) {
     // This can happen with display:none. Bug 1297249 tracks more investigation
     // and assertions here.
     return;
   }
 
   // Style the new subtree because we will most likely need it during subsequent
   // frame construction. Bug 1298281 tracks deferring this work in the lazy
   // frame construction case.
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -10588,23 +10588,23 @@ nsCSSFrameConstructor::AddFCItemsForAnon
       parentDisplayBasedStyleFixupSkipper(aState.mTreeMatchContext);
     if (aAnonymousItems[i].mStyleContext) {
       // If we have an explicit style context, that means that the anonymous
       // content creator had its own plan for the style, and doesn't need the
       // computed style obtained by cascading this content as a normal node.
       // This happens when a native anonymous node is used to implement a
       // pseudo-element. Allowing Servo to traverse these nodes would be wasted
       // work, so assert that we didn't do that.
-      MOZ_ASSERT_IF(content->IsStyledByServo(), !content->ServoData());
+      MOZ_ASSERT_IF(content->IsStyledByServo(), !content->HasServoData());
       styleContext = aAnonymousItems[i].mStyleContext.forget();
     } else {
       // If we don't have an explicit style context, that means we need the
       // ordinary computed values. Make sure we eagerly cascaded them when the
       // anonymous nodes were created.
-      MOZ_ASSERT_IF(content->IsStyledByServo(), !!content->ServoData());
+      MOZ_ASSERT_IF(content->IsStyledByServo(), content->HasServoData());
       styleContext = ResolveStyleContext(aFrame, content, &aState);
     }
 
     nsTArray<nsIAnonymousContentCreator::ContentInfo>* anonChildren = nullptr;
     if (!aAnonymousItems[i].mChildren.IsEmpty()) {
       anonChildren = &aAnonymousItems[i].mChildren;
     }
 
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -14,17 +14,17 @@
  * and the parameter list of the function.
  *
  * Users of this list should define a macro
  * SERVO_BINDING_FUNC(name_, return_, ...)
  * before including this file.
  */
 
 // Node data
-SERVO_BINDING_FUNC(Servo_NodeData_Drop, void, ServoNodeDataOwned data)
+SERVO_BINDING_FUNC(Servo_Node_ClearNodeData, void, RawGeckoNode* node)
 
 // Styleset and Stylesheet management
 SERVO_BINDING_FUNC(Servo_StyleSheet_FromUTF8Bytes, RawServoStyleSheetStrong,
                    const uint8_t* bytes, uint32_t length,
                    mozilla::css::SheetParsingMode parsing_mode,
                    const uint8_t* base_bytes, uint32_t base_length,
                    ThreadSafeURIHolder* base,
                    ThreadSafeURIHolder* referrer,
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -564,29 +564,16 @@ ClassOrClassList(Implementor* aElement, 
     return ClassOrClassList(aElement, aClass, aClassList);                     \
   }
 
 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElementBorrowed)
 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot, ServoElementSnapshot*)
 
 #undef SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS
 
-ServoNodeDataBorrowedOrNull
-Gecko_GetNodeData(RawGeckoNodeBorrowed aNode)
-{
-  return aNode->ServoData().get();
-}
-
-void
-Gecko_SetNodeData(RawGeckoNodeBorrowed aNode, ServoNodeDataOwned aData)
-{
-  MOZ_ASSERT(!aNode->ServoData());
-  aNode->ServoData().reset(aData);
-}
-
 nsIAtom*
 Gecko_Atomize(const char* aString, uint32_t aLength)
 {
   return NS_Atomize(nsDependentCSubstring(aString, aLength)).take();
 }
 
 void
 Gecko_AddRefAtom(nsIAtom* aAtom)
--- a/layout/style/ServoBindings.h
+++ b/layout/style/ServoBindings.h
@@ -2,52 +2,49 @@
 /* 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_ServoBindings_h
 #define mozilla_ServoBindings_h
 
+#include "mozilla/ServoTypes.h"
 #include "mozilla/ServoElementSnapshot.h"
 #include "mozilla/css/SheetParsingMode.h"
+#include "mozilla/dom/Element.h"
+#include "nsIDocument.h"
+#include "nsINode.h"
 #include "nsChangeHint.h"
 #include "nsColor.h"
 #include "nsProxyRelease.h"
 #include "nsStyleCoord.h"
 #include "nsStyleStruct.h"
 #include "stdint.h"
 
 /*
  * API for Servo to access Gecko data structures. This file must compile as valid
  * C code in order for the binding generator to parse it.
  *
  * Functions beginning with Gecko_ are implemented in Gecko and invoked from Servo.
  * Functions beginning with Servo_ are implemented in Servo and invoked from Gecko.
  */
 
 class nsIAtom;
-class nsINode;
-typedef nsINode RawGeckoNode;
 class nsIPrincipal;
 class nsIURI;
 struct nsFont;
 namespace mozilla {
   class FontFamilyList;
   enum FontFamilyType : uint32_t;
-  namespace dom { class Element; }
 }
 using mozilla::FontFamilyList;
 using mozilla::FontFamilyType;
 using mozilla::dom::Element;
 using mozilla::ServoElementSnapshot;
-typedef mozilla::dom::Element RawGeckoElement;
-class nsIDocument;
-typedef nsIDocument RawGeckoDocument;
-struct ServoNodeData;
 struct ServoComputedValues;
 struct RawServoStyleSheet;
 struct RawServoStyleSet;
 class nsHTMLCSSStyleSheet;
 struct nsStyleList;
 struct nsStyleImage;
 struct nsStyleGradientStop;
 class nsStyleGradient;
@@ -102,18 +99,16 @@ using mozilla::dom::StyleChildrenIterato
   DECL_NULLABLE_BORROWED_REF_TYPE_FOR(type_)       \
   DECL_NULLABLE_BORROWED_MUT_REF_TYPE_FOR(type_)
 
 DECL_ARC_REF_TYPE_FOR(ServoComputedValues)
 DECL_ARC_REF_TYPE_FOR(RawServoStyleSheet)
 DECL_ARC_REF_TYPE_FOR(ServoDeclarationBlock)
 
 DECL_OWNED_REF_TYPE_FOR(RawServoStyleSet)
-DECL_NULLABLE_OWNED_REF_TYPE_FOR(ServoNodeData)
-DECL_OWNED_REF_TYPE_FOR(ServoNodeData)
 DECL_NULLABLE_OWNED_REF_TYPE_FOR(StyleChildrenIterator)
 DECL_OWNED_REF_TYPE_FOR(StyleChildrenIterator)
 
 // We don't use BorrowedMut because the nodes may alias
 // Servo itself doesn't directly read or mutate these;
 // it only asks Gecko to do so. In case we wish to in
 // the future, we should ensure that things being mutated
 // are protected from noalias violations by a cell type
@@ -218,20 +213,16 @@ SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNC
 SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot,
                                               ServoElementSnapshot*)
 
 #undef SERVO_DECLARE_ELEMENT_ATTR_MATCHING_FUNCTIONS
 
 // Style attributes.
 ServoDeclarationBlockBorrowedOrNull Gecko_GetServoDeclarationBlock(RawGeckoElementBorrowed element);
 
-// Node data.
-ServoNodeDataBorrowedOrNull Gecko_GetNodeData(RawGeckoNodeBorrowed node);
-void Gecko_SetNodeData(RawGeckoNodeBorrowed node, ServoNodeDataOwned data);
-
 // Atoms.
 nsIAtom* Gecko_Atomize(const char* aString, uint32_t aLength);
 void Gecko_AddRefAtom(nsIAtom* aAtom);
 void Gecko_ReleaseAtom(nsIAtom* aAtom);
 const uint16_t* Gecko_GetAtomAsUTF16(nsIAtom* aAtom, uint32_t* aLength);
 bool Gecko_AtomEqualsUTF8(nsIAtom* aAtom, const char* aString, uint32_t aLength);
 bool Gecko_AtomEqualsUTF8IgnoreCase(nsIAtom* aAtom, const char* aString, uint32_t aLength);
 
new file mode 100644
--- /dev/null
+++ b/layout/style/ServoTypes.h
@@ -0,0 +1,40 @@
+/* -*- 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_ServoTypes_h
+#define mozilla_ServoTypes_h
+
+/*
+ * Type definitions used to interact with Servo. This gets included by nsINode,
+ * so don't add significant include dependencies to this file.
+ */
+
+struct ServoNodeData;
+namespace mozilla {
+
+/*
+ * Replaced types. These get mapped to associated Servo types in bindgen.
+ */
+
+template<typename T>
+struct ServoUnsafeCell {
+  T value;
+
+  // Ensure that primitive types (i.e. pointers) get zero-initialized.
+  ServoUnsafeCell() : value() {};
+};
+
+template<typename T>
+struct ServoCell {
+  ServoUnsafeCell<T> value;
+  T Get() const { return value.value; }
+  void Set(T arg) { value.value = arg; }
+  ServoCell() : value() {};
+};
+
+} // namespace mozilla
+
+#endif // mozilla_ServoTypes_h
--- a/layout/style/moz.build
+++ b/layout/style/moz.build
@@ -92,16 +92,17 @@ EXPORTS.mozilla += [
     'RuleNodeCacheConditions.h',
     'RuleProcessorCache.h',
     'ServoBindingHelpers.h',
     'ServoBindingList.h',
     'ServoBindings.h',
     'ServoElementSnapshot.h',
     'ServoStyleSet.h',
     'ServoStyleSheet.h',
+    'ServoTypes.h',
     'SheetType.h',
     'StyleAnimationValue.h',
     'StyleBackendType.h',
     'StyleComplexColor.h',
     'StyleContextSource.h',
     'StyleSetHandle.h',
     'StyleSetHandleInlines.h',
     'StyleSheet.h',
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -42,16 +42,21 @@
 
 class nsIFrame;
 class nsIURI;
 class nsStyleContext;
 class nsTextFrame;
 class imgIContainer;
 struct nsStyleVisibility;
 
+typedef nsINode RawGeckoNode;
+typedef mozilla::dom::Element RawGeckoElement;
+typedef nsIDocument RawGeckoDocument;
+struct ServoNodeData;
+
 // Includes nsStyleStructID.
 #include "nsStyleStructFwd.h"
 
 // Bits for each struct.
 // NS_STYLE_INHERIT_BIT defined in nsStyleStructFwd.h
 #define NS_STYLE_INHERIT_MASK              0x000ffffff
 
 // Bits for inherited structs.