Bug 801176 - part3-v6: Keep CSSParser operations as threading safe. r=heycam
authorvincentliu <vliu@mozilla.com>
Fri, 04 Mar 2016 15:22:58 +0800
changeset 325006 fc509e59a0cd5a3537914158fada88c9cd1033a6
parent 325005 134a8c56335a92fdf3461ecb489a7a4b1dfcaf1c
child 325007 c090dc98c670430e2dd99bd139fabe1b094f8582
push id1128
push userjlund@mozilla.com
push dateWed, 01 Jun 2016 01:31:59 +0000
treeherdermozilla-release@fe0d30de989d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersheycam
bugs801176
milestone47.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 801176 - part3-v6: Keep CSSParser operations as threading safe. r=heycam --- dom/canvas/CanvasRenderingContext2D.cpp | 13 +++++--- layout/style/ErrorReporter.cpp | 9 +++++- layout/style/nsCSSParser.cpp | 55 ++++++++++++++++++++------------- 3 files changed, 51 insertions(+), 26 deletions(-)
dom/canvas/CanvasRenderingContext2D.cpp
layout/style/ErrorReporter.cpp
layout/style/nsCSSParser.cpp
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -679,17 +679,19 @@ CanvasGradient::AddColorStop(float aOffs
   nsCSSValue value;
   nsCSSParser parser;
   if (!parser.ParseColorString(aColorstr, nullptr, 0, value)) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return;
   }
 
   nscolor color;
-  nsCOMPtr<nsIPresShell> presShell = mContext ? mContext->GetPresShell() : nullptr;
+  nsCOMPtr<nsIPresShell> presShell = NS_IsMainThread() && mContext
+                                     ? mContext->GetPresShell()
+                                     : nullptr;
   if (!nsRuleNode::ComputeColor(value, presShell ? presShell->GetPresContext() : nullptr,
                                 nullptr, color)) {
     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
     return;
   }
 
   mStops = nullptr;
 
