Bug 1354966 Part 1: [WIP] set a static flag for the duration of all Gecko_ calls, to be checked later within gtk calls for dangerous concurrent access. draft
authorBrad Werth <bwerth@mozilla.com>
Fri, 01 Sep 2017 10:27:36 -0700
changeset 657624 4b56a339a3603a1f4f23f77816addf99571fa6f5
parent 657500 34933f6390d52779ea498a6a5fd5f34d54734780
child 729477 d78c874899d249d5111d468b8c1f72cbabb95fc5
push id77577
push userbwerth@mozilla.com
push dateFri, 01 Sep 2017 18:13:54 +0000
bugs1354966
milestone57.0a1
Bug 1354966 Part 1: [WIP] set a static flag for the duration of all Gecko_ calls, to be checked later within gtk calls for dangerous concurrent access. MozReview-Commit-ID: AfkWj1nW1aQ
layout/style/ServoBindings.cpp
--- a/layout/style/ServoBindings.cpp
+++ b/layout/style/ServoBindings.cpp
@@ -88,16 +88,24 @@ using namespace mozilla::dom;
 #include "mozilla/ServoArcTypeList.h"
 SERVO_ARC_TYPE(StyleContext, ServoStyleContext)
 #undef SERVO_ARC_TYPE
 
 static Mutex* sServoFontMetricsLock = nullptr;
 static Mutex* sServoWidgetLock = nullptr;
 static RWLock* sServoLangFontPrefsLock = nullptr;
 
+// FIXME: this static is intended to be a marker used in all "Gecko_" calls.
+// The only purpose for this counter is for non-threadsafe libraries like GTK
+// to test the value at callsites. The static should become a threadsafe
+// counter, and setting to true should become incrementing and setting to false
+// should be decrementing. When that is done, non-threadsafe libraries should
+// instrument all callsites and assert that the value of the static is 1.
+static bool sInGeckoCall = false;
+
 static
 const nsFont*
 ThreadSafeGetDefaultFontHelper(const nsPresContext* aPresContext,
                                nsIAtom* aLanguage, uint8_t aGenericId)
 {
   bool needsCache = false;
   const nsFont* retval;
 
@@ -119,103 +127,121 @@ void
 AssertIsMainThreadOrServoLangFontPrefsCacheLocked()
 {
   MOZ_ASSERT(NS_IsMainThread() || sServoLangFontPrefsLock->LockedForWritingByCurrentThread());
 }
 
 bool
 Gecko_IsInDocument(RawGeckoNodeBorrowed aNode)
 {
+  sInGeckoCall = true;
   return aNode->IsInComposedDoc();
+  sInGeckoCall = false;
 }
 
 #ifdef MOZ_DEBUG_RUST
 bool
 Gecko_FlattenedTreeParentIsParent(RawGeckoNodeBorrowed aNode)
 {
+  sInGeckoCall = true;
   // Servo calls this in debug builds to verify the result of its own
   // flattened_tree_parent_is_parent() function.
   return FlattenedTreeParentIsParent<nsIContent::eForStyle>(aNode);
+  sInGeckoCall = false;
 }
 #endif
 
 /*
  * Does this child count as significant for selector matching?
  *
  * See nsStyleUtil::IsSignificantChild for details.
  */
 bool
 Gecko_IsSignificantChild(RawGeckoNodeBorrowed aNode, bool aTextIsSignificant,
                          bool aWhitespaceIsSignificant)
 {
+  sInGeckoCall = true;
   return nsStyleUtil::ThreadSafeIsSignificantChild(aNode->AsContent(),
                                                    aTextIsSignificant,
                                                    aWhitespaceIsSignificant);
+  sInGeckoCall = false;
 }
 
 RawGeckoNodeBorrowedOrNull
 Gecko_GetLastChild(RawGeckoNodeBorrowed aNode)
 {
+  sInGeckoCall = true;
   return aNode->GetLastChild();
+  sInGeckoCall = false;
 }
 
 RawGeckoNodeBorrowedOrNull
 Gecko_GetFlattenedTreeParentNode(RawGeckoNodeBorrowed aNode)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(!FlattenedTreeParentIsParent<nsIContent::eForStyle>(aNode),
              "Should have taken the inline path");
   MOZ_ASSERT(aNode->IsContent(), "Slow path only applies to content");
   const nsIContent* c = aNode->AsContent();
   return c->GetFlattenedTreeParentNodeInternal(nsIContent::eForStyle);
+  sInGeckoCall = false;
 }
 
 RawGeckoElementBorrowedOrNull
 Gecko_GetBeforeOrAfterPseudo(RawGeckoElementBorrowed aElement, bool aIsBefore)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aElement);
   MOZ_ASSERT(aElement->HasProperties());
 
   return aIsBefore
     ? nsLayoutUtils::GetBeforePseudo(aElement)
     : nsLayoutUtils::GetAfterPseudo(aElement);
+  sInGeckoCall = false;
 }
 
 nsTArray<nsIContent*>*
 Gecko_GetAnonymousContentForElement(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   nsIAnonymousContentCreator* ac = do_QueryFrame(aElement->GetPrimaryFrame());
   if (!ac) {
     return nullptr;
   }
 
   auto* array = new nsTArray<nsIContent*>();
   nsContentUtils::AppendNativeAnonymousChildren(aElement, *array, 0);
   return array;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_DestroyAnonymousContentList(nsTArray<nsIContent*>* aAnonContent)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aAnonContent);
   delete aAnonContent;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_ServoStyleContext_Init(
     ServoStyleContext* aContext,
     const ServoStyleContext* aParentContext,
     RawGeckoPresContextBorrowed aPresContext,
     const ServoComputedData* aValues,
     mozilla::CSSPseudoElementType aPseudoType,
     nsIAtom* aPseudoTag)
 {
+  sInGeckoCall = true;
   auto* presContext = const_cast<nsPresContext*>(aPresContext);
   new (KnownNotNull, aContext) ServoStyleContext(
       presContext, aPseudoTag, aPseudoType,
       ServoComputedDataForgotten(aValues));
+  sInGeckoCall = false;
 }
 
 ServoComputedData::ServoComputedData(
     const ServoComputedDataForgotten aValue)
 {
   PodAssign(this, aValue.mPtr);
 }
 
@@ -275,213 +301,257 @@ ServoComputedData::AddSizeOfExcludingThi
   // - writing_mode
   // - rules
   // - font_computation_data
 }
 
 void
 Gecko_ServoStyleContext_Destroy(ServoStyleContext* aContext)
 {
+  sInGeckoCall = true;
   aContext->~ServoStyleContext();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_ConstructStyleChildrenIterator(
   RawGeckoElementBorrowed aElement,
   RawGeckoStyleChildrenIteratorBorrowedMut aIterator)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aElement);
   MOZ_ASSERT(aIterator);
   new (aIterator) StyleChildrenIterator(aElement);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_DestroyStyleChildrenIterator(
   RawGeckoStyleChildrenIteratorBorrowedMut aIterator)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aIterator);
 
   aIterator->~StyleChildrenIterator();
