diff --git a/layout/base/nsDisplayList.cpp b/layout/base/nsDisplayList.cpp index 40d279dae..23e5316d4 100644 --- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -694,7 +694,7 @@ AnimatedGeometryRoot* nsDisplayListBuilder::WrapAGRForFrame(nsIFrame* aAnimatedGeometryRoot, AnimatedGeometryRoot* aParent /* = nullptr */) { - MOZ_ASSERT(IsAnimatedGeometryRoot(aAnimatedGeometryRoot)); + MOZ_ASSERT(IsAnimatedGeometryRoot(aAnimatedGeometryRoot) == AGR_YES); AnimatedGeometryRoot* result = nullptr; if (!mFrameToAnimatedGeometryRootMap.Get(aAnimatedGeometryRoot, &result)) { @@ -1079,66 +1079,91 @@ IsStickyFrameActive(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame, nsIFrame* return sf->IsScrollingActive(aBuilder) && sf->GetScrolledFrame() == cursor; } -bool +nsDisplayListBuilder::AGRState nsDisplayListBuilder::IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent) { if (aFrame == mReferenceFrame) { - return true; + return AGR_YES; } if (!IsPaintingToWindow()) { if (aParent) { *aParent = nsLayoutUtils::GetCrossDocParentFrame(aFrame); } - return false; + return AGR_NO; } if (nsLayoutUtils::IsPopup(aFrame)) - return true; + return AGR_YES; if (ActiveLayerTracker::IsOffsetOrMarginStyleAnimated(aFrame)) - return true; + // XXX: If we wanted to implement an AGRBudget, that's here. + // See bug 1247554, but it might not be needed since we have bug 1231818. + + return AGR_YES; if (!aFrame->GetParent() && nsLayoutUtils::ViewportHasDisplayPort(aFrame->PresContext())) { // Viewport frames in a display port need to be animated geometry roots // for background-attachment:fixed elements. - return true; + return AGR_YES; } if (aFrame->IsTransformed()) { - return true; + return AGR_YES; } nsIFrame* parent = nsLayoutUtils::GetCrossDocParentFrame(aFrame); if (!parent) - return true; + return AGR_YES; + + bool maybe = false; // Possible to transition from not being an AGR + // to being an AGR without a style change. nsIAtom* parentType = parent->GetType(); // Treat the slider thumb as being as an active scrolled root when it wants // its own layer so that it can move without repainting. - if (parentType == nsGkAtoms::sliderFrame && nsLayoutUtils::IsScrollbarThumbLayerized(aFrame)) { - return true; + if (parentType == nsGkAtoms::sliderFrame) { + if (nsLayoutUtils::IsScrollbarThumbLayerized(aFrame)) { + return AGR_YES; + } + maybe = true; } - if (aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY && - IsStickyFrameActive(this, aFrame, parent)) - { - return true; + if (aFrame->StyleDisplay()->mPosition == NS_STYLE_POSITION_STICKY) { + if (IsStickyFrameActive(this, aFrame, parent)) { + return AGR_YES; + } + maybe = true; } if (parentType == nsGkAtoms::scrollFrame || parentType == nsGkAtoms::listControlFrame) { nsIScrollableFrame* sf = do_QueryFrame(parent); - if (sf->IsScrollingActive(this) && sf->GetScrolledFrame() == aFrame) { - return true; + if (sf->GetScrolledFrame() == aFrame) { + if (sf->IsScrollingActive(this)) { + return AGR_YES; + } + maybe = true; } } // Fixed-pos frames are parented by the viewport frame, which has no parent. if (nsLayoutUtils::IsFixedPosFrameInDisplayPort(aFrame)) { - return true; + return AGR_YES; + } + + if ((aFrame->GetStateBits() & NS_FRAME_MAY_BE_TRANSFORMED) && + aFrame->IsFrameOfType(nsIFrame::eSVG)) { + // For SVG containers, they always have + // NS_FRAME_MAY_BE_TRANSFORMED bit. However, they would be + // affected by the fragement identifiers in the svgView form at + // runtime without a new style context. + // For example, layout/reftests/svg/fragmentIdentifier-01.xhtml + // + // see https://www.w3.org/TR/SVG/linking.html#SVGFragmentIdentifiers + maybe = true; } if (aParent) { *aParent = parent; } - return false; + return !maybe ? AGR_NO : AGR_MAYBE; } nsIFrame* @@ -1148,7 +1173,7 @@ nsDisplayListBuilder::FindAnimatedGeometryRootFrameFor(nsIFrame* aFrame) nsIFrame* cursor = aFrame; while (cursor != RootReferenceFrame()) { nsIFrame* next; - if (IsAnimatedGeometryRoot(cursor, &next)) + if (IsAnimatedGeometryRoot(cursor, &next) == AGR_YES) return cursor; cursor = next; } @@ -1159,7 +1184,7 @@ void nsDisplayListBuilder::RecomputeCurrentAnimatedGeometryRoot() { if (*mCurrentAGR != mCurrentFrame && - IsAnimatedGeometryRoot(const_cast(mCurrentFrame))) { + IsAnimatedGeometryRoot(const_cast(mCurrentFrame)) == AGR_YES) { AnimatedGeometryRoot* oldAGR = mCurrentAGR; mCurrentAGR = WrapAGRForFrame(const_cast(mCurrentFrame), mCurrentAGR); diff --git a/layout/base/nsDisplayList.h b/layout/base/nsDisplayList.h index aa8a69b24..a770da648 100644 --- a/layout/base/nsDisplayList.h +++ b/layout/base/nsDisplayList.h @@ -160,6 +160,15 @@ class nsDisplayListBuilder { typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect; typedef mozilla::LayoutDeviceIntRegion LayoutDeviceIntRegion; + /** + * A frame can be in one of three states of AGR. + * AGR_NO means the frame is not an AGR for now. + * AGR_YES means the frame is an AGR for now. + * AGR_MAYBE means the frame is not an AGR for now, but a transition + * to AGR_YES without restyling is possible. + */ + enum AGRState { AGR_NO, AGR_YES, AGR_MAYBE }; + public: typedef mozilla::FramePropertyDescriptor FramePropertyDescriptor; typedef mozilla::FrameLayerBuilder FrameLayerBuilder; @@ -636,8 +645,9 @@ public: aBuilder->FindReferenceFrameFor(aForChild, &aBuilder->mCurrentOffsetToReferenceFrame); } + mCurrentAGRState = aBuilder->IsAnimatedGeometryRoot(aForChild); if (aBuilder->mCurrentFrame == aForChild->GetParent()) { - if (aBuilder->IsAnimatedGeometryRoot(aForChild)) { + if (mCurrentAGRState == AGR_YES) { aBuilder->mCurrentAGR = aBuilder->WrapAGRForFrame(aForChild, aBuilder->mCurrentAGR); } } else if (aForChild != aBuilder->mCurrentFrame) { @@ -661,8 +671,10 @@ public: return mPrevAnimatedGeometryRoot; } bool IsAnimatedGeometryRoot() const { - return *mBuilder->mCurrentAGR == mBuilder->mCurrentFrame; - + return mCurrentAGRState == AGR_YES; + } + bool MaybeAnimatedGeometryRoot() const { + return mCurrentAGRState == AGR_MAYBE; } ~AutoBuildingDisplayList() { mBuilder->mCurrentFrame = mPrevFrame; @@ -676,6 +688,7 @@ public: } private: nsDisplayListBuilder* mBuilder; + AGRState mCurrentAGRState; const nsIFrame* mPrevFrame; const nsIFrame* mPrevReferenceFrame; nsIFrame* mPrevAnimatedGeometryRoot; @@ -938,7 +951,7 @@ private: * Returns whether a frame acts as an animated geometry root, optionally * returning the next ancestor to check. */ - bool IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent = nullptr); + AGRState IsAnimatedGeometryRoot(nsIFrame* aFrame, nsIFrame** aParent = nullptr); /** * Returns the nearest ancestor frame to aFrame that is considered to have diff --git a/layout/generic/nsFrame.cpp b/layout/generic/nsFrame.cpp index 15ff42276..44116634e 100644 --- a/layout/generic/nsFrame.cpp +++ b/layout/generic/nsFrame.cpp @@ -870,6 +870,12 @@ nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext) if (StyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL) { PresContext()->SetBidiEnabled(); } + + /* bug 1342009 has the following: + RemoveStateBits(NS_FRAME_SIMPLE_EVENT_REGIONS | + NS_FRAME_SIMPLE_DISPLAYLIST); + */ + RemoveStateBits(NS_FRAME_SIMPLE_DISPLAYLIST); } // MSVC fails with link error "one or more multiply defined symbols found", @@ -1705,8 +1711,10 @@ ApplyClipPropClipping(nsDisplayListBuilder* aBuilder, * handled by constructing a dedicated nsHTML/XULScrollFrame, set up clipping * for that overflow in aBuilder->ClipState() to clip all containing-block * descendants. + * + * Return true if clipping was applied. */ -static void +static bool ApplyOverflowClipping(nsDisplayListBuilder* aBuilder, const nsIFrame* aFrame, const nsStyleDisplay* aDisp, @@ -1718,7 +1726,7 @@ ApplyOverflowClipping(nsDisplayListBuilder* aBuilder, // is required by comboboxes which make their display text (an inline frame) // have clipping. if (!nsFrame::ShouldApplyOverflowClipping(aFrame, aDisp)) { - return; + return false; } nsRect clipRect; bool haveRadii = false; @@ -1734,6 +1742,7 @@ ApplyOverflowClipping(nsDisplayListBuilder* aBuilder, // XXX border-radius } aClipState.ClipContainingBlockDescendantsExtra(clipRect, haveRadii ? radii : nullptr); + return true; } #ifdef DEBUG @@ -2334,6 +2343,45 @@ WrapInWrapList(nsDisplayListBuilder* aBuilder, return item; } +/** + * Check if a frame should be visited for building display list. + */ +static bool +DescendIntoChild(nsDisplayListBuilder* aBuilder, nsIFrame *aChild, + const nsRect& aDirty) +{ + nsIFrame* child = aChild; + const nsRect& dirty = aDirty; + + if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) { + // No need to descend into child to catch placeholders for visible + // positioned stuff. So see if we can short-circuit frame traversal here. + + // We can stop if child's frame subtree's intersection with the + // dirty area is empty. + // If the child is a scrollframe that we want to ignore, then we need + // to descend into it because its scrolled child may intersect the dirty + // area even if the scrollframe itself doesn't. + // There are cases where the "ignore scroll frame" on the builder is not set + // correctly, and so we additionally want to catch cases where the child is + // a root scrollframe and we are ignoring scrolling on the viewport. + nsIPresShell* shell = child->PresContext()->PresShell(); + bool keepDescending = child == aBuilder->GetIgnoreScrollFrame() || + (shell->IgnoringViewportScrolling() && child == shell->GetRootScrollFrame()); + if (!keepDescending) { + nsRect childDirty; + if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect())) + return false; + // Usually we could set dirty to childDirty now but there's no + // benefit, and it can be confusing. It can especially confuse + // situations where we're going to ignore a scrollframe's clipping; + // we wouldn't want to clip the dirty area to the scrollframe's + // bounds in that case. + } + } + return true; +} + void nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, nsIFrame* aChild, @@ -2349,11 +2397,59 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, if (child->GetStateBits() & NS_FRAME_TOO_DEEP_IN_FRAME_TREE) return; + const bool doingShortcut = + (child->GetStateBits() & NS_FRAME_SIMPLE_DISPLAYLIST) && + aBuilder->IsPaintingToWindow() && + // This would be changed by the change of preference. + aBuilder->IsBuildingLayerEventRegions() && + // Animations may change the value of |HasOpacity()|. + !(child->GetContent() && + child->GetContent()->MayHaveAnimations()); + if (doingShortcut) { + // This is the shortcut for frames been handled along the common + // path, the most common one of THE COMMON CASE mentioned later. + MOZ_ASSERT(child->Type() != LayoutFrameType::Placeholder); + MOZ_ASSERT(!aBuilder->GetSelectedFramesOnly() && + !aBuilder->GetIncludeAllOutOfFlows(), + "It should be held for painting to window"); + + // dirty rect in child-relative coordinates + nsRect dirty = aDirtyRect - child->GetOffsetTo(this); + if (!DescendIntoChild(aBuilder, child, dirty)) { + return; + } + + nsDisplayListBuilder::AutoBuildingDisplayList + buildingForChild(aBuilder, child, dirty, false); + + CheckForApzAwareEventHandlers(aBuilder, child); + + nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions(); + if (eventRegions) { + eventRegions->AddFrame(aBuilder, child); + } + + child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty); + aBuilder->AdjustWindowDraggingRegion(child); + child->BuildDisplayList(aBuilder, dirty, aLists); + aBuilder->DisplayCaret(child, dirty, aLists.Content()); +#ifdef DEBUG +// DisplayDebugBorders(aBuilder, child, aLists); +#endif + return; + } + bool isSVG = (child->GetStateBits() & NS_FRAME_SVG_LAYOUT); + // It is raised if the control flow strays off the common path. + // The common path is the most common one of THE COMMON CASE + // mentioned later. + bool awayFromCommonPath = false; + // true if this is a real or pseudo stacking context bool pseudoStackingContext = (aFlags & DISPLAY_CHILD_FORCE_PSEUDO_STACKING_CONTEXT) != 0; + awayFromCommonPath |= pseudoStackingContext; if (!isSVG && (aFlags & DISPLAY_CHILD_INLINE) && !child->IsFrameOfType(eLineParticipant)) { @@ -2361,6 +2457,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, // it acts like inline-block or inline-table. Therefore it is a // pseudo-stacking-context. pseudoStackingContext = true; + awayFromCommonPath = false; } // dirty rect in child-relative coordinates @@ -2408,6 +2505,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, dirty.SetEmpty(); } pseudoStackingContext = true; + awayFromCommonPath = true; } if (child->Preserves3D()) { nsRect* savedDirty = static_cast @@ -2430,31 +2528,9 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, if (aBuilder->GetIncludeAllOutOfFlows() && (child->GetStateBits() & NS_FRAME_OUT_OF_FLOW)) { dirty = child->GetVisualOverflowRect(); - } else if (!(child->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) { - // No need to descend into child to catch placeholders for visible - // positioned stuff. So see if we can short-circuit frame traversal here. - - // We can stop if child's frame subtree's intersection with the - // dirty area is empty. - // If the child is a scrollframe that we want to ignore, then we need - // to descend into it because its scrolled child may intersect the dirty - // area even if the scrollframe itself doesn't. - // There are cases where the "ignore scroll frame" on the builder is not set - // correctly, and so we additionally want to catch cases where the child is - // a root scrollframe and we are ignoring scrolling on the viewport. - nsIPresShell* shell = PresContext()->PresShell(); - bool keepDescending = child == aBuilder->GetIgnoreScrollFrame() || - (shell->IgnoringViewportScrolling() && child == shell->GetRootScrollFrame()); - if (!keepDescending) { - nsRect childDirty; - if (!childDirty.IntersectRect(dirty, child->GetVisualOverflowRect())) - return; - // Usually we could set dirty to childDirty now but there's no - // benefit, and it can be confusing. It can especially confuse - // situations where we're going to ignore a scrollframe's clipping; - // we wouldn't want to clip the dirty area to the scrollframe's - // bounds in that case. - } + awayFromCommonPath = true; + } else if (!DescendIntoChild(aBuilder, child, dirty)) { + return; } // XXX need to have inline-block and inline-table set pseudoStackingContext @@ -2466,6 +2542,16 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, !PresContext()->GetTheme()->WidgetIsContainer(ourDisp->mAppearance)) return; +#if(0) + // XXX: The backbug from bug 1342009 for tracking visibility at this + // point is only required if we implement bug 1261554 (then we also need + // bug 1284350). + if (aBuilder->IsPaintingToWindow() && child->TrackingVisibility()) { + child->PresContext()->PresShell()->EnsureFrameInApproximatelyVisibleList(child); + awayFromCommonPath = true; + } +#endif + // Child is composited if it's transformed, partially transparent, or has // SVG effects or a blend mode.. const nsStylePosition* pos = child->StylePosition(); @@ -2494,6 +2580,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, (aFlags & DISPLAY_CHILD_FORCE_STACKING_CONTEXT)) { // If you change this, also change IsPseudoStackingContextFromStyle() pseudoStackingContext = true; + awayFromCommonPath = true; } NS_ASSERTION(!isStackingContext || pseudoStackingContext, "Stacking contexts must also be pseudo-stacking-contexts"); @@ -2506,8 +2593,31 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, if (savedOutOfFlowData) { clipState.SetClipForContainingBlockDescendants( &savedOutOfFlowData->mContainingBlockClip); + MOZ_ASSERT(awayFromCommonPath, "It is impossible when savedOutOfFlowData is true"); } +#if(0) + // XXX: there are some backbugs from bug 1342009 that should go here. + // These appear to be based on bug 1231538 and bug 1265237, so we + // probably don't need them since we don't have that particular regression. + + else if (GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO && + isPlaceholder) { + NS_ASSERTION(dirty.IsEmpty(), "should have empty dirty rect"); + // Every item we build from now until we descent into an out of flow that + // does have saved out of flow data should be invisible. This state gets + // restored when AutoBuildingDisplayList gets out of scope. + aBuilder->SetBuildingInvisibleItems(true); + + // If we have nested out-of-flow frames and the outer one isn't visible + // then we won't have stored clip data for it. We can just clear the clip + // instead since we know we won't render anything, and the inner out-of-flow + // frame will setup the correct clip for itself. + clipState.SetClipChainForContainingBlockDescendants(nullptr); + awayFromCommonPath = true; + } +#endif + // Setup clipping for the parent's overflow:-moz-hidden-unscrollable, // or overflow:hidden on elements that don't support scrolling (and therefore // don't create nsHTML/XULScrollFrame). This clipping needs to not clip @@ -2519,7 +2629,9 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, nsIFrame* parent = child->GetParent(); const nsStyleDisplay* parentDisp = parent == this ? ourDisp : parent->StyleDisplay(); - ApplyOverflowClipping(aBuilder, parent, parentDisp, clipState); + if (ApplyOverflowClipping(aBuilder, parent, parentDisp, clipState)) { + awayFromCommonPath = true; + } nsDisplayList list; nsDisplayList extraPositionedDescendants; @@ -2538,26 +2650,43 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder, // clipRect is in builder-reference-frame coordinates, // dirty/clippedDirtyRect are in child coordinates dirty.IntersectRect(dirty, clipRect); + awayFromCommonPath = true; // XXX bug 1342009 } child->MarkAbsoluteFramesForDisplayList(aBuilder, dirty); - // moved here from below + // moved here from below (bug 1220466) if (aBuilder->IsBuildingLayerEventRegions()) { // If this frame has a different animated geometry root than its parent, // make sure we accumulate event regions for its layer. - if (buildingForChild.IsAnimatedGeometryRoot()) { + if (buildingForChild.IsAnimatedGeometryRoot() || isPositioned) { nsDisplayLayerEventRegions* eventRegions = new (aBuilder) nsDisplayLayerEventRegions(aBuilder, child); eventRegions->AddFrame(aBuilder, child); aBuilder->SetLayerEventRegions(eventRegions); - aLists.BorderBackground()->AppendNewToTop(eventRegions); - } - } - nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions(); - if (eventRegions) { - eventRegions->AddFrame(aBuilder, child); + // various backbugs from 1342009 follow, including 1303408 and + // 1287142: + + if (isPositioned) { + // We need this nsDisplayLayerEventRegions to be sorted with the positioned + // elements as positioned elements will be sorted on top of normal elements + list.AppendNewToTop(eventRegions); + } else { + aLists.BorderBackground()->AppendNewToTop(eventRegions); + } + } else { + nsDisplayLayerEventRegions* eventRegions = aBuilder->GetLayerEventRegions(); + if (eventRegions) { + eventRegions->AddFrame(aBuilder, child); + } + if (!awayFromCommonPath && + aBuilder->IsPaintingToWindow() && + !buildingForChild.MaybeAnimatedGeometryRoot()) { + // The shortcut is available for the child for next time. + child->AddStateBits(NS_FRAME_SIMPLE_DISPLAYLIST); + } + } } if (!pseudoStackingContext) { diff --git a/layout/generic/nsFrameStateBits.h b/layout/generic/nsFrameStateBits.h index 3e721d6ef..422ad0da2 100644 --- a/layout/generic/nsFrameStateBits.h +++ b/layout/generic/nsFrameStateBits.h @@ -254,6 +254,14 @@ FRAME_STATE_BIT(Generic, 53, NS_FRAME_IS_NONDISPLAY) // Frame has a LayerActivityProperty property FRAME_STATE_BIT(Generic, 54, NS_FRAME_HAS_LAYER_ACTIVITY_PROPERTY) +// The display list of the frame can be handled by the shortcut for +// COMMON CASE. This is bug 1342009, but it uses bit 57. Since we might +// implement NS_FRAME_HAS_PROPERTIES (56) in the near future, we will use bit +// 55. XXX: Dump bit 57 and make it all work out -- we'd need the backout +// bits from bug 1250244 and then just not implement the replacement API. +// However, that's only worth doing if we're really short on bits later. +FRAME_STATE_BIT(Generic, 55, NS_FRAME_SIMPLE_DISPLAYLIST) + // Frame has VR content, and needs VR display items created FRAME_STATE_BIT(Generic, 57, NS_FRAME_HAS_VR_CONTENT) diff --git a/xpcom/glue/PLDHashTable.cpp b/xpcom/glue/PLDHashTable.cpp index 7433da17b..688403c23 100644 --- a/xpcom/glue/PLDHashTable.cpp +++ b/xpcom/glue/PLDHashTable.cpp @@ -395,6 +395,49 @@ PLDHashTable::SearchTable(const void* aKey, PLDHashNumber aKeyHash) // if Reason==ForAdd.) PLDHashEntryHdr* firstRemoved = nullptr; +#if(1) + // Speed up table searches a la bug 1352888, but we go one further by having + // separate for(;;) loops for ForAdd and everything else, which hoists the + // check up and eliminates up to several branches in the loop. + + if (Reason == ForAdd) { + for (;;) { + if (!firstRemoved) { + if (MOZ_UNLIKELY(EntryIsRemoved(entry))) { + firstRemoved = entry; + } else { + entry->mKeyHash |= kCollisionFlag; + } + } + + hash1 -= hash2; + hash1 &= sizeMask; + + entry = AddressEntry(hash1); + if (EntryIsFree(entry)) { + return (firstRemoved ? firstRemoved : entry); + } + + if (MatchEntryKeyhash(entry, aKeyHash) && + matchEntry(this, entry, aKey)) { + return entry; + } + } + } else for (;;) { + hash1 -= hash2; + hash1 &= sizeMask; + + entry = AddressEntry(hash1); + if (EntryIsFree(entry)) { + return nullptr; + } + + if (MatchEntryKeyhash(entry, aKeyHash) && + matchEntry(this, entry, aKey)) { + return entry; + } + } +#else for (;;) { if (Reason == ForAdd) { if (MOZ_UNLIKELY(EntryIsRemoved(entry))) { @@ -420,6 +463,7 @@ PLDHashTable::SearchTable(const void* aKey, PLDHashNumber aKeyHash) return entry; } } +#endif // NOTREACHED return nullptr;