@@ -1012,35 +1014,38 @@ CanvasRenderingContext2D::WrapObject(JSC
 {
   return CanvasRenderingContext2DBinding::Wrap(aCx, this, aGivenProto);
 }
 
 bool
 CanvasRenderingContext2D::ParseColor(const nsAString& aString,
                                      nscolor* aColor)
 {
-  nsIDocument* document = mCanvasElement
+  nsIDocument* document = NS_IsMainThread() && mCanvasElement
                           ? mCanvasElement->OwnerDoc()
                           : nullptr;
 
   // Pass the CSS Loader object to the parser, to allow parser error
   // reports to include the outer window ID.
   nsCSSParser parser(document ? document->CSSLoader() : nullptr);
   nsCSSValue value;
   if (!parser.ParseColorString(aString, nullptr, 0, value)) {
     return false;
   }
 
   if (value.IsNumericColorUnit()) {
     // if we already have a color we can just use it directly
     *aColor = value.GetColorValue();
   } else {
     // otherwise resolve it
-    nsCOMPtr<nsIPresShell> presShell = GetPresShell();
-    RefPtr<nsStyleContext> parentContext;
+    nsCOMPtr<nsIPresShell> presShell = NS_IsMainThread()
+                                      ? GetPresShell()
+                                      : nullptr;
+
+    RefPtr<nsStyleContext> parentContext = nullptr;
     if (mCanvasElement && mCanvasElement->IsInDoc()) {
       // Inherit from the canvas element.
       parentContext = nsComputedDOMStyle::GetStyleContextForElement(
         mCanvasElement, nullptr, presShell);
     }
 
     Unused << nsRuleNode::ComputeColor(
       value, presShell ? presShell->GetPresContext() : nullptr, parentContext,
--- a/layout/style/ErrorReporter.cpp
+++ b/layout/style/ErrorReporter.cpp
@@ -107,16 +107,22 @@ InitGlobals()
   sb.forget(&sStringBundle);
 
   return true;
 }
 
 static inline bool
 ShouldReportErrors()
 {
+  // we only need to do CSS parsing off the main thread for canvas-on-workers currently,
+  // where we don't need to report any CSS parser errors
+  if (!NS_IsMainThread()) {
+    return false;
+  }
+
   if (!sConsoleService) {
     if (!InitGlobals()) {
       return false;
     }
   }
   return sReportErrors;
 }
 
@@ -142,17 +148,18 @@ ErrorReporter::ErrorReporter(const nsCSS
 {
 }
 
 ErrorReporter::~ErrorReporter()
 {
   // Schedule deferred cleanup for cached data. We want to strike a
   // balance between performance and memory usage, so we only allow
   // short-term caching.
-  if (sSpecCache && sSpecCache->IsInUse() && !sSpecCache->IsPending()) {
+  if (NS_IsMainThread() && sSpecCache && sSpecCache->IsInUse() &&
+      !sSpecCache->IsPending()) {
     if (NS_FAILED(NS_DispatchToCurrentThread(sSpecCache))) {
       // Peform the "deferred" cleanup immediately if the dispatch fails.
       sSpecCache->Run();
     } else {
       sSpecCache->SetPending();
     }
   }
 }
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -1529,22 +1529,24 @@ CSSParserImpl::CSSParserImpl()
     mParsingCompoundProperty(false),
     mInSupportsCondition(false),
     mInFailingSupportsRule(false),
     mSuppressErrors(false),
     mSheetPrincipalRequired(true),
     mWebkitBoxUnprefixState(eNotParsingDecls),
     mNextFree(nullptr)
 {
+  MOZ_COUNT_CTOR(CSSParserImpl);
 }
 
 CSSParserImpl::~CSSParserImpl()
 {
   mData.AssertInitialState();
   mTempData.AssertInitialState();
+  MOZ_COUNT_DTOR(CSSParserImpl);
 }
 
 nsresult
 CSSParserImpl::SetStyleSheet(CSSStyleSheet* aSheet)
 {
   if (aSheet != mSheet) {
     // Switch to using the new sheet, if any
     mGroupStack.Clear();
@@ -17166,55 +17168,66 @@ nsCSSParser::Startup()
                                "layout.css.prefixes.gradients");
   Preferences::AddBoolVarCache(&sControlCharVisibility,
                                "layout.css.control-characters.visible");
 }
 
 nsCSSParser::nsCSSParser(mozilla::css::Loader* aLoader,
                          CSSStyleSheet* aSheet)
 {
-  CSSParserImpl *impl = gFreeList;
-  if (impl) {
-    gFreeList = impl->mNextFree;
-    impl->mNextFree = nullptr;
+  CSSParserImpl *impl;
+  if (NS_IsMainThread()) {
+    impl = gFreeList;
+    if (impl) {
+      gFreeList = impl->mNextFree;
+      impl->mNextFree = nullptr;
+    } else {
+      impl = new CSSParserImpl();
+    }
+
+    if (aLoader) {
+      impl->SetChildLoader(aLoader);
+      impl->SetQuirkMode(aLoader->GetCompatibilityMode() ==
+                         eCompatibility_NavQuirks);
+    }
+    if (aSheet) {
+      impl->SetStyleSheet(aSheet);
+    }
   } else {
+    MOZ_ASSERT(!aLoader);
+    MOZ_ASSERT(!aSheet);
     impl = new CSSParserImpl();
   }
-
-  if (aLoader) {
-    impl->SetChildLoader(aLoader);
-    impl->SetQuirkMode(aLoader->GetCompatibilityMode() ==
-                       eCompatibility_NavQuirks);
-  }
-  if (aSheet) {
-    impl->SetStyleSheet(aSheet);
-  }
-
   mImpl = static_cast<void*>(impl);
 }
 
 nsCSSParser::~nsCSSParser()
 {
   CSSParserImpl *impl = static_cast<CSSParserImpl*>(mImpl);
   impl->Reset();
-  impl->mNextFree = gFreeList;
-  gFreeList = impl;
+  if (NS_IsMainThread()) {
+    impl->mNextFree = gFreeList;
+    gFreeList = impl;
+  } else {
+    delete impl;
+  }
 }
 
 /* static */ void
 nsCSSParser::Shutdown()
 {
+  MOZ_ASSERT(NS_IsMainThread());
   CSSParserImpl *tofree = gFreeList;
   CSSParserImpl *next;
   while (tofree)
-    {
-      next = tofree->mNextFree;
-      delete tofree;
-      tofree = next;
-    }
+  {
+    next = tofree->mNextFree;
+    delete tofree;
+    tofree = next;
+  }
 }
 
 // Wrapper methods
 
 nsresult
 nsCSSParser::ParseSheet(const nsAString& aInput,
                         nsIURI*          aSheetURI,
                         nsIURI*          aBaseURI,