+  sInGeckoCall = false;
 }
 
 RawGeckoNodeBorrowed
 Gecko_GetNextStyleChild(RawGeckoStyleChildrenIteratorBorrowedMut aIterator)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aIterator);
   return aIterator->GetNextChild();
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_IsPrivateBrowsingEnabled(const nsIDocument* aDoc)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aDoc);
   MOZ_ASSERT(NS_IsMainThread());
 
   nsILoadContext* loadContext = aDoc->GetLoadContext();
   return loadContext && loadContext->UsePrivateBrowsing();
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_AreVisitedLinksEnabled()
 {
+  sInGeckoCall = true;
   return nsCSSRuleProcessor::VisitedLinksEnabled();
+  sInGeckoCall = false;
 }
 
 EventStates::ServoType
 Gecko_ElementState(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   return aElement->StyleState().ServoValue();
+  sInGeckoCall = false;
 }
 
 EventStates::ServoType
 Gecko_DocumentState(const nsIDocument* aDocument)
 {
+  sInGeckoCall = true;
   return aDocument->ThreadSafeGetDocumentState().ServoValue();
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_IsRootElement(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   return aElement->OwnerDoc()->GetRootElement() == aElement;
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_MatchesElement(CSSPseudoClassType aType,
                      RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   return nsCSSPseudoClasses::MatchesElement(aType, aElement).value();
+  sInGeckoCall = false;
 }
 
 nsIAtom*
 Gecko_Namespace(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   int32_t id = aElement->NodeInfo()->NamespaceID();
   return nsContentUtils::NameSpaceManager()->NameSpaceURIAtomForServo(id);
+  sInGeckoCall = false;
 }
 
 // Dirtiness tracking.
 void
 Gecko_SetNodeFlags(RawGeckoNodeBorrowed aNode, uint32_t aFlags)
 {
+  sInGeckoCall = true;
   const_cast<nsINode*>(aNode)->SetFlags(aFlags);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_UnsetNodeFlags(RawGeckoNodeBorrowed aNode, uint32_t aFlags)
 {
+  sInGeckoCall = true;
   const_cast<nsINode*>(aNode)->UnsetFlags(aFlags);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_NoteDirtyElement(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   const_cast<Element*>(aElement)->NoteDirtyForServo();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_NoteDirtySubtreeForInvalidation(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   const_cast<Element*>(aElement)->NoteDirtySubtreeForServo();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_NoteAnimationOnlyDirtyElement(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   const_cast<Element*>(aElement)->NoteAnimationOnlyDirtyForServo();
+  sInGeckoCall = false;
 }
 
 CSSPseudoElementType
 Gecko_GetImplementedPseudo(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   return aElement->GetPseudoElementType();
+  sInGeckoCall = false;
 }
 
 uint32_t
 Gecko_CalcStyleDifference(ServoStyleContextBorrowed aOldStyle,
                           ServoStyleContextBorrowed aNewStyle,
                           uint64_t aOldStyleBits,
                           bool* aAnyStyleChanged)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aOldStyle);
   MOZ_ASSERT(aNewStyle);
 
   uint32_t relevantStructs = aOldStyleBits & NS_STYLE_INHERIT_MASK;
 
   uint32_t equalStructs;
   uint32_t samePointerStructs;  // unused
   nsChangeHint result = const_cast<ServoStyleContext*>(aOldStyle)->
     CalcStyleDifference(
       const_cast<ServoStyleContext*>(aNewStyle),
       &equalStructs,
       &samePointerStructs,
       relevantStructs);
   *aAnyStyleChanged = equalStructs != NS_STYLE_INHERIT_MASK;
   return result;
+  sInGeckoCall = false;
 }
 
 const ServoElementSnapshot*
 Gecko_GetElementSnapshot(const ServoElementSnapshotTable* aTable,
                          const Element* aElement)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aTable);
   MOZ_ASSERT(aElement);
 
   return aTable->Get(const_cast<Element*>(aElement));
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_HaveSeenPtr(SeenPtrs* aTable, const void* aPtr)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aTable);
   // Empty Rust allocations are indicated by small values up to the alignment
   // of the relevant type. We shouldn't see anything like that here.
   MOZ_ASSERT(uintptr_t(aPtr) > 16);
 
   return aTable->HaveSeenPtr(aPtr);
 }
 
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetStyleAttrDeclarationBlock(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   DeclarationBlock* decl = aElement->GetInlineStyleDeclaration();
   if (!decl) {
     return nullptr;
   }
   if (decl->IsGecko()) {
     // XXX This can happen when nodes are adopted from a Gecko-style-backend
     //     document into a Servo-style-backend document.  See bug 1330051.
     NS_WARNING("stylo: requesting a Gecko declaration block?");
     return nullptr;
   }
   return decl->AsServo()->RefRawStrong();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_UnsetDirtyStyleAttr(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   DeclarationBlock* decl = aElement->GetInlineStyleDeclaration();
   if (!decl) {
     return;
   }
   if (decl->IsGecko()) {
     // XXX This can happen when nodes are adopted from a Gecko-style-backend
     //     document into a Servo-style-backend document.  See bug 1330051.
     NS_WARNING("stylo: requesting a Gecko declaration block?");
     return;
   }
   decl->UnsetDirty();
+  sInGeckoCall = false;
 }
 
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetSMILOverrideDeclarationBlock(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   // This function duplicates a lot of the code in
   // Gecko_GetStyleAttrDeclarationBlock above because I haven't worked out a way
   // to persuade hazard analysis that a pointer-to-lambda is ok yet.
   MOZ_ASSERT(aElement, "Invalid GeckoElement");
 
   DeclarationBlock* decl =
     const_cast<dom::Element*>(aElement)->GetSMILOverrideStyleDeclaration();
   if (!decl) {
@@ -489,66 +559,73 @@ Gecko_GetSMILOverrideDeclarationBlock(Ra
   }
   if (decl->IsGecko()) {
     // XXX This can happen when nodes are adopted from a Gecko-style-backend
     //     document into a Servo-style-backend document.  See bug 1330051.
     NS_WARNING("stylo: requesting a Gecko declaration block?");
     return nullptr;
   }
   return decl->AsServo()->RefRawStrong();
+  sInGeckoCall = false;
 }
 
 const RawServoDeclarationBlockStrong*
 AsRefRawStrong(const RefPtr<RawServoDeclarationBlock>& aDecl)
 {
   static_assert(sizeof(RefPtr<RawServoDeclarationBlock>) ==
                 sizeof(RawServoDeclarationBlockStrong),
                 "RefPtr should just be a pointer");
   return reinterpret_cast<const RawServoDeclarationBlockStrong*>(&aDecl);
 }
 
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetHTMLPresentationAttrDeclarationBlock(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   const nsMappedAttributes* attrs = aElement->GetMappedAttributes();
   if (!attrs) {
     auto* svg = nsSVGElement::FromContentOrNull(aElement);
     if (svg) {
       if (auto decl = svg->GetContentDeclarationBlock()) {
         return decl->AsServo()->RefRawStrong();
       }
     }
     return nullptr;
   }
 
   return AsRefRawStrong(attrs->GetServoStyle());
+  sInGeckoCall = false;
 }
 
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetExtraContentStyleDeclarations(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   if (!aElement->IsAnyOfHTMLElements(nsGkAtoms::td, nsGkAtoms::th)) {
     return nullptr;
   }
   const HTMLTableCellElement* cell = static_cast<const HTMLTableCellElement*>(aElement);
   if (nsMappedAttributes* attrs = cell->GetMappedAttributesInheritedFromTable()) {
     return AsRefRawStrong(attrs->GetServoStyle());
   }
   return nullptr;
+  sInGeckoCall = false;
 }
 
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetUnvisitedLinkAttrDeclarationBlock(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
   if (!sheet) {
     return nullptr;
   }
 
   return AsRefRawStrong(sheet->GetServoUnvisitedLinkDecl());
+  sInGeckoCall = false;
 }
 
 ServoStyleSheet* Gecko_StyleSheet_Clone(
     const ServoStyleSheet* aSheet,
     const ServoStyleSheet* aNewParentSheet)
 {
   MOZ_ASSERT(aSheet);
   MOZ_ASSERT(aSheet->GetParentSheet(), "Should only be used for @import");
@@ -564,47 +641,55 @@ ServoStyleSheet* Gecko_StyleSheet_Clone(
   // So we _don't_ update neither the parent pointer of the stylesheet, nor the
   // child list (yet). This is fixed up in that same constructor.
   return static_cast<ServoStyleSheet*>(newSheet.forget().take());
 }
 
 void
 Gecko_StyleSheet_AddRef(const ServoStyleSheet* aSheet)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   const_cast<ServoStyleSheet*>(aSheet)->AddRef();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_StyleSheet_Release(const ServoStyleSheet* aSheet)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   const_cast<ServoStyleSheet*>(aSheet)->Release();
+  sInGeckoCall = false;
 }
 
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetVisitedLinkAttrDeclarationBlock(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
   if (!sheet) {
     return nullptr;
   }
 
   return AsRefRawStrong(sheet->GetServoVisitedLinkDecl());
+  sInGeckoCall = false;
 }
 
 RawServoDeclarationBlockStrongBorrowedOrNull
 Gecko_GetActiveLinkAttrDeclarationBlock(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   nsHTMLStyleSheet* sheet = aElement->OwnerDoc()->GetAttributeStyleSheet();
   if (!sheet) {
     return nullptr;
   }
 
   return AsRefRawStrong(sheet->GetServoActiveLinkDecl());
+  sInGeckoCall = false;
 }
 
 static CSSPseudoElementType
 GetPseudoTypeFromElementForAnimation(const Element*& aElementOrPseudo) {
   if (aElementOrPseudo->IsGeneratedContentContainerForBefore()) {
     aElementOrPseudo = aElementOrPseudo->GetParent()->AsElement();
     return CSSPseudoElementType::before;
   }
@@ -617,16 +702,17 @@ GetPseudoTypeFromElementForAnimation(con
   return CSSPseudoElementType::NotPseudo;
 }
 
 bool
 Gecko_GetAnimationRule(RawGeckoElementBorrowed aElement,
                        EffectCompositor::CascadeLevel aCascadeLevel,
                        RawServoAnimationValueMapBorrowedMut aAnimationValues)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aElement);
 
   nsIDocument* doc = aElement->GetComposedDoc();
   if (!doc || !doc->GetShell()) {
     return false;
   }
   nsPresContext* presContext = doc->GetShell()->GetPresContext();
   if (!presContext || !presContext->IsDynamic()) {
@@ -637,31 +723,35 @@ Gecko_GetAnimationRule(RawGeckoElementBo
   CSSPseudoElementType pseudoType =
     GetPseudoTypeFromElementForAnimation(aElement);
 
   return presContext->EffectCompositor()
     ->GetServoAnimationRule(aElement,
                             pseudoType,
                             aCascadeLevel,
                             aAnimationValues);
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_StyleAnimationsEquals(RawGeckoStyleAnimationListBorrowed aA,
                             RawGeckoStyleAnimationListBorrowed aB)
 {
+  sInGeckoCall = true;
   return *aA == *aB;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_UpdateAnimations(RawGeckoElementBorrowed aElement,
                        ServoStyleContextBorrowedOrNull aOldComputedData,
                        ServoStyleContextBorrowedOrNull aComputedData,
                        UpdateAnimationsTasks aTasks)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aElement);
 
   if (!aElement->IsInComposedDoc()) {
     return;
   }
 
   nsPresContext* presContext = nsContentUtils::GetContextForContent(aElement);
@@ -708,61 +798,70 @@ Gecko_UpdateAnimations(RawGeckoElementBo
     // rules. We post a restyle here so that we can update the cascade
     // results in the pre-traversal of the next restyle.
     presContext->EffectCompositor()
                ->RequestRestyle(const_cast<Element*>(aElement),
                                 pseudoType,
                                 EffectCompositor::RestyleType::Standard,
                                 EffectCompositor::CascadeLevel::Animations);
   }
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_ElementHasAnimations(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   CSSPseudoElementType pseudoType =
     GetPseudoTypeFromElementForAnimation(aElement);
 
   return !!EffectSet::GetEffectSet(aElement, pseudoType);
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_ElementHasCSSAnimations(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   CSSPseudoElementType pseudoType =
     GetPseudoTypeFromElementForAnimation(aElement);
   nsAnimationManager::CSSAnimationCollection* collection =
     nsAnimationManager::CSSAnimationCollection
                       ::GetAnimationCollection(aElement, pseudoType);
 
   return collection && !collection->mAnimations.IsEmpty();
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_ElementHasCSSTransitions(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   CSSPseudoElementType pseudoType =
     GetPseudoTypeFromElementForAnimation(aElement);
   nsTransitionManager::CSSTransitionCollection* collection =
     nsTransitionManager::CSSTransitionCollection
                        ::GetAnimationCollection(aElement, pseudoType);
 
   return collection && !collection->mAnimations.IsEmpty();
+  sInGeckoCall = false;
 }
 
 size_t
 Gecko_ElementTransitions_Length(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   CSSPseudoElementType pseudoType =
     GetPseudoTypeFromElementForAnimation(aElement);
   nsTransitionManager::CSSTransitionCollection* collection =
     nsTransitionManager::CSSTransitionCollection
                        ::GetAnimationCollection(aElement, pseudoType);
 
   return collection ? collection->mAnimations.Length() : 0;
+  sInGeckoCall = false;
 }
 
 static CSSTransition*
 GetCurrentTransitionAt(RawGeckoElementBorrowed aElement, size_t aIndex)
 {
   CSSPseudoElementType pseudoType =
     GetPseudoTypeFromElementForAnimation(aElement);
   nsTransitionManager::CSSTransitionCollection* collection =
@@ -776,155 +875,183 @@ GetCurrentTransitionAt(RawGeckoElementBo
          ? transitions[aIndex].get()
          : nullptr;
 }
 
 nsCSSPropertyID
 Gecko_ElementTransitions_PropertyAt(RawGeckoElementBorrowed aElement,
                                     size_t aIndex)
 {
+  sInGeckoCall = true;
   CSSTransition* transition = GetCurrentTransitionAt(aElement, aIndex);
   return transition ? transition->TransitionProperty()
                     : nsCSSPropertyID::eCSSProperty_UNKNOWN;
+  sInGeckoCall = false;
 }
 
 RawServoAnimationValueBorrowedOrNull
 Gecko_ElementTransitions_EndValueAt(RawGeckoElementBorrowed aElement,
                                     size_t aIndex)
 {
+  sInGeckoCall = true;
   CSSTransition* transition = GetCurrentTransitionAt(aElement,
                                                      aIndex);
   return transition ? transition->ToValue().mServo.get() : nullptr;
+  sInGeckoCall = false;
 }
 
 double
 Gecko_GetProgressFromComputedTiming(RawGeckoComputedTimingBorrowed aComputedTiming)
 {
+  sInGeckoCall = true;
   return aComputedTiming->mProgress.Value();
+  sInGeckoCall = false;
 }
 
 double
 Gecko_GetPositionInSegment(RawGeckoAnimationPropertySegmentBorrowed aSegment,
                           double aProgress,
                           ComputedTimingFunction::BeforeFlag aBeforeFlag)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aSegment->mFromKey < aSegment->mToKey,
              "The segment from key should be less than to key");
 
   double positionInSegment =
     (aProgress - aSegment->mFromKey) / (aSegment->mToKey - aSegment->mFromKey);
 
   return ComputedTimingFunction::GetPortion(aSegment->mTimingFunction,
                                             positionInSegment,
                                             aBeforeFlag);
+  sInGeckoCall = false;
 }
 
 RawServoAnimationValueBorrowedOrNull
 Gecko_AnimationGetBaseStyle(void* aBaseStyles, nsCSSPropertyID aProperty)
 {
+  sInGeckoCall = true;
   auto base =
     static_cast<nsRefPtrHashtable<nsUint32HashKey, RawServoAnimationValue>*>
       (aBaseStyles);
   return base->GetWeak(aProperty);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_StyleTransition_SetUnsupportedProperty(StyleTransition* aTransition,
                                              nsIAtom* aAtom)
 {
+  sInGeckoCall = true;
   nsCSSPropertyID id =
     nsCSSProps::LookupProperty(nsDependentAtomString(aAtom),
                                CSSEnabledState::eForAllContent);
   if (id == eCSSProperty_UNKNOWN || id == eCSSPropertyExtra_variable) {
     aTransition->SetUnknownProperty(id, aAtom);
   } else {
     aTransition->SetProperty(id);
   }
+  sInGeckoCall = false;
 }
 
 void
 Gecko_FillAllBackgroundLists(nsStyleImageLayers* aLayers, uint32_t aMaxLen)
 {
+  sInGeckoCall = true;
   nsRuleNode::FillAllBackgroundLists(*aLayers, aMaxLen);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_FillAllMaskLists(nsStyleImageLayers* aLayers, uint32_t aMaxLen)
 {
+  sInGeckoCall = true;
   nsRuleNode::FillAllMaskLists(*aLayers, aMaxLen);
+  sInGeckoCall = false;
 }
 
 RawGeckoElementBorrowedOrNull
 Gecko_GetBody(RawGeckoPresContextBorrowed aPresContext)
 {
+  sInGeckoCall = true;
   return aPresContext->Document()->GetBodyElement();
+  sInGeckoCall = false;
 }
 
 nscolor
 Gecko_GetLookAndFeelSystemColor(int32_t aId,
                                 RawGeckoPresContextBorrowed aPresContext)
 {
+  sInGeckoCall = true;
   bool useStandinsForNativeColors = aPresContext && !aPresContext->IsChrome();
   nscolor result;
   LookAndFeel::ColorID colorId = static_cast<LookAndFeel::ColorID>(aId);
   MutexAutoLock guard(*sServoWidgetLock);
   LookAndFeel::GetColor(colorId, useStandinsForNativeColors, &result);
   return result;
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_MatchStringArgPseudo(RawGeckoElementBorrowed aElement,
                            CSSPseudoClassType aType,
                            const char16_t* aIdent,
                            bool* aSetSlowSelectorFlag)
 {
+  sInGeckoCall = true;
   EventStates dummyMask; // mask is never read because we pass aDependence=nullptr
   return nsCSSRuleProcessor::StringPseudoMatches(aElement, aType, aIdent,
                                                  aElement->OwnerDoc(), true,
                                                  dummyMask, aSetSlowSelectorFlag, nullptr);
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_MatchLang(RawGeckoElementBorrowed aElement,
                 nsIAtom* aOverrideLang,
                 bool aHasOverrideLang,
                 const char16_t* aValue)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(!(aOverrideLang && !aHasOverrideLang),
              "aHasOverrideLang should only be set when aOverrideLang is null");
 
   if (!aHasOverrideLang) {
     return nsCSSRuleProcessor::LangPseudoMatches(aElement, nullptr, false,
                                                  aValue, aElement->OwnerDoc());
   }
 
   return nsCSSRuleProcessor::LangPseudoMatches(aElement, aOverrideLang, true,
                                                aValue, aElement->OwnerDoc());
+  sInGeckoCall = false;
 }
 
 nsIAtom*
 Gecko_GetXMLLangValue(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   const nsAttrValue* attr =
     aElement->GetParsedAttr(nsGkAtoms::lang, kNameSpaceID_XML);
 
   if (!attr) {
     return nullptr;
   }
 
   MOZ_ASSERT(attr->Type() == nsAttrValue::eAtom);
 
   nsCOMPtr<nsIAtom> atom = attr->GetAtomValue();
   return atom.forget().take();
+  sInGeckoCall = false;
 }
 
 nsIDocument::DocumentTheme
 Gecko_GetDocumentLWTheme(const nsIDocument* aDocument)
 {
+  sInGeckoCall = true;
   return aDocument->ThreadSafeGetDocumentLWTheme();
+  sInGeckoCall = false;
 }
 
 template <typename Implementor>
 static nsIAtom*
 AtomAttrValue(Implementor* aElement, nsIAtom* aName)
 {
   const nsAttrValue* attr = aElement->GetParsedAttr(aName);
   return attr ? attr->GetAtomValue() : nullptr;
@@ -1199,285 +1326,349 @@ ClassOrClassList(Implementor* aElement, 
 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_, RawGeckoElementBorrowed)
 SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS(Gecko_Snapshot, const ServoElementSnapshot*)
 
 #undef SERVO_IMPL_ELEMENT_ATTR_MATCHING_FUNCTIONS
 
 nsIAtom*
 Gecko_Atomize(const char* aString, uint32_t aLength)
 {
+  sInGeckoCall = true;
   return NS_Atomize(nsDependentCSubstring(aString, aLength)).take();
+  sInGeckoCall = false;
 }
 
 nsIAtom*
 Gecko_Atomize16(const nsAString* aString)
 {
+  sInGeckoCall = true;
   return NS_Atomize(*aString).take();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_AddRefAtom(nsIAtom* aAtom)
 {
+  sInGeckoCall = true;
   NS_ADDREF(aAtom);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_ReleaseAtom(nsIAtom* aAtom)
 {
+  sInGeckoCall = true;
   NS_RELEASE(aAtom);
+  sInGeckoCall = false;
 }
 
 const uint16_t*
 Gecko_GetAtomAsUTF16(nsIAtom* aAtom, uint32_t* aLength)
 {
+  sInGeckoCall = true;
   static_assert(sizeof(char16_t) == sizeof(uint16_t), "Servo doesn't know what a char16_t is");
   MOZ_ASSERT(aAtom);
   *aLength = aAtom->GetLength();
 
   // We need to manually cast from char16ptr_t to const char16_t* to handle the
   // MOZ_USE_CHAR16_WRAPPER we use on WIndows.
   return reinterpret_cast<const uint16_t*>(static_cast<const char16_t*>(aAtom->GetUTF16String()));
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_AtomEqualsUTF8(nsIAtom* aAtom, const char* aString, uint32_t aLength)
 {
+  sInGeckoCall = true;
   // XXXbholley: We should be able to do this without converting, I just can't
   // find the right thing to call.
   nsDependentAtomString atomStr(aAtom);
   NS_ConvertUTF8toUTF16 inStr(nsDependentCSubstring(aString, aLength));
   return atomStr.Equals(inStr);
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_AtomEqualsUTF8IgnoreCase(nsIAtom* aAtom, const char* aString, uint32_t aLength)
 {
+  sInGeckoCall = true;
   // XXXbholley: We should be able to do this without converting, I just can't
   // find the right thing to call.
   nsDependentAtomString atomStr(aAtom);
   NS_ConvertUTF8toUTF16 inStr(nsDependentCSubstring(aString, aLength));
   return nsContentUtils::EqualsIgnoreASCIICase(atomStr, inStr);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_EnsureMozBorderColors(nsStyleBorder* aBorder)
 {
+  sInGeckoCall = true;
   aBorder->EnsureBorderColors();
+  sInGeckoCall = false;
 }
 
 void Gecko_ClearMozBorderColors(nsStyleBorder* aBorder, mozilla::Side aSide)
 {
   aBorder->ClearBorderColors(aSide);
 }
 
 void
 Gecko_AppendMozBorderColors(nsStyleBorder* aBorder, mozilla::Side aSide,
                             nscolor aColor)
 {
+  sInGeckoCall = true;
   aBorder->AppendBorderColor(aSide, aColor);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyMozBorderColors(nsStyleBorder* aDest, const nsStyleBorder* aSrc,
                           mozilla::Side aSide)
 {
+  sInGeckoCall = true;
   if (aSrc->mBorderColors) {
     aDest->CopyBorderColorsFrom(aSrc->mBorderColors[aSide], aSide);
   }
+  sInGeckoCall = false;
 }
 
 const nsBorderColors*
 Gecko_GetMozBorderColors(const nsStyleBorder* aBorder, mozilla::Side aSide)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aBorder);
   return aBorder->mBorderColors ? aBorder->mBorderColors[aSide] : nullptr;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_FontFamilyList_Clear(FontFamilyList* aList) {
+  sInGeckoCall = true;
   aList->Clear();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_FontFamilyList_AppendNamed(FontFamilyList* aList, nsIAtom* aName, bool aQuoted)
 {
+  sInGeckoCall = true;
   FontFamilyName family;
   aName->ToString(family.mName);
   if (aQuoted) {
     family.mType = eFamily_named_quoted;
   }
 
   aList->Append(family);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_FontFamilyList_AppendGeneric(FontFamilyList* aList, FontFamilyType aType)
 {
+  sInGeckoCall = true;
   aList->Append(FontFamilyName(aType));
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyFontFamilyFrom(nsFont* dst, const nsFont* src)
 {
+  sInGeckoCall = true;
   dst->fontlist = src->fontlist;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsFont_InitSystem(nsFont* aDest, int32_t aFontId,
                         const nsStyleFont* aFont, RawGeckoPresContextBorrowed aPresContext)
 {
+  sInGeckoCall = true;
   const nsFont* defaultVariableFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage,
                                                                      kPresContext_DefaultVariableFont_ID);
 
   // We have passed uninitialized memory to this function,
   // initialize it. We can't simply return an nsFont because then
   // we need to know its size beforehand. Servo cannot initialize nsFont
   // itself, so this will do.
   nsFont* system = new (aDest) nsFont(*defaultVariableFont);
 
   MOZ_RELEASE_ASSERT(system);
 
   *aDest = *defaultVariableFont;
   LookAndFeel::FontID fontID = static_cast<LookAndFeel::FontID>(aFontId);
 
   MutexAutoLock lock(*sServoFontMetricsLock);
   nsRuleNode::ComputeSystemFont(aDest, fontID, aPresContext, defaultVariableFont);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsFont_Destroy(nsFont* aDest)
 {
+  sInGeckoCall = true;
   aDest->~nsFont();
+  sInGeckoCall = false;
 }
 
 nsTArray<unsigned int>*
 Gecko_AppendFeatureValueHashEntry(gfxFontFeatureValueSet* aFontFeatureValues,
                                   nsIAtom* aFamily, uint32_t aAlternate, nsIAtom* aName)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   static_assert(sizeof(unsigned int) == sizeof(uint32_t),
                 "sizeof unsigned int and uint32_t must be the same");
   return aFontFeatureValues->AppendFeatureValueHashEntry(
     nsDependentAtomString(aFamily),
     nsDependentAtomString(aName),
     aAlternate
   );
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsFont_SetFontFeatureValuesLookup(nsFont* aFont,
                                         const RawGeckoPresContext* aPresContext)
 {
+  sInGeckoCall = true;
   aFont->featureValueLookup = aPresContext->GetFontFeatureValuesLookup();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsFont_ResetFontFeatureValuesLookup(nsFont* aFont)
 {
+  sInGeckoCall = true;
   aFont->featureValueLookup = nullptr;
+  sInGeckoCall = false;
 }
 
 
 void
 Gecko_ClearAlternateValues(nsFont* aFont, size_t aLength)
 {
+  sInGeckoCall = true;
   aFont->alternateValues.Clear();
   aFont->alternateValues.SetCapacity(aLength);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_AppendAlternateValues(nsFont* aFont, uint32_t aAlternateName, nsIAtom* aAtom)
 {
+  sInGeckoCall = true;
   aFont->alternateValues.AppendElement(gfxAlternateValue {
     aAlternateName,
     nsDependentAtomString(aAtom)
   });
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyAlternateValuesFrom(nsFont* aDest, const nsFont* aSrc)
 {
+  sInGeckoCall = true;
   aDest->alternateValues.Clear();
   aDest->alternateValues.AppendElements(aSrc->alternateValues);
   aDest->featureValueLookup = aSrc->featureValueLookup;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetImageOrientation(nsStyleVisibility* aVisibility,
                           uint8_t aOrientation, bool aFlip)
 {
+  sInGeckoCall = true;
   aVisibility->mImageOrientation =
     nsStyleImageOrientation::CreateAsOrientationAndFlip(aOrientation, aFlip);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetImageOrientationAsFromImage(nsStyleVisibility* aVisibility)
 {
+  sInGeckoCall = true;
   aVisibility->mImageOrientation = nsStyleImageOrientation::CreateAsFromImage();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyImageOrientationFrom(nsStyleVisibility* aDst,
                                const nsStyleVisibility* aSrc)
 {
+  sInGeckoCall = true;
   aDst->mImageOrientation = aSrc->mImageOrientation;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetCounterStyleToName(CounterStylePtr* aPtr, nsIAtom* aName,
                             RawGeckoPresContextBorrowed aPresContext)
 {
+  sInGeckoCall = true;
   // Try resolving the counter style if possible, and keep it unresolved
   // otherwise.
   CounterStyleManager* manager = aPresContext->CounterStyleManager();
   nsCOMPtr<nsIAtom> name = already_AddRefed<nsIAtom>(aName);
   if (CounterStyle* style = manager->GetCounterStyle(name)) {
     *aPtr = style;
   } else {
     *aPtr = name.forget();
   }
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetCounterStyleToSymbols(CounterStylePtr* aPtr, uint8_t aSymbolsType,
                                nsACString const* const* aSymbols,
                                uint32_t aSymbolsCount)
 {
+  sInGeckoCall = true;
   nsTArray<nsString> symbols(aSymbolsCount);
   for (uint32_t i = 0; i < aSymbolsCount; i++) {
     symbols.AppendElement(NS_ConvertUTF8toUTF16(*aSymbols[i]));
   }
   *aPtr = new AnonymousCounterStyle(aSymbolsType, Move(symbols));
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetCounterStyleToString(CounterStylePtr* aPtr, const nsACString* aSymbol)
 {
+  sInGeckoCall = true;
   *aPtr = new AnonymousCounterStyle(NS_ConvertUTF8toUTF16(*aSymbol));
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyCounterStyle(CounterStylePtr* aDst, const CounterStylePtr* aSrc)
 {
+  sInGeckoCall = true;
   *aDst = *aSrc;
+  sInGeckoCall = false;
 }
 
 nsIAtom*
 Gecko_CounterStyle_GetName(const CounterStylePtr* aPtr)
 {
+  sInGeckoCall = true;
   if (!aPtr->IsResolved()) {
     return aPtr->AsAtom();
   }
   return (*aPtr)->GetStyleName();
+  sInGeckoCall = false;
 }
 
 const AnonymousCounterStyle*
 Gecko_CounterStyle_GetAnonymous(const CounterStylePtr* aPtr)
 {
+  sInGeckoCall = true;
   return aPtr->AsAnonymous();
+  sInGeckoCall = false;
 }
 
 already_AddRefed<css::URLValue>
 ServoBundledURI::IntoCssUrl()
 {
   if (!mURLString) {
     return nullptr;
   }
@@ -1491,135 +1682,160 @@ ServoBundledURI::IntoCssUrl()
   RefPtr<css::URLValue> urlValue =
     new css::URLValue(url, do_AddRef(mExtraData));
   return urlValue.forget();
 }
 
 void
 Gecko_SetNullImageValue(nsStyleImage* aImage)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aImage);
   aImage->SetNull();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetGradientImageValue(nsStyleImage* aImage, nsStyleGradient* aGradient)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aImage);
   aImage->SetGradientData(aGradient);
+  sInGeckoCall = false;
 }
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::ImageValue, ImageValue);
 
 static already_AddRefed<nsStyleImageRequest>
 CreateStyleImageRequest(nsStyleImageRequest::Mode aModeFlags,
                         mozilla::css::ImageValue* aImageValue)
 {
   RefPtr<nsStyleImageRequest> req =
     new nsStyleImageRequest(aModeFlags, aImageValue);
   return req.forget();
 }
 
 mozilla::css::ImageValue*
 Gecko_ImageValue_Create(ServoBundledURI aURI)
 {
+  sInGeckoCall = true;
   NS_ConvertUTF8toUTF16 url(reinterpret_cast<const char*>(aURI.mURLString),
                             aURI.mURLStringLength);
 
   RefPtr<css::ImageValue> value(
     new css::ImageValue(url, do_AddRef(aURI.mExtraData)));
   return value.forget().take();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetLayerImageImageValue(nsStyleImage* aImage,
                               mozilla::css::ImageValue* aImageValue)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aImage && aImageValue);
 
   RefPtr<nsStyleImageRequest> req =
     CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aImageValue);
   aImage->SetImageRequest(req.forget());
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetImageElement(nsStyleImage* aImage, nsIAtom* aAtom) {
+  sInGeckoCall = true;
   MOZ_ASSERT(aImage);
   aImage->SetElementId(do_AddRef(aAtom));
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyImageValueFrom(nsStyleImage* aImage, const nsStyleImage* aOther)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aImage);
   MOZ_ASSERT(aOther);
 
   *aImage = *aOther;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_InitializeImageCropRect(nsStyleImage* aImage)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aImage);
   aImage->SetCropRect(MakeUnique<nsStyleSides>());
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetCursorArrayLength(nsStyleUserInterface* aStyleUI, size_t aLen)
 {
+  sInGeckoCall = true;
   aStyleUI->mCursorImages.Clear();
   aStyleUI->mCursorImages.SetLength(aLen);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetCursorImageValue(nsCursorImage* aCursor,
                           mozilla::css::ImageValue* aImageValue)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aCursor && aImageValue);
 
   aCursor->mImage =
     CreateStyleImageRequest(nsStyleImageRequest::Mode::Discard, aImageValue);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyCursorArrayFrom(nsStyleUserInterface* aDest,
                           const nsStyleUserInterface* aSrc)
 {
+  sInGeckoCall = true;
   aDest->mCursorImages = aSrc->mCursorImages;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetContentDataImageValue(nsStyleContentData* aContent,
                                mozilla::css::ImageValue* aImageValue)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aContent && aImageValue);
 
   RefPtr<nsStyleImageRequest> req =
     CreateStyleImageRequest(nsStyleImageRequest::Mode::Track, aImageValue);
   aContent->SetImageRequest(req.forget());
+  sInGeckoCall = false;
 }
 
 nsStyleContentData::CounterFunction*
 Gecko_SetCounterFunction(nsStyleContentData* aContent, nsStyleContentType aType)
 {
+  sInGeckoCall = true;
   RefPtr<nsStyleContentData::CounterFunction>
     counterFunc = new nsStyleContentData::CounterFunction();
   nsStyleContentData::CounterFunction* ptr = counterFunc;
   aContent->SetCounters(aType, counterFunc.forget());
   return ptr;
+  sInGeckoCall = false;
 }
 
 nsStyleGradient*
 Gecko_CreateGradient(uint8_t aShape,
                      uint8_t aSize,
                      bool aRepeating,
                      bool aLegacySyntax,
                      bool aMozLegacySyntax,
                      uint32_t aStopCount)
 {
+  sInGeckoCall = true;
   nsStyleGradient* result = new nsStyleGradient();
 
   result->mShape = aShape;
   result->mSize = aSize;
   result->mRepeating = aRepeating;
   result->mLegacySyntax = aLegacySyntax;
   result->mMozLegacySyntax = aMozLegacySyntax;
 
@@ -1634,244 +1850,293 @@ Gecko_CreateGradient(uint8_t aShape,
   dummyStop.mColor = NS_RGB(0, 0, 0);
   dummyStop.mIsInterpolationHint = 0;
 
   for (uint32_t i = 0; i < aStopCount; i++) {
     result->mStops.AppendElement(dummyStop);
   }
 
   return result;
+  sInGeckoCall = false;
 }
 
 const mozilla::css::URLValueData*
 Gecko_GetURLValue(const nsStyleImage* aImage)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aImage && aImage->GetType() == eStyleImageType_Image);
   return aImage->GetURLValue();
+  sInGeckoCall = false;
 }
 
 nsIAtom*
 Gecko_GetImageElement(const nsStyleImage* aImage)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aImage && aImage->GetType() == eStyleImageType_Element);
   return const_cast<nsIAtom*>(aImage->GetElementId());
+  sInGeckoCall = false;
 }
 
 const nsStyleGradient*
 Gecko_GetGradientImageValue(const nsStyleImage* aImage)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aImage && aImage->GetType() == eStyleImageType_Gradient);
   return aImage->GetGradientData();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetListStyleImageNone(nsStyleList* aList)
 {
+  sInGeckoCall = true;
   aList->mListStyleImage = nullptr;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetListStyleImageImageValue(nsStyleList* aList,
                              mozilla::css::ImageValue* aImageValue)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aList && aImageValue);
 
   aList->mListStyleImage =
     CreateStyleImageRequest(nsStyleImageRequest::Mode(0), aImageValue);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyListStyleImageFrom(nsStyleList* aList, const nsStyleList* aSource)
 {
+  sInGeckoCall = true;
   aList->mListStyleImage = aSource->mListStyleImage;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_EnsureTArrayCapacity(void* aArray, size_t aCapacity, size_t aElemSize)
 {
+  sInGeckoCall = true;
   auto base =
     reinterpret_cast<nsTArray_base<nsTArrayInfallibleAllocator,
                                    nsTArray_CopyWithMemutils>*>(aArray);
 
   base->EnsureCapacity<nsTArrayInfallibleAllocator>(aCapacity, aElemSize);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_ClearPODTArray(void* aArray, size_t aElementSize, size_t aElementAlign)
 {
+  sInGeckoCall = true;
   auto base =
     reinterpret_cast<nsTArray_base<nsTArrayInfallibleAllocator,
                                    nsTArray_CopyWithMemutils>*>(aArray);
 
   base->template ShiftData<nsTArrayInfallibleAllocator>(0, base->Length(), 0,
                                                         aElementSize, aElementAlign);
+  sInGeckoCall = false;
 }
 
 void Gecko_ResizeTArrayForStrings(nsTArray<nsString>* aArray, uint32_t aLength)
 {
   aArray->SetLength(aLength);
 }
 
 void
 Gecko_SetStyleGridTemplate(UniquePtr<nsStyleGridTemplate>* aGridTemplate,
                            nsStyleGridTemplate* aValue)
 {
+  sInGeckoCall = true;
   aGridTemplate->reset(aValue);
+  sInGeckoCall = false;
 }
 
 nsStyleGridTemplate*
 Gecko_CreateStyleGridTemplate(uint32_t aTrackSizes, uint32_t aNameSize)
 {
+  sInGeckoCall = true;
   nsStyleGridTemplate* result = new nsStyleGridTemplate;
   result->mMinTrackSizingFunctions.SetLength(aTrackSizes);
   result->mMaxTrackSizingFunctions.SetLength(aTrackSizes);
   result->mLineNameLists.SetLength(aNameSize);
   return result;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyStyleGridTemplateValues(UniquePtr<nsStyleGridTemplate>* aGridTemplate,
                                   const nsStyleGridTemplate* aOther)
 {
+  sInGeckoCall = true;
   if (aOther) {
     *aGridTemplate = MakeUnique<nsStyleGridTemplate>(*aOther);
   } else {
     *aGridTemplate = nullptr;
   }
+  sInGeckoCall = false;
 }
 
 mozilla::css::GridTemplateAreasValue*
 Gecko_NewGridTemplateAreasValue(uint32_t aAreas, uint32_t aTemplates, uint32_t aColumns)
 {
+  sInGeckoCall = true;
   RefPtr<mozilla::css::GridTemplateAreasValue> value = new mozilla::css::GridTemplateAreasValue;
   value->mNamedAreas.SetLength(aAreas);
   value->mTemplates.SetLength(aTemplates);
   value->mNColumns = aColumns;
   return value.forget().take();
+  sInGeckoCall = false;
 }
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(mozilla::css::GridTemplateAreasValue, GridTemplateAreasValue);
 
 void
 Gecko_ClearAndResizeStyleContents(nsStyleContent* aContent, uint32_t aHowMany)
 {
+  sInGeckoCall = true;
   aContent->AllocateContents(aHowMany);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyStyleContentsFrom(nsStyleContent* aContent, const nsStyleContent* aOther)
 {
+  sInGeckoCall = true;
   uint32_t count = aOther->ContentCount();
 
   aContent->AllocateContents(count);
 
   for (uint32_t i = 0; i < count; ++i) {
     aContent->ContentAt(i) = aOther->ContentAt(i);
   }
+  sInGeckoCall = false;
 }
 
 void
 Gecko_ClearAndResizeCounterIncrements(nsStyleContent* aContent, uint32_t aHowMany)
 {
+  sInGeckoCall = true;
   aContent->AllocateCounterIncrements(aHowMany);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyCounterIncrementsFrom(nsStyleContent* aContent, const nsStyleContent* aOther)
 {
+  sInGeckoCall = true;
   uint32_t count = aOther->CounterIncrementCount();
 
   aContent->AllocateCounterIncrements(count);
 
   for (uint32_t i = 0; i < count; ++i) {
     const nsStyleCounterData& data = aOther->CounterIncrementAt(i);
     aContent->SetCounterIncrementAt(i, data.mCounter, data.mValue);
   }
+  sInGeckoCall = false;
 }
 
 void
 Gecko_ClearAndResizeCounterResets(nsStyleContent* aContent, uint32_t aHowMany)
 {
+  sInGeckoCall = true;
   aContent->AllocateCounterResets(aHowMany);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyCounterResetsFrom(nsStyleContent* aContent, const nsStyleContent* aOther)
 {
+  sInGeckoCall = true;
   uint32_t count = aOther->CounterResetCount();
 
   aContent->AllocateCounterResets(count);
 
   for (uint32_t i = 0; i < count; ++i) {
     const nsStyleCounterData& data = aOther->CounterResetAt(i);
     aContent->SetCounterResetAt(i, data.mCounter, data.mValue);
   }
+  sInGeckoCall = false;
 }
 
 void
 Gecko_EnsureImageLayersLength(nsStyleImageLayers* aLayers, size_t aLen,
                               nsStyleImageLayers::LayerType aLayerType)
 {
+  sInGeckoCall = true;
   size_t oldLength = aLayers->mLayers.Length();
 
   aLayers->mLayers.EnsureLengthAtLeast(aLen);
 
   for (size_t i = oldLength; i < aLen; ++i) {
     aLayers->mLayers[i].Initialize(aLayerType);
   }
+  sInGeckoCall = false;
 }
 
 void
 Gecko_EnsureStyleAnimationArrayLength(void* aArray, size_t aLen)
 {
+  sInGeckoCall = true;
   auto base =
     static_cast<nsStyleAutoArray<StyleAnimation>*>(aArray);
 
   size_t oldLength = base->Length();
 
   base->EnsureLengthAtLeast(aLen);
 
   for (size_t i = oldLength; i < aLen; ++i) {
     (*base)[i].SetInitialValues();
   }
+  sInGeckoCall = false;
 }
 
 void
 Gecko_EnsureStyleTransitionArrayLength(void* aArray, size_t aLen)
 {
+  sInGeckoCall = true;
   auto base =
     reinterpret_cast<nsStyleAutoArray<StyleTransition>*>(aArray);
 
   size_t oldLength = base->Length();
 
   base->EnsureLengthAtLeast(aLen);
 
   for (size_t i = oldLength; i < aLen; ++i) {
     (*base)[i].SetInitialValues();
   }
+  sInGeckoCall = false;
 }
 
 void
 Gecko_ClearWillChange(nsStyleDisplay* aDisplay, size_t aLength)
 {
+  sInGeckoCall = true;
   aDisplay->mWillChange.Clear();
   aDisplay->mWillChange.SetCapacity(aLength);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_AppendWillChange(nsStyleDisplay* aDisplay, nsIAtom* aAtom)
 {
+  sInGeckoCall = true;
   aDisplay->mWillChange.AppendElement(aAtom);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyWillChangeFrom(nsStyleDisplay* aDest, nsStyleDisplay* aSrc)
 {
+  sInGeckoCall = true;
   aDest->mWillChange.Clear();
   aDest->mWillChange.AppendElements(aSrc->mWillChange);
+  sInGeckoCall = false;
 }
 
 enum class KeyframeSearchDirection {
   Forwards,
   Backwards,
 };
 
 enum class KeyframeInsertPosition {
@@ -1926,483 +2191,589 @@ GetOrCreateKeyframe(nsTArray<Keyframe>* 
   return keyframe;
 }
 
 Keyframe*
 Gecko_GetOrCreateKeyframeAtStart(nsTArray<Keyframe>* aKeyframes,
                                  float aOffset,
                                  const nsTimingFunction* aTimingFunction)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aKeyframes->IsEmpty() ||
              aKeyframes->ElementAt(0).mOffset.value() >= aOffset,
              "The offset should be less than or equal to the first keyframe's "
              "offset if there are exisiting keyframes");
 
   return GetOrCreateKeyframe(aKeyframes,
                              aOffset,
                              aTimingFunction,
                              KeyframeSearchDirection::Forwards,
                              KeyframeInsertPosition::Prepend);
+  sInGeckoCall = false;
 }
 
 Keyframe*
 Gecko_GetOrCreateInitialKeyframe(nsTArray<Keyframe>* aKeyframes,
                                  const nsTimingFunction* aTimingFunction)
 {
+  sInGeckoCall = true;
   return GetOrCreateKeyframe(aKeyframes,
                              0.,
                              aTimingFunction,
                              KeyframeSearchDirection::Forwards,
                              KeyframeInsertPosition::LastForOffset);
+  sInGeckoCall = false;
 }
 
 Keyframe*
 Gecko_GetOrCreateFinalKeyframe(nsTArray<Keyframe>* aKeyframes,
                                const nsTimingFunction* aTimingFunction)
 {
+  sInGeckoCall = true;
   return GetOrCreateKeyframe(aKeyframes,
                              1.,
                              aTimingFunction,
                              KeyframeSearchDirection::Backwards,
                              KeyframeInsertPosition::LastForOffset);
+  sInGeckoCall = false;
 }
 
 PropertyValuePair*
 Gecko_AppendPropertyValuePair(nsTArray<PropertyValuePair>* aProperties,
                               nsCSSPropertyID aProperty)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aProperties);
   return aProperties->AppendElement(PropertyValuePair {aProperty});
+  sInGeckoCall = false;
 }
 
 void
 Gecko_ResetStyleCoord(nsStyleUnit* aUnit, nsStyleUnion* aValue)
 {
+  sInGeckoCall = true;
   nsStyleCoord::Reset(*aUnit, *aValue);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetStyleCoordCalcValue(nsStyleUnit* aUnit, nsStyleUnion* aValue, nsStyleCoord::CalcValue aCalc)
 {
+  sInGeckoCall = true;
   // Calc units should be cleaned up first
   MOZ_ASSERT(*aUnit != nsStyleUnit::eStyleUnit_Calc);
   nsStyleCoord::Calc* calcRef = new nsStyleCoord::Calc();
   calcRef->mLength = aCalc.mLength;
   calcRef->mPercent = aCalc.mPercent;
   calcRef->mHasPercent = aCalc.mHasPercent;
   *aUnit = nsStyleUnit::eStyleUnit_Calc;
   aValue->mPointer = calcRef;
   calcRef->AddRef();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyShapeSourceFrom(mozilla::StyleShapeSource* aDst, const mozilla::StyleShapeSource* aSrc)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aDst);
   MOZ_ASSERT(aSrc);
 
   *aDst = *aSrc;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_DestroyShapeSource(mozilla::StyleShapeSource* aShape)
 {
+  sInGeckoCall = true;
   aShape->~StyleShapeSource();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_StyleShapeSource_SetURLValue(mozilla::StyleShapeSource* aShape, ServoBundledURI aURI)
 {
+  sInGeckoCall = true;
   RefPtr<css::URLValue> url = aURI.IntoCssUrl();
   aShape->SetURL(url.get());
+  sInGeckoCall = false;
 }
 
 mozilla::StyleBasicShape*
 Gecko_NewBasicShape(mozilla::StyleBasicShapeType aType)
 {
+  sInGeckoCall = true;
   RefPtr<StyleBasicShape> ptr = new mozilla::StyleBasicShape(aType);
   return ptr.forget().take();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_ResetFilters(nsStyleEffects* effects, size_t new_len)
 {
+  sInGeckoCall = true;
   effects->mFilters.Clear();
   effects->mFilters.SetLength(new_len);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CopyFiltersFrom(nsStyleEffects* aSrc, nsStyleEffects* aDest)
 {
+  sInGeckoCall = true;
   aDest->mFilters = aSrc->mFilters;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsStyleFilter_SetURLValue(nsStyleFilter* aEffects, ServoBundledURI aURI)
 {
+  sInGeckoCall = true;
   RefPtr<css::URLValue> url = aURI.IntoCssUrl();
   aEffects->SetURL(url.get());
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsStyleSVGPaint_CopyFrom(nsStyleSVGPaint* aDest, const nsStyleSVGPaint* aSrc)
 {
+  sInGeckoCall = true;
   *aDest = *aSrc;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsStyleSVGPaint_SetURLValue(nsStyleSVGPaint* aPaint, ServoBundledURI aURI)
 {
+  sInGeckoCall = true;
   RefPtr<css::URLValue> url = aURI.IntoCssUrl();
   aPaint->SetPaintServer(url.get());
+  sInGeckoCall = false;
 }
 
 void Gecko_nsStyleSVGPaint_Reset(nsStyleSVGPaint* aPaint)
 {
   aPaint->SetNone();
 }
 
 void
 Gecko_nsStyleSVG_SetDashArrayLength(nsStyleSVG* aSvg, uint32_t aLen)
 {
+  sInGeckoCall = true;
   aSvg->mStrokeDasharray.Clear();
   aSvg->mStrokeDasharray.SetLength(aLen);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsStyleSVG_CopyDashArray(nsStyleSVG* aDst, const nsStyleSVG* aSrc)
 {
+  sInGeckoCall = true;
   aDst->mStrokeDasharray = aSrc->mStrokeDasharray;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsStyleSVG_SetContextPropertiesLength(nsStyleSVG* aSvg, uint32_t aLen)
 {
+  sInGeckoCall = true;
   aSvg->mContextProps.Clear();
   aSvg->mContextProps.SetLength(aLen);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsStyleSVG_CopyContextProperties(nsStyleSVG* aDst, const nsStyleSVG* aSrc)
 {
+  sInGeckoCall = true;
   aDst->mContextProps = aSrc->mContextProps;
   aDst->mContextPropsBits = aSrc->mContextPropsBits;
+  sInGeckoCall = false;
 }
 
 
 css::URLValue*
 Gecko_NewURLValue(ServoBundledURI aURI)
 {
+  sInGeckoCall = true;
   RefPtr<css::URLValue> url = aURI.IntoCssUrl();
   return url.forget().take();
+  sInGeckoCall = false;
 }
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(css::URLValue, CSSURLValue);
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(URLExtraData, URLExtraData);
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsStyleCoord::Calc, Calc);
 
 nsCSSShadowArray*
 Gecko_NewCSSShadowArray(uint32_t aLen)
 {
+  sInGeckoCall = true;
   RefPtr<nsCSSShadowArray> arr = new(aLen) nsCSSShadowArray(aLen);
   return arr.forget().take();
+  sInGeckoCall = false;
 }
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsCSSShadowArray, CSSShadowArray);
 
 nsStyleQuoteValues*
 Gecko_NewStyleQuoteValues(uint32_t aLen)
 {
+  sInGeckoCall = true;
   RefPtr<nsStyleQuoteValues> values = new nsStyleQuoteValues;
   values->mQuotePairs.SetLength(aLen);
   return values.forget().take();
+  sInGeckoCall = false;
 }
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsStyleQuoteValues, QuoteValues);
 
 nsCSSValueSharedList*
 Gecko_NewCSSValueSharedList(uint32_t aLen)
 {
+  sInGeckoCall = true;
   RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList;
   if (aLen == 0) {
     return list.forget().take();
   }
 
   list->mHead = new nsCSSValueList;
   nsCSSValueList* cur = list->mHead;
   for (uint32_t i = 0; i < aLen - 1; i++) {
     cur->mNext = new nsCSSValueList;
     cur = cur->mNext;
   }
 
   return list.forget().take();
+  sInGeckoCall = false;
 }
 
 nsCSSValueSharedList*
 Gecko_NewNoneTransform()
 {
+  sInGeckoCall = true;
   RefPtr<nsCSSValueSharedList> list = new nsCSSValueSharedList;
   list->mHead = new nsCSSValueList;
   list->mHead->mValue.SetNoneValue();
   return list.forget().take();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetAbsoluteLength(nsCSSValueBorrowedMut aCSSValue, nscoord aLen)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null || aCSSValue->IsLengthUnit());
   // The call below could trigger refcounting if aCSSValue were a
   // FontFamilyList, but we just asserted that it's not. So we can
   // whitelist this for static analysis.
   aCSSValue->SetIntegerCoordValue(aLen);
+  sInGeckoCall = false;
 }
 
 nscoord
 Gecko_CSSValue_GetAbsoluteLength(nsCSSValueBorrowed aCSSValue)
 {
+  sInGeckoCall = true;
   // SetIntegerCoordValue() which is used in Gecko_CSSValue_SetAbsoluteLength()
   // converts values by nsPresContext::AppUnitsToFloatCSSPixels() and stores
   // values in eCSSUnit_Pixel unit. We need to convert the values back to app
   // units by GetPixelLength().
   MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Pixel,
              "The unit should be eCSSUnit_Pixel");
   return aCSSValue->GetPixelLength();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetNumber(nsCSSValueBorrowedMut aCSSValue, float aNumber)
 {
+  sInGeckoCall = true;
   aCSSValue->SetFloatValue(aNumber, eCSSUnit_Number);
+  sInGeckoCall = false;
 }
 
 float
 Gecko_CSSValue_GetNumber(nsCSSValueBorrowed aCSSValue)
 {
+  sInGeckoCall = true;
   return aCSSValue->GetFloatValue();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetKeyword(nsCSSValueBorrowedMut aCSSValue, nsCSSKeyword aKeyword)
 {
+  sInGeckoCall = true;
   aCSSValue->SetEnumValue(aKeyword);
+  sInGeckoCall = false;
 }
 
 nsCSSKeyword
 Gecko_CSSValue_GetKeyword(nsCSSValueBorrowed aCSSValue)
 {
+  sInGeckoCall = true;
   return aCSSValue->GetKeywordValue();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetPercentage(nsCSSValueBorrowedMut aCSSValue, float aPercent)
 {
+  sInGeckoCall = true;
   aCSSValue->SetPercentValue(aPercent);
+  sInGeckoCall = false;
 }
 
 float
 Gecko_CSSValue_GetPercentage(nsCSSValueBorrowed aCSSValue)
 {
+  sInGeckoCall = true;
   return aCSSValue->GetPercentValue();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetCalc(nsCSSValueBorrowedMut aCSSValue, nsStyleCoord::CalcValue aCalc)
 {
+  sInGeckoCall = true;
   aCSSValue->SetCalcValue(&aCalc);
+  sInGeckoCall = false;
 }
 
 nsStyleCoord::CalcValue
 Gecko_CSSValue_GetCalc(nsCSSValueBorrowed aCSSValue)
 {
+  sInGeckoCall = true;
   return aCSSValue->GetCalcValue();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetFunction(nsCSSValueBorrowedMut aCSSValue, int32_t aLen)
 {
+  sInGeckoCall = true;
   nsCSSValue::Array* arr = nsCSSValue::Array::Create(aLen);
   aCSSValue->SetArrayValue(arr, eCSSUnit_Function);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetString(nsCSSValueBorrowedMut aCSSValue,
                          const uint8_t* aString, uint32_t aLength,
                          nsCSSUnit aUnit)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null);
   nsString string;
   nsDependentCSubstring slice(reinterpret_cast<const char*>(aString),
                                   aLength);
   AppendUTF8toUTF16(slice, string);
   aCSSValue->SetStringValue(string, aUnit);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetStringFromAtom(nsCSSValueBorrowedMut aCSSValue,
                                  nsIAtom* aAtom, nsCSSUnit aUnit)
 {
+  sInGeckoCall = true;
   aCSSValue->SetStringValue(nsDependentAtomString(aAtom), aUnit);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetAtomIdent(nsCSSValueBorrowedMut aCSSValue, nsIAtom* aAtom)
 {
+  sInGeckoCall = true;
   aCSSValue->SetAtomIdentValue(already_AddRefed<nsIAtom>(aAtom));
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetArray(nsCSSValueBorrowedMut aCSSValue, int32_t aLength)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null);
   RefPtr<nsCSSValue::Array> array
     = nsCSSValue::Array::Create(aLength);
   aCSSValue->SetArrayValue(array, eCSSUnit_Array);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetURL(nsCSSValueBorrowedMut aCSSValue,
                       ServoBundledURI aURI)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aCSSValue->GetUnit() == eCSSUnit_Null);
   RefPtr<css::URLValue> url = aURI.IntoCssUrl();
   aCSSValue->SetURLValue(url.get());
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetInt(nsCSSValueBorrowedMut aCSSValue,
                       int32_t aInteger, nsCSSUnit aUnit)
 {
+  sInGeckoCall = true;
   aCSSValue->SetIntValue(aInteger, aUnit);
+  sInGeckoCall = false;
 }
 
 nsCSSValueBorrowedMut
 Gecko_CSSValue_GetArrayItem(nsCSSValueBorrowedMut aCSSValue, int32_t aIndex)
 {
+  sInGeckoCall = true;
   return &aCSSValue->GetArrayValue()->Item(aIndex);
+  sInGeckoCall = false;
 }
 
 nsCSSValueBorrowed
 Gecko_CSSValue_GetArrayItemConst(nsCSSValueBorrowed aCSSValue, int32_t aIndex)
 {
+  sInGeckoCall = true;
   return &aCSSValue->GetArrayValue()->Item(aIndex);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetPair(nsCSSValueBorrowedMut aCSSValue,
                        nsCSSValueBorrowed aXValue, nsCSSValueBorrowed aYValue)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   aCSSValue->SetPairValue(*aXValue, *aYValue);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetList(nsCSSValueBorrowedMut aCSSValue, uint32_t aLen)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   nsCSSValueList* item = aCSSValue->SetListValue();
   for (uint32_t i = 1; i < aLen; ++i) {
     item->mNext = new nsCSSValueList;
     item = item->mNext;
   }
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_SetPairList(nsCSSValueBorrowedMut aCSSValue, uint32_t aLen)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   nsCSSValuePairList* item = aCSSValue->SetPairListValue();
   for (uint32_t i = 1; i < aLen; ++i) {
     item->mNext = new nsCSSValuePairList;
     item = item->mNext;
   }
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_InitSharedList(nsCSSValueBorrowedMut aCSSValue,
                               uint32_t aLen)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(aLen > 0, "Must create at least one nsCSSValueList (mHead)");
 
   nsCSSValueSharedList* list = new nsCSSValueSharedList;
   aCSSValue->SetSharedListValue(list);
   list->mHead = new nsCSSValueList;
   nsCSSValueList* cur = list->mHead;
   for (uint32_t i = 1; i < aLen; ++i) {
     cur->mNext = new nsCSSValueList;
     cur = cur->mNext;
   }
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSValue_Drop(nsCSSValueBorrowedMut aCSSValue)
 {
+  sInGeckoCall = true;
   aCSSValue->~nsCSSValue();
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsStyleFont_SetLang(nsStyleFont* aFont, nsIAtom* aAtom)
 {
+  sInGeckoCall = true;
   already_AddRefed<nsIAtom> atom = already_AddRefed<nsIAtom>(aAtom);
   aFont->mLanguage = atom;
   aFont->mExplicitLanguage = true;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsStyleFont_CopyLangFrom(nsStyleFont* aFont, const nsStyleFont* aSource)
 {
+  sInGeckoCall = true;
   aFont->mLanguage = aSource->mLanguage;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsStyleFont_FixupNoneGeneric(nsStyleFont* aFont,
                                    RawGeckoPresContextBorrowed aPresContext)
 {
+  sInGeckoCall = true;
   const nsFont* defaultVariableFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage,
                                                                      kPresContext_DefaultVariableFont_ID);
   nsRuleNode::FixupNoneGeneric(&aFont->mFont, aPresContext,
                                aFont->mGenericID, defaultVariableFont);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsStyleFont_PrefillDefaultForGeneric(nsStyleFont* aFont,
                                            RawGeckoPresContextBorrowed aPresContext,
                                            uint8_t aGenericId)
 {
+  sInGeckoCall = true;
   const nsFont* defaultFont = ThreadSafeGetDefaultFontHelper(aPresContext, aFont->mLanguage,
                                                              aGenericId);
   // In case of just the language changing, the parent could have had no generic,
   // which Gecko just does regular cascading with. Do the same.
   // This can only happen in the case where the language changed but the family did not
   if (aGenericId != kGenericFont_NONE) {
     aFont->mFont.fontlist = defaultFont->fontlist;
   } else {
     aFont->mFont.fontlist.SetDefaultFontType(defaultFont->fontlist.GetDefaultFontType());
   }
+  sInGeckoCall = false;
 }
 
 void
 Gecko_nsStyleFont_FixupMinFontSize(nsStyleFont* aFont,
                                    RawGeckoPresContextBorrowed aPresContext)
 {
+  sInGeckoCall = true;
   nscoord minFontSize;
   bool needsCache = false;
 
   {
     AutoReadLock guard(*sServoLangFontPrefsLock);
     minFontSize = aPresContext->MinFontSize(aFont->mLanguage, &needsCache);
   }
 
   if (needsCache) {
     AutoWriteLock guard(*sServoLangFontPrefsLock);
     minFontSize = aPresContext->MinFontSize(aFont->mLanguage, nullptr);
   }
 
   nsRuleNode::ApplyMinFontSize(aFont, aPresContext, minFontSize);
+  sInGeckoCall = false;
 }
 
 void
 FontSizePrefs::CopyFrom(const LangGroupFontPrefs& prefs)
 {
   mDefaultVariableSize = prefs.mDefaultVariableFont.size;
   mDefaultFixedSize = prefs.mDefaultFixedFont.size;
   mDefaultSerifSize = prefs.mDefaultSerifFont.size;
@@ -2410,50 +2781,60 @@ FontSizePrefs::CopyFrom(const LangGroupF
   mDefaultMonospaceSize = prefs.mDefaultMonospaceFont.size;
   mDefaultCursiveSize = prefs.mDefaultCursiveFont.size;
   mDefaultFantasySize = prefs.mDefaultFantasyFont.size;
 }
 
 FontSizePrefs
 Gecko_GetBaseSize(nsIAtom* aLanguage)
 {
+  sInGeckoCall = true;
   LangGroupFontPrefs prefs;
   nsCOMPtr<nsIAtom> langGroupAtom = StaticPresData::Get()->GetUncachedLangGroup(aLanguage);
 
   prefs.Initialize(langGroupAtom);
   FontSizePrefs sizes;
   sizes.CopyFrom(prefs);
 
   return sizes;
+  sInGeckoCall = false;
 }
 
 RawGeckoElementBorrowedOrNull
 Gecko_GetBindingParent(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   nsIContent* parent = aElement->GetBindingParent();
   return parent ? parent->AsElement() : nullptr;
+  sInGeckoCall = false;
 }
 
 RawGeckoXBLBindingBorrowedOrNull
 Gecko_GetXBLBinding(RawGeckoElementBorrowed aElement)
 {
+  sInGeckoCall = true;
   return aElement->GetXBLBinding();
+  sInGeckoCall = false;
 }
 
 RawServoStyleSetBorrowedOrNull
 Gecko_XBLBinding_GetRawServoStyleSet(RawGeckoXBLBindingBorrowed aXBLBinding)
 {
+  sInGeckoCall = true;
   const ServoStyleSet* set = aXBLBinding->GetServoStyleSet();
   return set ? set->RawSet() : nullptr;
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_XBLBinding_InheritsStyle(RawGeckoXBLBindingBorrowed aXBLBinding)
 {
+  sInGeckoCall = true;
   return aXBLBinding->InheritsStyle();
+  sInGeckoCall = false;
 }
 
 void
 InitializeServo()
 {
   URLExtraData::InitDummy();
   Servo_Initialize(URLExtraData::Dummy());
 
@@ -2490,16 +2871,17 @@ AssertIsMainThreadOrServoFontMetricsLock
 
 GeckoFontMetrics
 Gecko_GetFontMetrics(RawGeckoPresContextBorrowed aPresContext,
                      bool aIsVertical,
                      const nsStyleFont* aFont,
                      nscoord aFontSize,
                      bool aUseUserFontSet)
 {
+  sInGeckoCall = true;
   MutexAutoLock lock(*sServoFontMetricsLock);
   GeckoFontMetrics ret;
 
   // Getting font metrics can require some main thread only work to be
   // done, such as work that needs to touch non-threadsafe refcounted
   // objects (like the DOM FontFace/FontFaceSet objects), network loads, etc.
   //
   // To handle this work, font code checks whether we are in a Servo traversal
@@ -2514,34 +2896,38 @@ Gecko_GetFontMetrics(RawGeckoPresContext
   RefPtr<nsFontMetrics> fm = nsRuleNode::GetMetricsFor(presContext, aIsVertical,
                                                        aFont, aFontSize,
                                                        aUseUserFontSet);
   ret.mXSize = fm->XHeight();
   gfxFloat zeroWidth = fm->GetThebesFontGroup()->GetFirstValidFont()->
                            GetMetrics(fm->Orientation()).zeroOrAveCharWidth;
   ret.mChSize = ceil(aPresContext->AppUnitsPerDevPixel() * zeroWidth);
   return ret;
+  sInGeckoCall = false;
 }
 
 int32_t
 Gecko_GetAppUnitsPerPhysicalInch(RawGeckoPresContextBorrowed aPresContext)
 {
+  sInGeckoCall = true;
   nsPresContext* presContext = const_cast<nsPresContext*>(aPresContext);
   return presContext->DeviceContext()->AppUnitsPerPhysicalInch();
+  sInGeckoCall = false;
 }
 
 ServoStyleSheet*
 Gecko_LoadStyleSheet(css::Loader* aLoader,
                      ServoStyleSheet* aParent,
                      css::LoaderReusableStyleSheets* aReusableSheets,
                      RawGeckoURLExtraData* aURLExtraData,
                      const uint8_t* aURLString,
                      uint32_t aURLStringLength,
                      RawServoMediaListStrong aMediaList)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aLoader, "Should've catched this before");
   MOZ_ASSERT(aParent, "Only used for @import, so parent should exist!");
   MOZ_ASSERT(aURLString, "Invalid URLs shouldn't be loaded!");
   MOZ_ASSERT(aURLExtraData, "Need URL extra data");
 
   RefPtr<dom::MediaList> media = new ServoMediaList(aMediaList.Consume());
   nsDependentCSubstring urlSpec(reinterpret_cast<const char*>(aURLString),
@@ -2576,183 +2962,220 @@ Gecko_LoadStyleSheet(css::Loader* aLoade
     emptySheet->SetComplete();
     aParent->PrependStyleSheet(emptySheet);
     return emptySheet.forget().take();
   }
 
   RefPtr<ServoStyleSheet> sheet =
     static_cast<ServoStyleSheet*>(aParent->GetFirstChild());
   return sheet.forget().take();
+  sInGeckoCall = false;
 }
 
 nsCSSKeyword
 Gecko_LookupCSSKeyword(const uint8_t* aString, uint32_t aLength)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
 
   nsDependentCSubstring keyword(reinterpret_cast<const char*>(aString), aLength);
   return nsCSSKeywords::LookupKeyword(keyword);
+  sInGeckoCall = false;
 }
 
 const char*
 Gecko_CSSKeywordString(nsCSSKeyword aKeyword, uint32_t* aLength)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(aLength);
   const nsCString& value = nsCSSKeywords::GetStringValue(aKeyword);
   *aLength = value.Length();
   return value.get();
+  sInGeckoCall = false;
 }
 
 nsCSSFontFaceRule*
 Gecko_CSSFontFaceRule_Create(uint32_t aLine, uint32_t aColumn)
 {
+  sInGeckoCall = true;
   RefPtr<nsCSSFontFaceRule> rule = new nsCSSFontFaceRule(aLine, aColumn);
   return rule.forget().take();
+  sInGeckoCall = false;
 }
 
 nsCSSFontFaceRule*
 Gecko_CSSFontFaceRule_Clone(const nsCSSFontFaceRule* aRule)
 {
+  sInGeckoCall = true;
   RefPtr<css::Rule> rule = aRule->Clone();
   return static_cast<nsCSSFontFaceRule*>(rule.forget().take());
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSFontFaceRule_GetCssText(const nsCSSFontFaceRule* aRule,
                                  nsAString* aResult)
 {
+  sInGeckoCall = true;
   // GetCSSText serializes nsCSSValues, which have a heap write
   // hazard when dealing with color values (nsCSSKeywords::AddRefTable)
   // We only serialize on the main thread; assert to convince the analysis
   // and prevent accidentally calling this elsewhere
   MOZ_ASSERT(NS_IsMainThread());
 
   aRule->GetCssText(*aResult);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_AddPropertyToSet(nsCSSPropertyIDSetBorrowedMut aPropertySet,
                        nsCSSPropertyID aProperty)
 {
+  sInGeckoCall = true;
   aPropertySet->AddProperty(aProperty);
+  sInGeckoCall = false;
 }
 
 int32_t
 Gecko_RegisterNamespace(nsIAtom* aNamespace)
 {
+  sInGeckoCall = true;
   int32_t id;
 
   MOZ_ASSERT(NS_IsMainThread());
 
   nsAutoString str;
   aNamespace->ToString(str);
   nsresult rv = nsContentUtils::NameSpaceManager()->RegisterNameSpace(str, id);
 
   if (NS_FAILED(rv)) {
     return -1;
   }
   return id;
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_ShouldCreateStyleThreadPool()
 {
+  sInGeckoCall = true;
   return !mozilla::BrowserTabsRemoteAutostart() || XRE_IsContentProcess();
+  sInGeckoCall = false;
 }
 
 NS_IMPL_FFI_REFCOUNTING(nsCSSFontFaceRule, CSSFontFaceRule);
 
 nsCSSCounterStyleRule*
 Gecko_CSSCounterStyle_Create(nsIAtom* aName)
 {
+  sInGeckoCall = true;
   RefPtr<nsCSSCounterStyleRule> rule = new nsCSSCounterStyleRule(aName, 0, 0);
   return rule.forget().take();
+  sInGeckoCall = false;
 }
 
 nsCSSCounterStyleRule*
 Gecko_CSSCounterStyle_Clone(const nsCSSCounterStyleRule* aRule)
 {
+  sInGeckoCall = true;
   RefPtr<css::Rule> rule = aRule->Clone();
   return static_cast<nsCSSCounterStyleRule*>(rule.forget().take());
+  sInGeckoCall = false;
 }
 
 void
 Gecko_CSSCounterStyle_GetCssText(const nsCSSCounterStyleRule* aRule,
                                  nsAString* aResult)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   aRule->GetCssText(*aResult);
+  sInGeckoCall = false;
 }
 
 NS_IMPL_FFI_REFCOUNTING(nsCSSCounterStyleRule, CSSCounterStyleRule);
 
 NS_IMPL_THREADSAFE_FFI_REFCOUNTING(nsCSSValueSharedList, CSSValueSharedList);
 
 #define STYLE_STRUCT(name, checkdata_cb)                                      \
                                                                               \
 void                                                                          \
 Gecko_Construct_Default_nsStyle##name(nsStyle##name* ptr,                     \
                                       const nsPresContext* pres_context)      \
 {                                                                             \
+  sInGeckoCall = true;                                                        \
   new (ptr) nsStyle##name(pres_context);                                      \
+  sInGeckoCall = false;                                                       \
 }                                                                             \
                                                                               \
 void                                                                          \
 Gecko_CopyConstruct_nsStyle##name(nsStyle##name* ptr,                         \
                                   const nsStyle##name* other)                 \
 {                                                                             \
+  sInGeckoCall = true;                                                        \
   new (ptr) nsStyle##name(*other);                                            \
+  sInGeckoCall = false;                                                       \
 }                                                                             \
                                                                               \
 void                                                                          \
 Gecko_Destroy_nsStyle##name(nsStyle##name* ptr)                               \
 {                                                                             \
+  sInGeckoCall = true;                                                        \
   ptr->~nsStyle##name();                                                      \
+  sInGeckoCall = false;                                                       \
 }
 
 void
 Gecko_RegisterProfilerThread(const char* name)
 {
+  sInGeckoCall = true;
   char stackTop;
   profiler_register_thread(name, &stackTop);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_UnregisterProfilerThread()
 {
+  sInGeckoCall = true;
   profiler_unregister_thread();
+  sInGeckoCall = false;
 }
 
 bool
 Gecko_DocumentRule_UseForPresentation(RawGeckoPresContextBorrowed aPresContext,
                                       const nsACString* aPattern,
                                       css::URLMatchingFunction aURLMatchingFunction)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
 
   nsIDocument *doc = aPresContext->Document();
   nsIURI *docURI = doc->GetDocumentURI();
   nsAutoCString docURISpec;
   if (docURI) {
     // If GetSpec fails (due to OOM) just skip these URI-specific CSS rules.
     nsresult rv = docURI->GetSpec(docURISpec);
     NS_ENSURE_SUCCESS(rv, false);
   }
 
   return css::DocumentRule::UseForPresentation(doc, docURI, docURISpec,
                                                *aPattern, aURLMatchingFunction);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_SetJemallocThreadLocalArena(bool enabled)
 {
+  sInGeckoCall = true;
 #if defined(MOZ_MEMORY)
   jemalloc_thread_local_arena(enabled);
 #endif
+  sInGeckoCall = false;
 }
 
 #include "nsStyleStructList.h"
 
 #undef STYLE_STRUCT
 
 #ifndef MOZ_STYLO
 #define SERVO_BINDING_FUNC(name_, return_, ...)                               \
@@ -2763,40 +3186,45 @@ Gecko_SetJemallocThreadLocalArena(bool e
 #undef SERVO_BINDING_FUNC
 #endif
 
 ErrorReporter*
 Gecko_CreateCSSErrorReporter(ServoStyleSheet* sheet,
                              Loader* loader,
                              nsIURI* uri)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
   return new ErrorReporter(sheet, loader, uri);
+  sInGeckoCall = false;
 }
 
 void
 Gecko_DestroyCSSErrorReporter(ErrorReporter* reporter)
 {
+  sInGeckoCall = true;
   delete reporter;
+  sInGeckoCall = false;
 }
 
 void
 Gecko_ReportUnexpectedCSSError(ErrorReporter* reporter,
                                const char* message,
                                const char* param,
                                uint32_t paramLen,
                                const char* prefix,
                                const char* prefixParam,
                                uint32_t prefixParamLen,
                                const char* suffix,
                                const char* source,
                                uint32_t sourceLen,
                                uint32_t lineNumber,
                                uint32_t colNumber)
 {
+  sInGeckoCall = true;
   MOZ_ASSERT(NS_IsMainThread());
 
   if (prefix) {
     if (prefixParam) {
       nsDependentCSubstring paramValue(prefixParam, prefixParamLen);
       nsAutoString wideParam = NS_ConvertUTF8toUTF16(paramValue);
       reporter->ReportUnexpectedUnescaped(prefix, wideParam);
     } else {
@@ -2812,9 +3240,10 @@ Gecko_ReportUnexpectedCSSError(ErrorRepo
     reporter->ReportUnexpected(message);
   }
 
   if (suffix) {
     reporter->ReportUnexpected(suffix);
   }
   nsDependentCSubstring sourceValue(source, sourceLen);
   reporter->OutputError(lineNumber, colNumber, sourceValue);
+  sInGeckoCall = false;
 }