Bug 1461012: Add CC optimizations for PrecompiledScript objects. r?mccr8
Tracing the script members held alive by PrecompiledScript objects can be
expensive, especially for large scripts. It would be nice if we could avoid
tracing them when possible.
Most of the time, when PrecompiledScripts are alive, they're held alive by
black roots, and have black JS wrappers. In those cases, there's no chance of
them creating garbage cycles, and we can just mark their script children
black.
MozReview-Commit-ID: KnkJfznJZBx
--- a/js/xpconnect/loader/ChromeScriptLoader.cpp
+++ b/js/xpconnect/loader/ChromeScriptLoader.cpp
@@ -15,16 +15,17 @@
#include "jsfriendapi.h"
#include "js/Utility.h"
#include "mozilla/dom/ChromeUtils.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/ScriptLoader.h"
#include "mozilla/HoldDropJSObjects.h"
#include "mozilla/SystemGroup.h"
+#include "nsCCUncollectableMarker.h"
#include "nsCycleCollectionParticipant.h"
using namespace JS;
using namespace mozilla;
using namespace mozilla::dom;
class AsyncScriptCompiler final : public nsIIncrementalStreamLoaderObserver
, public Runnable
@@ -333,16 +334,24 @@ PrecompiledScript::HasReturnValue()
}
JSObject*
PrecompiledScript::WrapObject(JSContext* aCx, HandleObject aGivenProto)
{
return PrecompiledScriptBinding::Wrap(aCx, this, aGivenProto);
}
+bool
+PrecompiledScript::IsBlackForCC(bool aTracingNeeded)
+{
+ return (nsCCUncollectableMarker::sGeneration &&
+ HasKnownLiveWrapper() &&
+ (!aTracingNeeded || HasNothingToTrace(this)));
+}
+
NS_IMPL_CYCLE_COLLECTION_CLASS(PrecompiledScript)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PrecompiledScript)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(PrecompiledScript)
@@ -356,13 +365,28 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(PrecompiledScript)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScript)
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_TRACE_END
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(PrecompiledScript)
+ if (tmp->IsBlackForCC(false)) {
+ tmp->mScript.exposeToActiveJS();
+ return true;
+ }
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_BEGIN(PrecompiledScript)
+ return tmp->IsBlackForCC(true);
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_IN_CC_END
+
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(PrecompiledScript)
+ return tmp->IsBlackForCC(false);
+NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
+
NS_IMPL_CYCLE_COLLECTING_ADDREF(PrecompiledScript)
NS_IMPL_CYCLE_COLLECTING_RELEASE(PrecompiledScript)
} // namespace dom
} // namespace mozilla
--- a/js/xpconnect/loader/PrecompiledScript.h
+++ b/js/xpconnect/loader/PrecompiledScript.h
@@ -17,17 +17,17 @@
#include "nsWrapperCache.h"
namespace mozilla {
namespace dom {
class PrecompiledScript : public nsISupports
, public nsWrapperCache
{
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PrecompiledScript)
+ NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(PrecompiledScript)
explicit PrecompiledScript(nsISupports* aParent, JS::Handle<JSScript*> aScript, JS::ReadOnlyCompileOptions& aOptions);
void ExecuteInGlobal(JSContext* aCx, JS::HandleObject aGlobal,
JS::MutableHandleValue aRval,
ErrorResult& aRv);
void GetUrl(nsAString& aUrl);
@@ -38,16 +38,18 @@ class PrecompiledScript : public nsISupp
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
protected:
virtual ~PrecompiledScript();
private:
+ bool IsBlackForCC(bool aTracingNeeded);
+
nsCOMPtr<nsISupports> mParent;
JS::Heap<JSScript*> mScript;
nsCString mURL;
const bool mHasReturnValue;
};
} // namespace dom