Bug 1433579 - Allow recursively holding the APZ tree lock. r?botond draft
authorKartikaya Gupta <kgupta@mozilla.com>
Wed, 31 Jan 2018 12:00:19 -0500
changeset 749569 584d527967839b44e3bb64b3471ead74d49bdde6
parent 749389 7b46ef2ae1412b15ed45e7d2367ca491344729f7
push id97440
push userkgupta@mozilla.com
push dateWed, 31 Jan 2018 18:26:05 +0000
reviewersbotond
bugs1433579
milestone60.0a1
Bug 1433579 - Allow recursively holding the APZ tree lock. r?botond MozReview-Commit-ID: DzLgqb2wMN9
gfx/layers/apz/src/APZCTreeManager.cpp
gfx/layers/apz/src/APZCTreeManager.h
--- a/gfx/layers/apz/src/APZCTreeManager.cpp
+++ b/gfx/layers/apz/src/APZCTreeManager.cpp
@@ -153,17 +153,17 @@ NS_IMPL_ISUPPORTS(APZCTreeManager::Check
 NS_IMETHODIMP
 APZCTreeManager::CheckerboardFlushObserver::Observe(nsISupports* aSubject,
                                                     const char* aTopic,
                                                     const char16_t*)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(mTreeManager.get());
 
-  MutexAutoLock lock(mTreeManager->mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeManager->mTreeLock);
   if (mTreeManager->mRootNode) {
     ForEachNode<ReverseIterator>(mTreeManager->mRootNode.get(),
         [](HitTestingTreeNode* aNode)
         {
           if (aNode->IsPrimaryHolder()) {
             MOZ_ASSERT(aNode->GetApzc());
             aNode->GetApzc()->FlushActiveCheckerboardReport();
           }
@@ -289,17 +289,17 @@ template<class ScrollNode> void // Scrol
 APZCTreeManager::UpdateHitTestingTreeImpl(uint64_t aRootLayerTreeId,
                                           const ScrollNode& aRoot,
                                           bool aIsFirstPaint,
                                           uint64_t aOriginatingLayersId,
                                           uint32_t aPaintSequenceNumber)
 {
   APZThreadUtils::AssertOnCompositorThread();
 
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
 
   // For testing purposes, we log some data to the APZTestData associated with
   // the layers id that originated this update.
   APZTestData* testData = nullptr;
   if (gfxPrefs::APZTestLoggingEnabled()) {
     if (LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(aOriginatingLayersId)) {
       testData = &state->mApzTestData;
       testData->StartNewPaint(aPaintSequenceNumber);
@@ -339,17 +339,17 @@ APZCTreeManager::UpdateHitTestingTreeImp
     HitTestingTreeNode* next = nullptr;
     uint64_t layersId = aRootLayerTreeId;
     ancestorTransforms.push(AncestorTransform());
     state.mParentHasPerspective.push(false);
 
     state.mLayersIdsToDestroy.erase(aRootLayerTreeId);
 
     mApzcTreeLog << "[start]\n";
-    mTreeLock.AssertCurrentThreadOwns();
+    mTreeLock.AssertCurrentThreadIn();
 
     ForEachNode<ReverseIterator>(aRoot,
         [&](ScrollNode aLayerMetrics)
         {
           mApzcTreeLog << aLayerMetrics.Name() << '\t';
 
           HitTestingTreeNode* node = PrepareNodeForLayer(aLayerMetrics,
                 aLayerMetrics.Metrics(), layersId, ancestorTransforms.top(),
@@ -497,17 +497,17 @@ APZCTreeManager::UpdateHitTestingTree(ui
 
 bool
 APZCTreeManager::PushStateToWR(wr::TransactionBuilder& aTxn,
                                const TimeStamp& aSampleTime,
                                nsTArray<wr::WrTransformProperty>& aTransformArray)
 {
   APZThreadUtils::AssertOnCompositorThread();
 
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
 
   // During the first pass through the tree, we build a cache of guid->HTTN so
   // that we can find the relevant APZC instances quickly in subsequent passes,
   // such as the one below to generate scrollbar transforms. Without this, perf
   // could end up being O(n^2) instead of O(n log n) because we'd have to search
   // the tree to find the corresponding APZC every time we hit a thumb node.
   std::unordered_map<ScrollableLayerGuid, HitTestingTreeNode*, ScrollableLayerGuidHash> httnMap;
 
@@ -773,17 +773,17 @@ template<class ScrollNode> HitTestingTre
 APZCTreeManager::PrepareNodeForLayer(const ScrollNode& aLayer,
                                      const FrameMetrics& aMetrics,
                                      uint64_t aLayersId,
                                      const AncestorTransform& aAncestorTransform,
                                      HitTestingTreeNode* aParent,
                                      HitTestingTreeNode* aNextSibling,
                                      TreeBuildingState& aState)
 {
-  mTreeLock.AssertCurrentThreadOwns();
+  mTreeLock.AssertCurrentThreadIn();
 
   bool needsApzc = true;
   if (!aMetrics.IsScrollable()) {
     needsApzc = false;
   }
 
   const LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(aLayersId);
   if (!(state && state->mController.get())) {
@@ -1069,17 +1069,17 @@ APZCTreeManager::ReceiveInputEvent(Input
 
   // Use a RAII class for updating the focus sequence number of this event
   AutoFocusSequenceNumberSetter focusSetter(mFocusState, aEvent);
 
 #if defined(MOZ_WIDGET_ANDROID)
   MOZ_ASSERT(mToolbarAnimator);
   ScreenPoint scrollOffset;
   {
-    MutexAutoLock lock(mTreeLock);
+    RecursiveMutexAutoLock lock(mTreeLock);
     RefPtr<AsyncPanZoomController> apzc = FindRootContentOrRootApzc();
     if (apzc) {
       scrollOffset = ViewAs<ScreenPixel>(apzc->GetCurrentAsyncScrollOffset(AsyncPanZoomController::eForHitTesting),
                                          PixelCastJustification::ScreenIsParentLayerForRoot);
     }
   }
   nsEventStatus isConsumed = mToolbarAnimator->ReceiveInputEvent(aEvent, scrollOffset);
   // Check if the mToolbarAnimator consumed the event.
@@ -1119,17 +1119,17 @@ APZCTreeManager::ReceiveInputEvent(Input
       RefPtr<HitTestingTreeNode> hitScrollbarNode = nullptr;
       RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(mouseInput.mOrigin,
             &hitResult, &hitScrollbarNode);
       bool hitScrollbar = hitScrollbarNode;
 
       // When the mouse is outside the window we still want to handle dragging
       // but we won't find an APZC. Fallback to root APZC then.
       { // scope lock
-        MutexAutoLock lock(mTreeLock);
+        RecursiveMutexAutoLock lock(mTreeLock);
         if (!apzc && mRootNode) {
           apzc = mRootNode->GetApzc();
         }
       }
 
       if (apzc) {
         if (gfxPrefs::APZTestLoggingEnabled() && mouseInput.mType == MouseInput::MOUSE_HITTEST) {
           ScrollableLayerGuid guid = apzc->GetGuid();
@@ -1734,17 +1734,17 @@ APZCTreeManager::SetupScrollbarDrag(Mous
     // ConvertScrollbarPoint() got the drag start offset relative to
     // the scroll track. Now get it relative to the thumb.
     // ScrollThumbData::mThumbStart stores the offset of the thumb
     // relative to the scroll track at the time of the last paint.
     // Since that paint, the thumb may have acquired an async transform
     // due to async scrolling, so look that up and apply it.
     LayerToParentLayerMatrix4x4 thumbTransform;
     {
-      MutexAutoLock lock(mTreeLock);
+      RecursiveMutexAutoLock lock(mTreeLock);
       thumbTransform = ComputeTransformForNode(aScrollThumbNode);
     }
     // Only consider the translation, since we do not support both
     // zooming and scrollbar dragging on any platform.
     CSSCoord thumbStart = thumbData.mThumbStart
                         + ((*thumbData.mDirection == ScrollDirection::eHorizontal)
                            ? thumbTransform._41 : thumbTransform._42);
     dragStart -= thumbStart;
@@ -1898,17 +1898,17 @@ APZCTreeManager::SetTargetAPZC(uint64_t 
   RefPtr<AsyncPanZoomController> apzc = GetTargetAPZC(aTarget);
   mInputQueue->SetConfirmedTargetApzc(aInputBlockId, apzc);
 }
 
 void
 APZCTreeManager::UpdateZoomConstraints(const ScrollableLayerGuid& aGuid,
                                        const Maybe<ZoomConstraints>& aConstraints)
 {
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
   RefPtr<HitTestingTreeNode> node = GetTargetNode(aGuid, nullptr);
   MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
 
   // Propagate the zoom constraints down to the subtree, stopping at APZCs
   // which have their own zoom constraints or are in a different layers id.
   if (aConstraints) {
     APZCTM_LOG("Recording constraints %s for guid %s\n",
       Stringify(aConstraints.value()).c_str(), Stringify(aGuid).c_str());
@@ -1957,18 +1957,17 @@ APZCTreeManager::FlushRepaintsToClearScr
   // hits a dispatch-to-content region then that's an ambiguous result and we
   // need to ask Gecko what actually got hit. In order to do this we need to
   // untransform the input event into Gecko space - but to do that we need to
   // know which APZC got hit! This leads to a circular dependency; the only way
   // to get out of it is to make sure that the untransform for all the possible
   // matched APZCs is the same. It is simplest to ensure that by flushing the
   // pending repaint requests, which makes all of the untransforms empty (and
   // therefore equal).
-  MutexAutoLock lock(mTreeLock);
-  mTreeLock.AssertCurrentThreadOwns();
+  RecursiveMutexAutoLock lock(mTreeLock);
 
   ForEachNode<ReverseIterator>(mRootNode.get(),
       [](HitTestingTreeNode* aNode)
       {
         if (aNode->IsPrimaryHolder()) {
           MOZ_ASSERT(aNode->GetApzc());
           aNode->GetApzc()->FlushRepaintForNewInputBlock();
         }
@@ -1982,33 +1981,33 @@ APZCTreeManager::CancelAnimation(const S
   if (apzc) {
     apzc->CancelAnimation();
   }
 }
 
 void
 APZCTreeManager::AdjustScrollForSurfaceShift(const ScreenPoint& aShift)
 {
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
   RefPtr<AsyncPanZoomController> apzc = FindRootContentOrRootApzc();
   if (apzc) {
     apzc->AdjustScrollForSurfaceShift(aShift);
   }
 }
 
 void
 APZCTreeManager::ClearTree()
 {
   // Ensure that no references to APZCs are alive in any lingering input
   // blocks. This breaks cycles from InputBlockState::mTargetApzc back to
   // the InputQueue.
   APZThreadUtils::RunOnControllerThread(NewRunnableMethod(
     "layers::InputQueue::Clear", mInputQueue, &InputQueue::Clear));
 
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
 
   // Collect the nodes into a list, and then destroy each one.
   // We can't destroy them as we collect them, because ForEachNode()
   // does a pre-order traversal of the tree, and Destroy() nulls out
   // the fields needed to reach the children of the node.
   nsTArray<RefPtr<HitTestingTreeNode>> nodesToDestroy;
   ForEachNode<ReverseIterator>(mRootNode.get(),
       [&nodesToDestroy](HitTestingTreeNode* aNode)
@@ -2027,17 +2026,17 @@ APZCTreeManager::ClearTree()
       self->mFlushObserver->Unregister();
       self->mFlushObserver = nullptr;
     }));
 }
 
 RefPtr<HitTestingTreeNode>
 APZCTreeManager::GetRootNode() const
 {
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
   return mRootNode;
 }
 
 /**
  * Transform a displacement from the ParentLayer coordinates of a source APZC
  * to the ParentLayer coordinates of a target APZC.
  * @param aTreeManager the tree manager for the APZC tree containing |aSource|
  *                     and |aTarget|
@@ -2230,17 +2229,17 @@ APZCTreeManager::HitTestAPZC(const Scree
 {
   RefPtr<AsyncPanZoomController> target = GetTargetAPZC(aPoint, nullptr);
   return target != nullptr;
 }
 
 already_AddRefed<AsyncPanZoomController>
 APZCTreeManager::GetTargetAPZC(const ScrollableLayerGuid& aGuid)
 {
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
   RefPtr<HitTestingTreeNode> node = GetTargetNode(aGuid, nullptr);
   MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
   RefPtr<AsyncPanZoomController> apzc = node ? node->GetApzc() : nullptr;
   return apzc.forget();
 }
 
 static bool
 GuidComparatorIgnoringPresShell(const ScrollableLayerGuid& aOne, const ScrollableLayerGuid& aTwo)
@@ -2248,29 +2247,29 @@ GuidComparatorIgnoringPresShell(const Sc
   return aOne.mLayersId == aTwo.mLayersId
       && aOne.mScrollId == aTwo.mScrollId;
 }
 
 already_AddRefed<AsyncPanZoomController>
 APZCTreeManager::GetTargetAPZC(const uint64_t& aLayersId,
                                const FrameMetrics::ViewID& aScrollId)
 {
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
   ScrollableLayerGuid guid(aLayersId, 0, aScrollId);
   RefPtr<HitTestingTreeNode> node = GetTargetNode(guid, &GuidComparatorIgnoringPresShell);
   MOZ_ASSERT(!node || node->GetApzc()); // any node returned must have an APZC
   RefPtr<AsyncPanZoomController> apzc = node ? node->GetApzc() : nullptr;
   return apzc.forget();
 }
 
 already_AddRefed<HitTestingTreeNode>
 APZCTreeManager::GetTargetNode(const ScrollableLayerGuid& aGuid,
                                GuidComparator aComparator) const
 {
-  mTreeLock.AssertCurrentThreadOwns();
+  mTreeLock.AssertCurrentThreadIn();
   RefPtr<HitTestingTreeNode> target = DepthFirstSearchPostOrder<ReverseIterator>(mRootNode.get(),
       [&aGuid, &aComparator](HitTestingTreeNode* node)
       {
         bool matches = false;
         if (node->GetApzc()) {
           if (aComparator) {
             matches = aComparator(aGuid, node->GetApzc()->GetGuid());
           } else {
@@ -2283,17 +2282,17 @@ APZCTreeManager::GetTargetNode(const Scr
   return target.forget();
 }
 
 already_AddRefed<AsyncPanZoomController>
 APZCTreeManager::GetTargetAPZC(const ScreenPoint& aPoint,
                                CompositorHitTestInfo* aOutHitResult,
                                RefPtr<HitTestingTreeNode>* aOutScrollbarNode)
 {
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
 
   CompositorHitTestInfo hitResult = CompositorHitTestInfo::eInvisibleToHitTest;
   HitTestingTreeNode* scrollbarNode = nullptr;
   RefPtr<AsyncPanZoomController> target;
   if (gfx::gfxVars::UseWebRender() && gfxPrefs::WebRenderHitTest()) {
     target = GetAPZCAtPointWR(aPoint, &hitResult, &scrollbarNode);
   } else {
     target = GetAPZCAtPoint(mRootNode, aPoint, &hitResult, &scrollbarNode);
@@ -2380,17 +2379,17 @@ APZCTreeManager::BuildOverscrollHandoffC
   // something higher up in the tree.
   // It's not sufficient to just find the initial target, however, as
   // overscroll can be handed off to another APZC. Without scroll grabbing,
   // handoff just occurs from child to parent. With scroll grabbing, the
   // handoff order can be different, so we build a chain of APZCs in the
   // order in which scroll will be handed off to them.
 
   // Grab tree lock since we'll be walking the APZC tree.
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
 
   // Build the chain. If there is a scroll parent link, we use that. This is
   // needed to deal with scroll info layers, because they participate in handoff
   // but do not follow the expected layer tree structure. If there are no
   // scroll parent links we just walk up the tree to find the scroll parent.
   OverscrollHandoffChain* result = new OverscrollHandoffChain;
   AsyncPanZoomController* apzc = aInitialTarget;
   while (apzc != nullptr) {
@@ -2454,17 +2453,17 @@ APZCTreeManager::SetLongTapEnabled(bool 
   APZThreadUtils::RunOnControllerThread(
     NewRunnableFunction("SetLongTapEnabledRunnable",
                         GestureEventListener::SetLongTapEnabled, aLongTapEnabled));
 }
 
 RefPtr<HitTestingTreeNode>
 APZCTreeManager::FindScrollThumbNode(const AsyncDragMetrics& aDragMetrics)
 {
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
 
   return DepthFirstSearch<ReverseIterator>(mRootNode.get(),
       [&aDragMetrics](HitTestingTreeNode* aNode) {
         return aNode->MatchesScrollDragMetrics(aDragMetrics);
       });
 }
 
 AsyncPanZoomController*
@@ -2488,17 +2487,17 @@ APZCTreeManager::GetTargetApzcForNode(Hi
 }
 
 AsyncPanZoomController*
 APZCTreeManager::GetAPZCAtPoint(HitTestingTreeNode* aNode,
                                 const ScreenPoint& aHitTestPoint,
                                 CompositorHitTestInfo* aOutHitResult,
                                 HitTestingTreeNode** aOutScrollbarNode)
 {
-  mTreeLock.AssertCurrentThreadOwns();
+  mTreeLock.AssertCurrentThreadIn();
 
   // This walks the tree in depth-first, reverse order, so that it encounters
   // APZCs front-to-back on the screen.
   HitTestingTreeNode* resultNode;
   HitTestingTreeNode* root = aNode;
   std::stack<LayerPoint> hitTestPoints;
   ParentLayerPoint point = ViewAs<ParentLayerPixel>(aHitTestPoint,
       PixelCastJustification::ScreenIsParentLayerForRoot);
@@ -2581,47 +2580,47 @@ APZCTreeManager::GetAPZCAtPoint(HitTesti
   }
 
   return nullptr;
 }
 
 AsyncPanZoomController*
 APZCTreeManager::FindRootApzcForLayersId(uint64_t aLayersId) const
 {
-  mTreeLock.AssertCurrentThreadOwns();
+  mTreeLock.AssertCurrentThreadIn();
 
   HitTestingTreeNode* resultNode = BreadthFirstSearch<ReverseIterator>(mRootNode.get(),
       [aLayersId](HitTestingTreeNode* aNode) {
         AsyncPanZoomController* apzc = aNode->GetApzc();
         return apzc
             && apzc->GetLayersId() == aLayersId
             && apzc->IsRootForLayersId();
       });
   return resultNode ? resultNode->GetApzc() : nullptr;
 }
 
 AsyncPanZoomController*
 APZCTreeManager::FindRootContentApzcForLayersId(uint64_t aLayersId) const
 {
-  mTreeLock.AssertCurrentThreadOwns();
+  mTreeLock.AssertCurrentThreadIn();
 
   HitTestingTreeNode* resultNode = BreadthFirstSearch<ReverseIterator>(mRootNode.get(),
       [aLayersId](HitTestingTreeNode* aNode) {
         AsyncPanZoomController* apzc = aNode->GetApzc();
         return apzc
             && apzc->GetLayersId() == aLayersId
             && apzc->IsRootContent();
       });
   return resultNode ? resultNode->GetApzc() : nullptr;
 }
 
 AsyncPanZoomController*
 APZCTreeManager::FindRootContentOrRootApzc() const
 {
-  mTreeLock.AssertCurrentThreadOwns();
+  mTreeLock.AssertCurrentThreadIn();
 
   // Note: this is intended to find the same "root" that would be found
   // by AsyncCompositionManager::ApplyAsyncContentTransformToTree inside
   // the MOZ_WIDGET_ANDROID block. That is, it should find the RCD node if there
   // is one, or the root APZC if there is not.
   // Since BreadthFirstSearch is a pre-order search, we first do a search for
   // the RCD, and then if we don't find one, we do a search for the root APZC.
   HitTestingTreeNode* resultNode = BreadthFirstSearch<ReverseIterator>(mRootNode.get(),
@@ -2733,17 +2732,17 @@ APZCTreeManager::FindRootContentOrRootAp
 
 /*
  * See the long comment above for a detailed explanation of this function.
  */
 ScreenToParentLayerMatrix4x4
 APZCTreeManager::GetScreenToApzcTransform(const AsyncPanZoomController *aApzc) const
 {
   Matrix4x4 result;
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
 
   // The comments below assume there is a chain of layers L..R with L and P having APZC instances as
   // explained in the comment above. This function is called with aApzc at L, and the loop
   // below performs one iteration, where parent is at P. The comments explain what values are stored
   // in the variables at these two levels. All the comments use standard matrix notation where the
   // leftmost matrix in a multiplication is applied first.
 
   // ancestorUntransform is PC.Inverse() * OC.Inverse() * NC.Inverse() * MC.Inverse()
@@ -2774,17 +2773,17 @@ APZCTreeManager::GetScreenToApzcTransfor
 /*
  * See the long comment above GetScreenToApzcTransform() for a detailed
  * explanation of this function.
  */
 ParentLayerToScreenMatrix4x4
 APZCTreeManager::GetApzcToGeckoTransform(const AsyncPanZoomController *aApzc) const
 {
   Matrix4x4 result;
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
 
   // The comments below assume there is a chain of layers L..R with L and P having APZC instances as
   // explained in the comment above. This function is called with aApzc at L, and the loop
   // below performs one iteration, where parent is at P. The comments explain what values are stored
   // in the variables at these two levels. All the comments use standard matrix notation where the
   // leftmost matrix in a multiplication is applied first.
 
   // asyncUntransform is LA.Inverse()
@@ -2809,17 +2808,17 @@ ScreenPoint
 APZCTreeManager::GetCurrentMousePosition() const
 {
   return mCurrentMousePosition;
 }
 
 already_AddRefed<AsyncPanZoomController>
 APZCTreeManager::GetMultitouchTarget(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const
 {
-  MutexAutoLock lock(mTreeLock);
+  RecursiveMutexAutoLock lock(mTreeLock);
   RefPtr<AsyncPanZoomController> apzc;
   // For now, we only ever want to do pinching on the root-content APZC for
   // a given layers id.
   if (aApzc1 && aApzc2 && aApzc1->GetLayersId() == aApzc2->GetLayersId()) {
     // If the two APZCs have the same layers id, find the root-content APZC
     // for that layers id. Don't call CommonAncestor() because there may not
     // be a common ancestor for the layers id (e.g. if one APZCs is inside a
     // fixed-position element).
@@ -2833,17 +2832,17 @@ APZCTreeManager::GetMultitouchTarget(Asy
     }
   }
   return apzc.forget();
 }
 
 already_AddRefed<AsyncPanZoomController>
 APZCTreeManager::CommonAncestor(AsyncPanZoomController* aApzc1, AsyncPanZoomController* aApzc2) const
 {
-  mTreeLock.AssertCurrentThreadOwns();
+  mTreeLock.AssertCurrentThreadIn();
   RefPtr<AsyncPanZoomController> ancestor;
 
   // If either aApzc1 or aApzc2 is null, min(depth1, depth2) will be 0 and this function
   // will return null.
 
   // Calculate depth of the APZCs in the tree
   int depth1 = 0, depth2 = 0;
   for (AsyncPanZoomController* parent = aApzc1; parent; parent = parent->GetParent()) {
@@ -2879,17 +2878,17 @@ APZCTreeManager::CommonAncestor(AsyncPan
     aApzc2 = aApzc2->GetParent();
   }
   return ancestor.forget();
 }
 
 LayerToParentLayerMatrix4x4
 APZCTreeManager::ComputeTransformForNode(const HitTestingTreeNode* aNode) const
 {
-  mTreeLock.AssertCurrentThreadOwns();
+  mTreeLock.AssertCurrentThreadIn();
   if (AsyncPanZoomController* apzc = aNode->GetApzc()) {
     // If the node represents scrollable content, apply the async transform
     // from its APZC.
     return aNode->GetTransform() *
         CompleteAsyncTransform(
           apzc->GetCurrentAsyncTransformWithOverscroll(AsyncPanZoomController::eForHitTesting));
   } else if (aNode->IsScrollThumbNode()) {
     // If the node represents a scrollbar thumb, compute and apply the
--- a/gfx/layers/apz/src/APZCTreeManager.h
+++ b/gfx/layers/apz/src/APZCTreeManager.h
@@ -13,17 +13,17 @@
 #include "mozilla/Assertions.h"         // for MOZ_ASSERT_HELPER2
 #include "mozilla/gfx/CompositorHitTestInfo.h"
 #include "mozilla/gfx/Logging.h"        // for gfx::TreeLog
 #include "mozilla/gfx/Matrix.h"         // for Matrix4x4
 #include "mozilla/layers/TouchCounter.h"// for TouchCounter
 #include "mozilla/layers/IAPZCTreeManager.h" // for IAPZCTreeManager
 #include "mozilla/layers/KeyboardMap.h" // for KeyboardMap
 #include "mozilla/layers/FocusState.h"  // for FocusState
-#include "mozilla/Mutex.h"              // for Mutex
+#include "mozilla/RecursiveMutex.h"     // for RecursiveMutex
 #include "mozilla/RefPtr.h"             // for RefPtr
 #include "mozilla/TimeStamp.h"          // for mozilla::TimeStamp
 #include "nsCOMPtr.h"                   // for already_AddRefed
 
 #if defined(MOZ_WIDGET_ANDROID)
 #include "mozilla/layers/AndroidDynamicToolbarAnimator.h"
 #endif // defined(MOZ_WIDGET_ANDROID)
 
@@ -644,17 +644,17 @@ private:
 
   /* Whenever walking or mutating the tree rooted at mRootNode, mTreeLock must be held.
    * This lock does not need to be held while manipulating a single APZC instance in
    * isolation (that is, if its tree pointers are not being accessed or mutated). The
    * lock also needs to be held when accessing the mRootNode instance variable, as that
    * is considered part of the APZC tree management state.
    * Finally, the lock needs to be held when accessing mZoomConstraints.
    * IMPORTANT: See the note about lock ordering at the top of this file. */
-  mutable mozilla::Mutex mTreeLock;
+  mutable mozilla::RecursiveMutex mTreeLock;
   RefPtr<HitTestingTreeNode> mRootNode;
   /* Holds the zoom constraints for scrollable layers, as determined by the
    * the main-thread gecko code. */
   std::unordered_map<ScrollableLayerGuid, ZoomConstraints, ScrollableLayerGuidHash> mZoomConstraints;
   /* A list of keyboard shortcuts to use for translating keyboard inputs into
    * keyboard actions. This is gathered on the main thread from XBL bindings.
    */
   KeyboardMap mKeyboardMap;