mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-i to m-c, a=merge
This commit is contained in:
commit
842c8df579
@ -13,8 +13,8 @@
|
||||
"unpack": "True"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
},
|
||||
|
@ -13,8 +13,8 @@
|
||||
"unpack": "True"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
},
|
||||
|
@ -15,8 +15,8 @@
|
||||
"filename": "clang.tar.bz2"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
},
|
||||
|
@ -12,8 +12,8 @@
|
||||
"filename": "gcc.tar.xz"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
},
|
||||
|
@ -15,8 +15,8 @@
|
||||
"filename": "clang.tar.bz2"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
},
|
||||
|
@ -12,8 +12,8 @@
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
},
|
||||
|
@ -1890,3 +1890,8 @@ pref("readinglist.server", "https://readinglist.services.mozilla.com/v1");
|
||||
|
||||
// Don't limit how many nodes we care about on desktop:
|
||||
pref("reader.parse-node-limit", 0);
|
||||
|
||||
// Enable Service workers for desktop on non-release builds
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("dom.serviceWorkers.enabled", true);
|
||||
#endif
|
||||
|
@ -12,8 +12,8 @@
|
||||
"filename": "gcc.tar.xz"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
}
|
||||
|
@ -12,8 +12,8 @@
|
||||
"filename": "gcc.tar.xz"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
}
|
||||
|
@ -15,8 +15,8 @@
|
||||
"filename": "clang.tar.bz2"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
}
|
||||
|
@ -15,8 +15,8 @@
|
||||
"filename": "clang.tar.bz2"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
}
|
||||
|
@ -12,8 +12,8 @@
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
}
|
||||
|
@ -12,8 +12,8 @@
|
||||
"filename": "setup.sh"
|
||||
},
|
||||
{
|
||||
"size": 166506,
|
||||
"digest": "f3c214fd571f21d64937584645212f8d7c2d12c9016be613bd2bc9cecd80b3d52a741423cc1ca69bd85fb924c3d0572c85a1734d12db1616df37abcc397e9252",
|
||||
"size": 167175,
|
||||
"digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831",
|
||||
"algorithm": "sha512",
|
||||
"filename": "sccache.tar.bz2"
|
||||
}
|
||||
|
@ -13915,7 +13915,7 @@ nsDocShell::GetURLSearchParams()
|
||||
}
|
||||
|
||||
void
|
||||
nsDocShell::NotifyJSRunToCompletionStart()
|
||||
nsDocShell::NotifyJSRunToCompletionStart(const char *aReason)
|
||||
{
|
||||
bool timelineOn = nsIDocShell::GetRecordProfileTimelineMarkers();
|
||||
|
||||
|
@ -54,7 +54,7 @@ interface nsITabParent;
|
||||
|
||||
typedef unsigned long nsLoadFlags;
|
||||
|
||||
[scriptable, builtinclass, uuid(68ba7610-e33d-47ce-8fa2-af07af2422bc)]
|
||||
[scriptable, builtinclass, uuid(bf78de98-9e88-498d-bc19-0e138f683939)]
|
||||
interface nsIDocShell : nsIDocShellTreeItem
|
||||
{
|
||||
/**
|
||||
@ -1039,7 +1039,7 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
* that execution has stopped. This only occurs when the Timeline devtool
|
||||
* is collecting information.
|
||||
*/
|
||||
[noscript,notxpcom,nostdcall] void notifyJSRunToCompletionStart();
|
||||
[noscript,notxpcom,nostdcall] void notifyJSRunToCompletionStart(in string aReason);
|
||||
[noscript,notxpcom,nostdcall] void notifyJSRunToCompletionStop();
|
||||
|
||||
/**
|
||||
|
@ -759,7 +759,10 @@ MainProcessRunnable::ReadMetadata()
|
||||
nsresult rv =
|
||||
qm->EnsureOriginIsInitialized(mPersistence, mGroup, mOrigin, mIsApp,
|
||||
getter_AddRefs(mDirectory));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mResult = JS::AsmJSCache_StorageInitFailure;
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = mDirectory->Append(NS_LITERAL_STRING(ASMJSCACHE_DIRECTORY_NAME));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -522,6 +522,7 @@ AutoJSAPI::StealException(JS::MutableHandle<JS::Value> aVal)
|
||||
}
|
||||
|
||||
AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
const char *aReason,
|
||||
bool aIsMainThread,
|
||||
JSContext* aCx)
|
||||
: AutoJSAPI(aGlobalObject, aIsMainThread,
|
||||
@ -546,7 +547,7 @@ AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
}
|
||||
|
||||
if (mDocShellForJSRunToCompletion) {
|
||||
mDocShellForJSRunToCompletion->NotifyJSRunToCompletionStart();
|
||||
mDocShellForJSRunToCompletion->NotifyJSRunToCompletionStart(aReason);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -318,11 +318,16 @@ private:
|
||||
|
||||
/*
|
||||
* A class that represents a new script entry point.
|
||||
*
|
||||
* |aReason| should be a statically-allocated C string naming the reason we're
|
||||
* invoking JavaScript code: "setTimeout", "event", and so on. The devtools use
|
||||
* these strings to label JS execution in timeline and profiling displays.
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoEntryScript : public AutoJSAPI,
|
||||
protected ScriptSettingsStackEntry {
|
||||
public:
|
||||
explicit AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
AutoEntryScript(nsIGlobalObject* aGlobalObject,
|
||||
const char *aReason,
|
||||
bool aIsMainThread = NS_IsMainThread(),
|
||||
// Note: aCx is mandatory off-main-thread.
|
||||
JSContext* aCx = nullptr);
|
||||
|
@ -20,6 +20,9 @@
|
||||
0x45f27d10, 0x987b, 0x11d2, \
|
||||
{0xbd, 0x40, 0x00, 0x10, 0x5a, 0xa4, 0x5e, 0x89} }
|
||||
|
||||
#define SERVICEWORKERPERIODICUPDATER_CONTRACTID \
|
||||
"@mozilla.org/service-worker-periodic-updater;1"
|
||||
|
||||
//The dom cannot provide the crypto or pkcs11 classes that
|
||||
//were used in older days, so if someone wants to provide
|
||||
//the service they must implement an object and give it
|
||||
|
@ -1063,7 +1063,7 @@ nsFrameMessageManager::ReceiveMessage(nsISupports* aTarget,
|
||||
// JSContext* cx = aes.cx();
|
||||
nsIGlobalObject* nativeGlobal =
|
||||
xpc::NativeGlobal(js::GetGlobalForObjectCrossCompartment(wrappedJS->GetJSObject()));
|
||||
AutoEntryScript aes(nativeGlobal);
|
||||
AutoEntryScript aes(nativeGlobal, "message manager handler");
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = aes.cx();
|
||||
JS::Rooted<JSObject*> object(cx, wrappedJS->GetJSObject());
|
||||
@ -1567,7 +1567,8 @@ nsMessageManagerScriptExecutor::LoadScriptInternal(const nsAString& aURL,
|
||||
|
||||
JS::Rooted<JSObject*> global(rt, mGlobal->GetJSObject());
|
||||
if (global) {
|
||||
AutoEntryScript aes(xpc::NativeGlobal(global));
|
||||
AutoEntryScript aes(xpc::NativeGlobal(global),
|
||||
"message manager script load");
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = aes.cx();
|
||||
if (script) {
|
||||
|
@ -2703,7 +2703,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
|
||||
if (createdInnerWindow) {
|
||||
// AutoEntryScript required to invoke debugger hook, which is a
|
||||
// Gecko-specific concept at present.
|
||||
AutoEntryScript aes(newInnerWindow);
|
||||
AutoEntryScript aes(newInnerWindow, "nsGlobalWindow report new global");
|
||||
JS::Rooted<JSObject*> global(aes.cx(), newInnerWindow->GetWrapper());
|
||||
JS_FireOnNewGlobalObject(aes.cx(), global);
|
||||
}
|
||||
@ -12323,6 +12323,13 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
|
||||
sNestingLevel = timeout->mNestingLevel;
|
||||
}
|
||||
|
||||
const char *reason;
|
||||
if (timeout->mIsInterval) {
|
||||
reason = "setInterval handler";
|
||||
} else {
|
||||
reason = "setTimeout handler";
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
|
||||
nsRefPtr<Function> callback = handler->GetCallback();
|
||||
if (!callback) {
|
||||
@ -12335,8 +12342,8 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
|
||||
handler->GetLocation(&filename, &lineNo);
|
||||
|
||||
// New script entry point required, due to the "Create a script" sub-step of
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#timer-initialization-steps
|
||||
AutoEntryScript entryScript(this, true, aScx->GetNativeContext());
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#timer-initialisation-steps
|
||||
AutoEntryScript entryScript(this, reason, true, aScx->GetNativeContext());
|
||||
JS::CompileOptions options(entryScript.cx());
|
||||
options.setFileAndLine(filename, lineNo)
|
||||
.setVersion(JSVERSION_DEFAULT);
|
||||
@ -12348,7 +12355,7 @@ nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
|
||||
nsCOMPtr<nsISupports> me(static_cast<nsIDOMWindow *>(this));
|
||||
ErrorResult ignored;
|
||||
JS::Rooted<JS::Value> ignoredVal(CycleCollectedJSRuntime::Get()->Runtime());
|
||||
callback->Call(me, handler->GetArgs(), &ignoredVal, ignored);
|
||||
callback->Call(me, handler->GetArgs(), &ignoredVal, ignored, reason);
|
||||
}
|
||||
|
||||
// We ignore any failures from calling EvaluateString() on the context or
|
||||
|
@ -1122,7 +1122,8 @@ nsScriptLoader::EvaluateScript(nsScriptLoadRequest* aRequest,
|
||||
|
||||
// New script entry point required, due to the "Create a script" sub-step of
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#execute-the-script-block
|
||||
AutoEntryScript entryScript(globalObject, true, context->GetNativeContext());
|
||||
AutoEntryScript entryScript(globalObject, "<script> element", true,
|
||||
context->GetNativeContext());
|
||||
JS::Rooted<JSObject*> global(entryScript.cx(),
|
||||
globalObject->GetGlobalJSObject());
|
||||
|
||||
|
@ -61,8 +61,11 @@ nsTraversal::TestNode(nsINode* aNode, mozilla::ErrorResult& aResult)
|
||||
if (mFilter.HasWebIDLCallback()) {
|
||||
AutoRestore<bool> inAcceptNode(mInAcceptNode);
|
||||
mInAcceptNode = true;
|
||||
// No need to pass in an execution reason, since the generated default,
|
||||
// "NodeFilter.acceptNode", is pretty much exactly what we'd say anyway.
|
||||
return mFilter.GetWebIDLCallback()->
|
||||
AcceptNode(*aNode, aResult, CallbackObject::eRethrowExceptions);
|
||||
AcceptNode(*aNode, aResult, nullptr,
|
||||
CallbackObject::eRethrowExceptions);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNode> domNode = do_QueryInterface(aNode);
|
||||
|
@ -3191,7 +3191,7 @@ WrappedJSToDictionary(nsISupports* aObject, T& aDictionary)
|
||||
|
||||
// we need this AutoEntryScript here because the spec requires us to execute
|
||||
// getters when parsing a dictionary
|
||||
AutoEntryScript aes(global);
|
||||
AutoEntryScript aes(global, "WebIDL dictionary creation");
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
|
||||
JS::Rooted<JS::Value> v(aes.cx(), JS::ObjectValue(*obj));
|
||||
|
@ -52,6 +52,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||
ErrorResult& aRv,
|
||||
const char* aExecutionReason,
|
||||
ExceptionHandling aExceptionHandling,
|
||||
JSCompartment* aCompartment,
|
||||
bool aIsJSImplementedWebIDL)
|
||||
@ -127,7 +128,8 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
|
||||
return;
|
||||
}
|
||||
|
||||
mAutoEntryScript.emplace(globalObject, mIsMainThread, cx);
|
||||
mAutoEntryScript.emplace(globalObject, aExecutionReason,
|
||||
mIsMainThread, cx);
|
||||
mAutoEntryScript->SetWebIDLCallerPrincipal(webIDLCallerPrincipal);
|
||||
nsIGlobalObject* incumbent = aCallback->IncumbentGlobalOrNull();
|
||||
if (incumbent) {
|
||||
|
@ -177,6 +177,7 @@ protected:
|
||||
// they will only be rethrown if that compartment's principal subsumes the
|
||||
// principal of our (unwrapped) callback.
|
||||
CallSetup(CallbackObject* aCallback, ErrorResult& aRv,
|
||||
const char* aExecutionReason,
|
||||
ExceptionHandling aExceptionHandling,
|
||||
JSCompartment* aCompartment = nullptr,
|
||||
bool aIsJSImplementedWebIDL = false);
|
||||
|
@ -4763,7 +4763,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
extraConditionForNull=extraConditionForNull)
|
||||
elif (not type.hasNullableType and defaultValue and
|
||||
isinstance(defaultValue, IDLNullValue)):
|
||||
assert type.hasDictionaryType
|
||||
assert type.hasDictionaryType()
|
||||
assert defaultValue.type.isDictionary()
|
||||
if not isOwningUnion and typeNeedsRooting(defaultValue.type):
|
||||
ctorArgs = "cx"
|
||||
@ -13759,9 +13759,9 @@ class CGCallback(CGClass):
|
||||
self.baseName = baseName
|
||||
self._deps = idlObject.getDeps()
|
||||
self.idlObject = idlObject
|
||||
name = idlObject.identifier.name
|
||||
self.name = idlObject.identifier.name
|
||||
if isJSImplementedDescriptor(descriptorProvider):
|
||||
name = jsImplName(name)
|
||||
self.name = jsImplName(self.name)
|
||||
# For our public methods that needThisHandling we want most of the
|
||||
# same args and the same return type as what CallbackMember
|
||||
# generates. So we want to take advantage of all its
|
||||
@ -13776,11 +13776,11 @@ class CGCallback(CGClass):
|
||||
realMethods.extend(self.getMethodImpls(method))
|
||||
realMethods.append(
|
||||
ClassMethod("operator==", "bool",
|
||||
[Argument("const %s&" % name, "aOther")],
|
||||
[Argument("const %s&" % self.name, "aOther")],
|
||||
inline=True, bodyInHeader=True,
|
||||
const=True,
|
||||
body=("return %s::operator==(aOther);\n" % baseName)))
|
||||
CGClass.__init__(self, name,
|
||||
CGClass.__init__(self, self.name,
|
||||
bases=[ClassBase(baseName)],
|
||||
constructors=self.getConstructors(),
|
||||
methods=realMethods+getters+setters)
|
||||
@ -13818,8 +13818,10 @@ class CGCallback(CGClass):
|
||||
argnamesWithThis = ["s.GetContext()", "thisValJS"] + argnames
|
||||
argnamesWithoutThis = ["s.GetContext()", "JS::UndefinedHandleValue"] + argnames
|
||||
# Now that we've recorded the argnames for our call to our private
|
||||
# method, insert our optional argument for deciding whether the
|
||||
# CallSetup should re-throw exceptions on aRv.
|
||||
# method, insert our optional arguments for the execution reason and for
|
||||
# deciding whether the CallSetup should re-throw exceptions on aRv.
|
||||
args.append(Argument("const char*", "aExecutionReason",
|
||||
"nullptr"))
|
||||
args.append(Argument("ExceptionHandling", "aExceptionHandling",
|
||||
"eReportExceptions"))
|
||||
# And the argument for communicating when exceptions should really be
|
||||
@ -13835,13 +13837,17 @@ class CGCallback(CGClass):
|
||||
|
||||
setupCall = fill(
|
||||
"""
|
||||
CallSetup s(this, aRv, aExceptionHandling, aCompartment);
|
||||
if (!aExecutionReason) {
|
||||
aExecutionReason = "${executionReason}";
|
||||
}
|
||||
CallSetup s(this, aRv, aExecutionReason, aExceptionHandling, aCompartment);
|
||||
if (!s.GetContext()) {
|
||||
aRv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return${errorReturn};
|
||||
}
|
||||
""",
|
||||
errorReturn=errorReturn)
|
||||
errorReturn=errorReturn,
|
||||
executionReason=method.getPrettyName())
|
||||
|
||||
bodyWithThis = fill(
|
||||
"""
|
||||
@ -14145,6 +14151,8 @@ class CallbackMember(CGNativeMember):
|
||||
# Since we don't need this handling, we're the actual method that
|
||||
# will be called, so we need an aRethrowExceptions argument.
|
||||
if not self.rethrowContentException:
|
||||
args.append(Argument("const char*", "aExecutionReason",
|
||||
"nullptr"))
|
||||
args.append(Argument("ExceptionHandling", "aExceptionHandling",
|
||||
"eReportExceptions"))
|
||||
args.append(Argument("JSCompartment*", "aCompartment", "nullptr"))
|
||||
@ -14162,10 +14170,10 @@ class CallbackMember(CGNativeMember):
|
||||
if self.rethrowContentException:
|
||||
# getArgs doesn't add the aExceptionHandling argument but does add
|
||||
# aCompartment for us.
|
||||
callSetup += ", eRethrowContentExceptions, aCompartment, /* aIsJSImplementedWebIDL = */ "
|
||||
callSetup += ', "%s", eRethrowContentExceptions, aCompartment, /* aIsJSImplementedWebIDL = */ ' % self.getPrettyName()
|
||||
callSetup += toStringBool(isJSImplementedDescriptor(self.descriptorProvider))
|
||||
else:
|
||||
callSetup += ", aExceptionHandling, aCompartment"
|
||||
callSetup += ', "%s", aExceptionHandling, aCompartment' % self.getPrettyName()
|
||||
callSetup += ");\n"
|
||||
return fill(
|
||||
"""
|
||||
|
@ -1471,6 +1471,14 @@ class IDLDictionary(IDLObjectWithScope):
|
||||
def isDictionary(self):
|
||||
return True;
|
||||
|
||||
def canBeEmpty(self):
|
||||
"""
|
||||
Returns true if this dictionary can be empty (that is, it has no
|
||||
required members and neither do any of its ancestors).
|
||||
"""
|
||||
return (all(member.optional for member in self.members) and
|
||||
(not self.parent or self.parent.canBeEmpty()))
|
||||
|
||||
def finish(self, scope):
|
||||
if self._finished:
|
||||
return
|
||||
@ -2133,7 +2141,7 @@ class IDLUnionType(IDLType):
|
||||
IDLType.__init__(self, location, "")
|
||||
self.memberTypes = memberTypes
|
||||
self.hasNullableType = False
|
||||
self.hasDictionaryType = False
|
||||
self._dictionaryType = None
|
||||
self.flatMemberTypes = None
|
||||
self.builtin = False
|
||||
|
||||
@ -2189,10 +2197,10 @@ class IDLUnionType(IDLType):
|
||||
if self.hasNullableType:
|
||||
raise WebIDLError("Can't have more than one nullable types in a union",
|
||||
[nullableType.location, self.flatMemberTypes[i].location])
|
||||
if self.hasDictionaryType:
|
||||
if self.hasDictionaryType():
|
||||
raise WebIDLError("Can't have a nullable type and a "
|
||||
"dictionary type in a union",
|
||||
[dictionaryType.location,
|
||||
[self._dictionaryType.location,
|
||||
self.flatMemberTypes[i].location])
|
||||
self.hasNullableType = True
|
||||
nullableType = self.flatMemberTypes[i]
|
||||
@ -2204,8 +2212,7 @@ class IDLUnionType(IDLType):
|
||||
"dictionary type in a union",
|
||||
[nullableType.location,
|
||||
self.flatMemberTypes[i].location])
|
||||
self.hasDictionaryType = True
|
||||
dictionaryType = self.flatMemberTypes[i]
|
||||
self._dictionaryType = self.flatMemberTypes[i]
|
||||
elif self.flatMemberTypes[i].isUnion():
|
||||
self.flatMemberTypes[i:i + 1] = self.flatMemberTypes[i].memberTypes
|
||||
continue
|
||||
@ -2244,6 +2251,13 @@ class IDLUnionType(IDLType):
|
||||
return False
|
||||
return True
|
||||
|
||||
def hasDictionaryType(self):
|
||||
return self._dictionaryType is not None
|
||||
|
||||
def hasPossiblyEmptyDictionaryType(self):
|
||||
return (self._dictionaryType is not None and
|
||||
self._dictionaryType.inner.canBeEmpty())
|
||||
|
||||
def _getDependentObjects(self):
|
||||
return set(self.memberTypes)
|
||||
|
||||
@ -3036,14 +3050,14 @@ class IDLNullValue(IDLObject):
|
||||
def coerceToType(self, type, location):
|
||||
if (not isinstance(type, IDLNullableType) and
|
||||
not (type.isUnion() and type.hasNullableType) and
|
||||
not (type.isUnion() and type.hasDictionaryType) and
|
||||
not (type.isUnion() and type.hasDictionaryType()) and
|
||||
not type.isDictionary() and
|
||||
not type.isAny()):
|
||||
raise WebIDLError("Cannot coerce null value to type %s." % type,
|
||||
[location])
|
||||
|
||||
nullValue = IDLNullValue(self.location)
|
||||
if type.isUnion() and not type.nullable() and type.hasDictionaryType:
|
||||
if type.isUnion() and not type.nullable() and type.hasDictionaryType():
|
||||
# We're actually a default value for the union's dictionary member.
|
||||
# Use its type.
|
||||
for t in type.flatMemberTypes:
|
||||
@ -3608,7 +3622,7 @@ class IDLArgument(IDLObjectWithIdentifier):
|
||||
self.type = type
|
||||
|
||||
if ((self.type.isDictionary() or
|
||||
self.type.isUnion() and self.type.unroll().hasDictionaryType) and
|
||||
self.type.isUnion() and self.type.unroll().hasDictionaryType()) and
|
||||
self.optional and not self.defaultValue and not self.variadic):
|
||||
# Default optional non-variadic dictionaries to null,
|
||||
# for simplicity, so the codegen doesn't have to special-case this.
|
||||
@ -3930,45 +3944,7 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
def finish(self, scope):
|
||||
IDLInterfaceMember.finish(self, scope)
|
||||
|
||||
overloadWithPromiseReturnType = None
|
||||
overloadWithoutPromiseReturnType = None
|
||||
for overload in self._overloads:
|
||||
variadicArgument = None
|
||||
|
||||
arguments = overload.arguments
|
||||
for (idx, argument) in enumerate(arguments):
|
||||
if not argument.isComplete():
|
||||
argument.complete(scope)
|
||||
assert argument.type.isComplete()
|
||||
|
||||
if (argument.type.isDictionary() or
|
||||
(argument.type.isUnion() and
|
||||
argument.type.unroll().hasDictionaryType)):
|
||||
# Dictionaries and unions containing dictionaries at the
|
||||
# end of the list or followed by optional arguments must be
|
||||
# optional.
|
||||
if (not argument.optional and
|
||||
all(arg.optional for arg in arguments[idx+1:])):
|
||||
raise WebIDLError("Dictionary argument or union "
|
||||
"argument containing a dictionary "
|
||||
"not followed by a required argument "
|
||||
"must be optional",
|
||||
[argument.location])
|
||||
|
||||
# An argument cannot be a Nullable Dictionary
|
||||
if argument.type.nullable():
|
||||
raise WebIDLError("An argument cannot be a nullable "
|
||||
"dictionary or nullable union "
|
||||
"containing a dictionary",
|
||||
[argument.location])
|
||||
|
||||
# Only the last argument can be variadic
|
||||
if variadicArgument:
|
||||
raise WebIDLError("Variadic argument is not last argument",
|
||||
[variadicArgument.location])
|
||||
if argument.variadic:
|
||||
variadicArgument = argument
|
||||
|
||||
returnType = overload.returnType
|
||||
if not returnType.isComplete():
|
||||
returnType = returnType.complete(scope)
|
||||
@ -3977,22 +3953,10 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
assert not isinstance(returnType.name, IDLUnresolvedIdentifier)
|
||||
overload.returnType = returnType
|
||||
|
||||
if returnType.isPromise():
|
||||
overloadWithPromiseReturnType = overload
|
||||
else:
|
||||
overloadWithoutPromiseReturnType = overload
|
||||
|
||||
# Make sure either all our overloads return Promises or none do
|
||||
if overloadWithPromiseReturnType and overloadWithoutPromiseReturnType:
|
||||
raise WebIDLError("We have overloads with both Promise and "
|
||||
"non-Promise return types",
|
||||
[overloadWithPromiseReturnType.location,
|
||||
overloadWithoutPromiseReturnType.location])
|
||||
|
||||
if overloadWithPromiseReturnType and self._legacycaller:
|
||||
raise WebIDLError("May not have a Promise return type for a "
|
||||
"legacycaller.",
|
||||
[overloadWithPromiseReturnType.location])
|
||||
for argument in overload.arguments:
|
||||
if not argument.isComplete():
|
||||
argument.complete(scope)
|
||||
assert argument.type.isComplete()
|
||||
|
||||
# Now compute various information that will be used by the
|
||||
# WebIDL overload resolution algorithm.
|
||||
@ -4022,12 +3986,67 @@ class IDLMethod(IDLInterfaceMember, IDLScope):
|
||||
distinguishingIndex),
|
||||
[self.location, overload.location])
|
||||
|
||||
overloadWithPromiseReturnType = None
|
||||
overloadWithoutPromiseReturnType = None
|
||||
for overload in self._overloads:
|
||||
if not overload.returnType.unroll().isExposedInAllOf(self.exposureSet):
|
||||
returnType = overload.returnType
|
||||
if not returnType.unroll().isExposedInAllOf(self.exposureSet):
|
||||
raise WebIDLError("Overload returns a type that is not exposed "
|
||||
"everywhere where the method is exposed",
|
||||
[overload.location])
|
||||
|
||||
variadicArgument = None
|
||||
|
||||
arguments = overload.arguments
|
||||
for (idx, argument) in enumerate(arguments):
|
||||
assert argument.type.isComplete()
|
||||
|
||||
if ((argument.type.isDictionary() and
|
||||
argument.type.inner.canBeEmpty())or
|
||||
(argument.type.isUnion() and
|
||||
argument.type.unroll().hasPossiblyEmptyDictionaryType())):
|
||||
# Optional dictionaries and unions containing optional
|
||||
# dictionaries at the end of the list or followed by
|
||||
# optional arguments must be optional.
|
||||
if (not argument.optional and
|
||||
all(arg.optional for arg in arguments[idx+1:])):
|
||||
raise WebIDLError("Dictionary argument or union "
|
||||
"argument containing a dictionary "
|
||||
"not followed by a required argument "
|
||||
"must be optional",
|
||||
[argument.location])
|
||||
|
||||
# An argument cannot be a Nullable Dictionary
|
||||
if argument.type.nullable():
|
||||
raise WebIDLError("An argument cannot be a nullable "
|
||||
"dictionary or nullable union "
|
||||
"containing a dictionary",
|
||||
[argument.location])
|
||||
|
||||
# Only the last argument can be variadic
|
||||
if variadicArgument:
|
||||
raise WebIDLError("Variadic argument is not last argument",
|
||||
[variadicArgument.location])
|
||||
if argument.variadic:
|
||||
variadicArgument = argument
|
||||
|
||||
if returnType.isPromise():
|
||||
overloadWithPromiseReturnType = overload
|
||||
else:
|
||||
overloadWithoutPromiseReturnType = overload
|
||||
|
||||
# Make sure either all our overloads return Promises or none do
|
||||
if overloadWithPromiseReturnType and overloadWithoutPromiseReturnType:
|
||||
raise WebIDLError("We have overloads with both Promise and "
|
||||
"non-Promise return types",
|
||||
[overloadWithPromiseReturnType.location,
|
||||
overloadWithoutPromiseReturnType.location])
|
||||
|
||||
if overloadWithPromiseReturnType and self._legacycaller:
|
||||
raise WebIDLError("May not have a Promise return type for a "
|
||||
"legacycaller.",
|
||||
[overloadWithPromiseReturnType.location])
|
||||
|
||||
def overloadsForArgCount(self, argc):
|
||||
return [overload for overload in self._overloads if
|
||||
len(overload.arguments) == argc or
|
||||
|
@ -712,6 +712,7 @@ public:
|
||||
|
||||
// Dictionary tests
|
||||
void PassDictionary(JSContext*, const Dict&);
|
||||
void PassDictionary2(JSContext*, const Dict&);
|
||||
void GetReadonlyDictionary(JSContext*, Dict&);
|
||||
void GetReadonlyNullableDictionary(JSContext*, Nullable<Dict>&);
|
||||
void GetWritableDictionary(JSContext*, Dict&);
|
||||
|
@ -685,6 +685,7 @@ interface TestInterface {
|
||||
attribute byte otherAttributeRenamedFrom;
|
||||
|
||||
void passDictionary(optional Dict x);
|
||||
void passDictionary2(Dict x);
|
||||
[Cached, Pure]
|
||||
readonly attribute Dict readonlyDictionary;
|
||||
[Cached, Pure]
|
||||
|
@ -549,6 +549,7 @@ interface TestExampleInterface {
|
||||
attribute byte otherAttributeRenamedFrom;
|
||||
|
||||
void passDictionary(optional Dict x);
|
||||
void passDictionary2(Dict x);
|
||||
[Cached, Pure]
|
||||
readonly attribute Dict readonlyDictionary;
|
||||
[Cached, Pure]
|
||||
|
@ -562,6 +562,7 @@ interface TestJSImplInterface {
|
||||
attribute byte otherAttributeRenamedFrom;
|
||||
|
||||
void passDictionary(optional Dict x);
|
||||
void passDictionary2(Dict x);
|
||||
[Cached, Pure]
|
||||
readonly attribute Dict readonlyDictionary;
|
||||
[Cached, Pure]
|
||||
|
@ -241,7 +241,7 @@ nsGeolocationSettings::HandleGeolocationPerOriginSettingsChange(const JS::Value&
|
||||
|
||||
// because the spec requires calling getters when enumerating the key of a
|
||||
// dictionary
|
||||
AutoEntryScript aes(global);
|
||||
AutoEntryScript aes(global, "geolocation.app_settings enumeration");
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
JSContext *cx = aes.cx();
|
||||
JS::AutoIdArray ids(cx, JS_Enumerate(cx, obj));
|
||||
@ -317,7 +317,7 @@ nsGeolocationSettings::HandleGeolocationAlwaysPreciseChange(const JS::Value& aVa
|
||||
NS_ENSURE_TRUE_VOID(global && global->GetGlobalJSObject());
|
||||
|
||||
// the spec requires calling getters when accessing array by index
|
||||
AutoEntryScript aes(global);
|
||||
AutoEntryScript aes(global, "geolocation.always_precise indexing");
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
JSContext *cx = aes.cx();
|
||||
|
||||
|
@ -33,7 +33,7 @@ interface nsIServiceWorkerInfo : nsISupports
|
||||
readonly attribute DOMString waitingCacheName;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(3cd3acce-8c80-4fcc-9265-067ebe8cab92)]
|
||||
[scriptable, builtinclass, uuid(c05b3b45-7f39-458c-8097-afafc7d69b01)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -124,6 +124,8 @@ interface nsIServiceWorkerManager : nsISupports
|
||||
|
||||
void sendPushEvent(in ACString scope, in DOMString data);
|
||||
void sendPushSubscriptionChangedEvent(in ACString scope);
|
||||
|
||||
void updateAllRegistrations();
|
||||
};
|
||||
|
||||
%{ C++
|
||||
|
@ -78,6 +78,7 @@
|
||||
#include "nsIMutable.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIServiceWorkerManager.h"
|
||||
#include "nsScreenManagerProxy.h"
|
||||
#include "nsMemoryInfoDumper.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
@ -1239,6 +1240,16 @@ ContentChild::RecvBidiKeyboardNotify(const bool& aIsLangRTL)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvUpdateServiceWorkerRegistrations()
|
||||
{
|
||||
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
|
||||
if (swm) {
|
||||
swm->UpdateAllRegistrations();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static CancelableTask* sFirstIdleTask;
|
||||
|
||||
static void FirstIdle(void)
|
||||
|
@ -301,6 +301,8 @@ public:
|
||||
|
||||
virtual bool RecvBidiKeyboardNotify(const bool& isLangRTL) override;
|
||||
|
||||
virtual bool RecvUpdateServiceWorkerRegistrations() override;
|
||||
|
||||
virtual bool RecvNotifyVisited(const URIParams& aURI) override;
|
||||
// auto remove when alertfinished is received.
|
||||
nsresult AddRemoteAlertObserver(const nsString& aData, nsIObserver* aObserver);
|
||||
|
@ -465,6 +465,8 @@ child:
|
||||
*/
|
||||
async BidiKeyboardNotify(bool isLangRTL);
|
||||
|
||||
async UpdateServiceWorkerRegistrations();
|
||||
|
||||
async DataStoreNotify(uint32_t aAppId, nsString aName,
|
||||
nsString aManifestURL);
|
||||
|
||||
|
@ -249,7 +249,7 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
|
||||
|
||||
// New script entry point required, due to the "Create a script" step of
|
||||
// http://www.whatwg.org/specs/web-apps/current-work/#javascript-protocol
|
||||
AutoEntryScript entryScript(innerGlobal, true,
|
||||
AutoEntryScript entryScript(innerGlobal, "javascript: URI", true,
|
||||
scriptContext->GetNativeContext());
|
||||
JSContext* cx = entryScript.cx();
|
||||
JS::Rooted<JSObject*> globalJSObject(cx, innerGlobal->GetGlobalJSObject());
|
||||
|
@ -8,8 +8,14 @@
|
||||
|
||||
#include "MediaTaskQueue.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "TaskDispatcher.h"
|
||||
|
||||
#include "nsIAppShell.h"
|
||||
#include "nsWidgetsCID.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
@ -18,13 +24,26 @@ namespace mozilla {
|
||||
StaticRefPtr<AbstractThread> sMainThread;
|
||||
ThreadLocal<AbstractThread*> AbstractThread::sCurrentThreadTLS;
|
||||
|
||||
static NS_DEFINE_CID(kAppShellCID, NS_APPSHELL_CID);
|
||||
|
||||
class XPCOMThreadWrapper : public AbstractThread
|
||||
{
|
||||
public:
|
||||
explicit XPCOMThreadWrapper(nsIThread* aTarget)
|
||||
: AbstractThread(/* aRequireTailDispatch = */ false)
|
||||
explicit XPCOMThreadWrapper(nsIThread* aTarget, bool aRequireTailDispatch)
|
||||
: AbstractThread(aRequireTailDispatch)
|
||||
, mTarget(aTarget)
|
||||
{}
|
||||
{
|
||||
// Our current mechanism of implementing tail dispatch is appshell-specific.
|
||||
// This is because a very similar mechanism already exists on the main
|
||||
// thread, and we want to avoid making event dispatch on the main thread
|
||||
// more complicated than it already is.
|
||||
//
|
||||
// If you need to use tail dispatch on other XPCOM threads, you'll need to
|
||||
// implement an nsIThreadObserver to fire the tail dispatcher at the
|
||||
// appropriate times.
|
||||
MOZ_ASSERT_IF(aRequireTailDispatch,
|
||||
NS_IsMainThread() && NS_GetCurrentThread() == aTarget);
|
||||
}
|
||||
|
||||
virtual void Dispatch(already_AddRefed<nsIRunnable> aRunnable,
|
||||
DispatchFailureHandling aFailureHandling = AssertDispatchSuccess,
|
||||
@ -45,14 +64,30 @@ public:
|
||||
virtual bool IsCurrentThreadIn() override
|
||||
{
|
||||
bool in = NS_GetCurrentThread() == mTarget;
|
||||
MOZ_ASSERT_IF(in, GetCurrent() == this);
|
||||
MOZ_ASSERT(in == (GetCurrent() == this));
|
||||
return in;
|
||||
}
|
||||
|
||||
virtual TaskDispatcher& TailDispatcher() override { MOZ_CRASH("Not implemented!"); }
|
||||
void FireTailDispatcher() { MOZ_ASSERT(mTailDispatcher.isSome()); mTailDispatcher.reset(); }
|
||||
|
||||
virtual TaskDispatcher& TailDispatcher() override
|
||||
{
|
||||
MOZ_ASSERT(this == sMainThread); // See the comment in the constructor.
|
||||
MOZ_ASSERT(IsCurrentThreadIn());
|
||||
if (!mTailDispatcher.isSome()) {
|
||||
mTailDispatcher.emplace(/* aIsTailDispatcher = */ true);
|
||||
|
||||
nsCOMPtr<nsIRunnable> event = NS_NewRunnableMethod(this, &XPCOMThreadWrapper::FireTailDispatcher);
|
||||
nsCOMPtr<nsIAppShell> appShell = do_GetService(kAppShellCID);
|
||||
appShell->RunInStableState(event);
|
||||
}
|
||||
|
||||
return mTailDispatcher.ref();
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<nsIThread> mTarget;
|
||||
Maybe<AutoTaskDispatcher> mTailDispatcher;
|
||||
};
|
||||
|
||||
AbstractThread*
|
||||
@ -70,7 +105,7 @@ AbstractThread::InitStatics()
|
||||
nsCOMPtr<nsIThread> mainThread;
|
||||
NS_GetMainThread(getter_AddRefs(mainThread));
|
||||
MOZ_DIAGNOSTIC_ASSERT(mainThread);
|
||||
sMainThread = new XPCOMThreadWrapper(mainThread.get());
|
||||
sMainThread = new XPCOMThreadWrapper(mainThread.get(), /* aRequireTailDispatch = */ true);
|
||||
ClearOnShutdown(&sMainThread);
|
||||
|
||||
if (!sCurrentThreadTLS.init()) {
|
||||
|
@ -106,8 +106,16 @@ private:
|
||||
void
|
||||
MediaTaskQueue::SyncDispatch(TemporaryRef<nsIRunnable> aRunnable) {
|
||||
NS_WARNING("MediaTaskQueue::SyncDispatch is dangerous and deprecated. Stop using this!");
|
||||
RefPtr<MediaTaskQueueSyncRunnable> task(new MediaTaskQueueSyncRunnable(aRunnable));
|
||||
Dispatch(task);
|
||||
nsRefPtr<MediaTaskQueueSyncRunnable> task(new MediaTaskQueueSyncRunnable(aRunnable));
|
||||
|
||||
// Tail dispatchers don't interact nicely with sync dispatch. We require that
|
||||
// nothing is already in the tail dispatcher, and then sidestep it for this
|
||||
// task.
|
||||
MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
|
||||
!AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
|
||||
nsRefPtr<MediaTaskQueueSyncRunnable> taskRef = task;
|
||||
Dispatch(taskRef.forget(), AssertDispatchSuccess, TailDispatch);
|
||||
|
||||
task->WaitUntilDone();
|
||||
}
|
||||
|
||||
@ -121,6 +129,11 @@ MediaTaskQueue::AwaitIdle()
|
||||
void
|
||||
MediaTaskQueue::AwaitIdleLocked()
|
||||
{
|
||||
// Make the there are no tasks for this queue waiting in the caller's tail
|
||||
// dispatcher.
|
||||
MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
|
||||
!AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
|
||||
|
||||
mQueueMonitor.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(mIsRunning || mTasks.empty());
|
||||
while (mIsRunning) {
|
||||
@ -131,6 +144,11 @@ MediaTaskQueue::AwaitIdleLocked()
|
||||
void
|
||||
MediaTaskQueue::AwaitShutdownAndIdle()
|
||||
{
|
||||
// Make the there are no tasks for this queue waiting in the caller's tail
|
||||
// dispatcher.
|
||||
MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
|
||||
!AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
|
||||
|
||||
MonitorAutoLock mon(mQueueMonitor);
|
||||
while (!mIsShutdown) {
|
||||
mQueueMonitor.Wait();
|
||||
@ -176,6 +194,11 @@ FlushableMediaTaskQueue::FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable)
|
||||
void
|
||||
FlushableMediaTaskQueue::FlushLocked()
|
||||
{
|
||||
// Make the there are no tasks for this queue waiting in the caller's tail
|
||||
// dispatcher.
|
||||
MOZ_ASSERT_IF(AbstractThread::GetCurrent(),
|
||||
!AbstractThread::GetCurrent()->TailDispatcher().HasTasksFor(this));
|
||||
|
||||
mQueueMonitor.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(mIsFlushing);
|
||||
|
||||
@ -197,7 +220,7 @@ bool
|
||||
MediaTaskQueue::IsCurrentThreadIn()
|
||||
{
|
||||
bool in = NS_GetCurrentThread() == mRunningThread;
|
||||
MOZ_ASSERT_IF(in, GetCurrent() == this);
|
||||
MOZ_ASSERT(in == (GetCurrent() == this));
|
||||
return in;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@ const PC_ICE_CONTRACT = "@mozilla.org/dom/rtcicecandidate;1";
|
||||
const PC_SESSION_CONTRACT = "@mozilla.org/dom/rtcsessiondescription;1";
|
||||
const PC_MANAGER_CONTRACT = "@mozilla.org/dom/peerconnectionmanager;1";
|
||||
const PC_STATS_CONTRACT = "@mozilla.org/dom/rtcstatsreport;1";
|
||||
const PC_IDENTITY_CONTRACT = "@mozilla.org/dom/rtcidentityassertion;1";
|
||||
const PC_STATIC_CONTRACT = "@mozilla.org/dom/peerconnectionstatic;1";
|
||||
const PC_SENDER_CONTRACT = "@mozilla.org/dom/rtpsender;1";
|
||||
const PC_RECEIVER_CONTRACT = "@mozilla.org/dom/rtpreceiver;1";
|
||||
@ -31,7 +30,6 @@ const PC_ICE_CID = Components.ID("{02b9970c-433d-4cc2-923d-f7028ac66073}");
|
||||
const PC_SESSION_CID = Components.ID("{1775081b-b62d-4954-8ffe-a067bbf508a7}");
|
||||
const PC_MANAGER_CID = Components.ID("{7293e901-2be3-4c02-b4bd-cbef6fc24f78}");
|
||||
const PC_STATS_CID = Components.ID("{7fe6e18b-0da3-4056-bf3b-440ef3809e06}");
|
||||
const PC_IDENTITY_CID = Components.ID("{1abc7499-3c54-43e0-bd60-686e2703f072}");
|
||||
const PC_STATIC_CID = Components.ID("{0fb47c47-a205-4583-a9fc-cbadf8c95880}");
|
||||
const PC_SENDER_CID = Components.ID("{4fff5d46-d827-4cd4-a970-8fd53977440e}");
|
||||
const PC_RECEIVER_CID = Components.ID("{d974b814-8fde-411c-8c45-b86791b81030}");
|
||||
@ -272,22 +270,6 @@ RTCStatsReport.prototype = {
|
||||
get mozPcid() { return this._pcid; }
|
||||
};
|
||||
|
||||
function RTCIdentityAssertion() {}
|
||||
RTCIdentityAssertion.prototype = {
|
||||
classDescription: "RTCIdentityAssertion",
|
||||
classID: PC_IDENTITY_CID,
|
||||
contractID: PC_IDENTITY_CONTRACT,
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
|
||||
Ci.nsIDOMGlobalPropertyInitializer]),
|
||||
|
||||
init: function(win) { this._win = win; },
|
||||
|
||||
__init: function(idp, name) {
|
||||
this.idp = idp;
|
||||
this.name = name;
|
||||
}
|
||||
};
|
||||
|
||||
function RTCPeerConnection() {
|
||||
this._senders = [];
|
||||
this._receivers = [];
|
||||
@ -717,9 +699,10 @@ RTCPeerConnection.prototype = {
|
||||
if (msg) {
|
||||
// Set new identity and generate an event.
|
||||
this._impl.peerIdentity = msg.identity;
|
||||
let assertion = new this._win.RTCIdentityAssertion(
|
||||
this._remoteIdp.provider, msg.identity);
|
||||
this._resolvePeerIdentity(assertion);
|
||||
this._resolvePeerIdentity(Cu.cloneInto({
|
||||
idp: this._remoteIdp.provider,
|
||||
name: msg.identity
|
||||
}, this._win));
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
@ -1343,6 +1326,5 @@ this.NSGetFactory = XPCOMUtils.generateNSGetFactory(
|
||||
RTCRtpReceiver,
|
||||
RTCRtpSender,
|
||||
RTCStatsReport,
|
||||
RTCIdentityAssertion,
|
||||
PeerConnectionObserver]
|
||||
);
|
||||
|
@ -4,7 +4,6 @@ component {02b9970c-433d-4cc2-923d-f7028ac66073} PeerConnection.js
|
||||
component {1775081b-b62d-4954-8ffe-a067bbf508a7} PeerConnection.js
|
||||
component {7293e901-2be3-4c02-b4bd-cbef6fc24f78} PeerConnection.js
|
||||
component {7fe6e18b-0da3-4056-bf3b-440ef3809e06} PeerConnection.js
|
||||
component {1abc7499-3c54-43e0-bd60-686e2703f072} PeerConnection.js
|
||||
component {0fb47c47-a205-4583-a9fc-cbadf8c95880} PeerConnection.js
|
||||
component {4fff5d46-d827-4cd4-a970-8fd53977440e} PeerConnection.js
|
||||
component {d974b814-8fde-411c-8c45-b86791b81030} PeerConnection.js
|
||||
@ -15,7 +14,6 @@ contract @mozilla.org/dom/rtcicecandidate;1 {02b9970c-433d-4cc2-923d-f7028ac6607
|
||||
contract @mozilla.org/dom/rtcsessiondescription;1 {1775081b-b62d-4954-8ffe-a067bbf508a7}
|
||||
contract @mozilla.org/dom/peerconnectionmanager;1 {7293e901-2be3-4c02-b4bd-cbef6fc24f78}
|
||||
contract @mozilla.org/dom/rtcstatsreport;1 {7fe6e18b-0da3-4056-bf3b-440ef3809e06}
|
||||
contract @mozilla.org/dom/rtcidentityassertion;1 {1abc7499-3c54-43e0-bd60-686e2703f072}
|
||||
contract @mozilla.org/dom/peerconnectionstatic;1 {0fb47c47-a205-4583-a9fc-cbadf8c95880}
|
||||
contract @mozilla.org/dom/rtpsender;1 {4fff5d46-d827-4cd4-a970-8fd53977440e}
|
||||
contract @mozilla.org/dom/rtpreceiver;1 {d974b814-8fde-411c-8c45-b86791b81030}
|
||||
|
@ -44,13 +44,15 @@ public:
|
||||
virtual void AddTask(AbstractThread* aThread,
|
||||
already_AddRefed<nsIRunnable> aRunnable,
|
||||
AbstractThread::DispatchFailureHandling aFailureHandling = AbstractThread::AssertDispatchSuccess) = 0;
|
||||
|
||||
virtual bool HasTasksFor(AbstractThread* aThread) = 0;
|
||||
};
|
||||
|
||||
/*
|
||||
* AutoTaskDispatcher is a stack-scoped TaskDispatcher implementation that fires
|
||||
* its queued tasks when it is popped off the stack.
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoTaskDispatcher : public TaskDispatcher
|
||||
class AutoTaskDispatcher : public TaskDispatcher
|
||||
{
|
||||
public:
|
||||
explicit AutoTaskDispatcher(bool aIsTailDispatcher = false) : mIsTailDispatcher(aIsTailDispatcher) {}
|
||||
@ -88,6 +90,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
bool HasTasksFor(AbstractThread* aThread) override { return !!GetTaskGroup(aThread); }
|
||||
|
||||
private:
|
||||
|
||||
struct PerThreadTaskGroup
|
||||
@ -131,16 +135,27 @@ private:
|
||||
|
||||
PerThreadTaskGroup& EnsureTaskGroup(AbstractThread* aThread)
|
||||
{
|
||||
for (size_t i = 0; i < mTaskGroups.Length(); ++i) {
|
||||
if (mTaskGroups[i]->mThread == aThread) {
|
||||
return *mTaskGroups[i];
|
||||
}
|
||||
PerThreadTaskGroup* existing = GetTaskGroup(aThread);
|
||||
if (existing) {
|
||||
return *existing;
|
||||
}
|
||||
|
||||
mTaskGroups.AppendElement(new PerThreadTaskGroup(aThread));
|
||||
return *mTaskGroups.LastElement();
|
||||
}
|
||||
|
||||
PerThreadTaskGroup* GetTaskGroup(AbstractThread* aThread)
|
||||
{
|
||||
for (size_t i = 0; i < mTaskGroups.Length(); ++i) {
|
||||
if (mTaskGroups[i]->mThread == aThread) {
|
||||
return mTaskGroups[i].get();
|
||||
}
|
||||
}
|
||||
|
||||
// Not found.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Task groups, organized by thread.
|
||||
nsTArray<UniquePtr<PerThreadTaskGroup>> mTaskGroups;
|
||||
|
||||
|
@ -58,7 +58,11 @@ private:
|
||||
{
|
||||
{
|
||||
nsRefPtr<MediaTaskQueue> queue = reader->GetTaskQueue();
|
||||
queue->Dispatch(NS_NewRunnableMethod(reader, &MP4Reader::Shutdown));
|
||||
nsCOMPtr<nsIRunnable> task = NS_NewRunnableMethod(reader, &MP4Reader::Shutdown);
|
||||
// Hackily bypass the tail dispatcher so that we can AwaitShutdownAndIdle.
|
||||
// In production code we'd use BeginShutdown + promises.
|
||||
queue->Dispatch(task.forget(), AbstractThread::AssertDispatchSuccess,
|
||||
AbstractThread::TailDispatch);
|
||||
queue->AwaitShutdownAndIdle();
|
||||
}
|
||||
decoder = nullptr;
|
||||
|
@ -21,9 +21,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=604067
|
||||
|
||||
/** Test for Bug 604067 **/
|
||||
|
||||
function documentVideo() {
|
||||
return document.body.getElementsByTagName("iframe")[0]
|
||||
.contentDocument.body.getElementsByTagName("video")[0];
|
||||
}
|
||||
|
||||
function check() {
|
||||
var v = document.body.getElementsByTagName("iframe")[0]
|
||||
.contentDocument.body.getElementsByTagName("video")[0];
|
||||
var v = documentVideo();
|
||||
|
||||
// Debug info for Bug 608634
|
||||
ok(true, "iframe src=" + document.body.getElementsByTagName("iframe")[0].src);
|
||||
@ -47,7 +51,15 @@ if (!t) {
|
||||
|
||||
var f = document.createElement("iframe");
|
||||
f.src = t.name;
|
||||
f.addEventListener("load", function() { SimpleTest.executeSoon(check); }, false);
|
||||
f.addEventListener("load", function() {
|
||||
if (documentVideo().error) {
|
||||
info("Error occured by the time we got |load| - checking directly.");
|
||||
check();
|
||||
} else {
|
||||
todo(false, "Error hasn't occurred yet - adding |error| event listener. This shouldn't happen, see bug 608634.");
|
||||
documentVideo().addEventListener("error", check);
|
||||
}
|
||||
}, false);
|
||||
document.body.appendChild(f);
|
||||
}
|
||||
|
||||
|
@ -773,7 +773,7 @@ doInvoke(NPObject *npobj, NPIdentifier method, const NPVariant *args,
|
||||
|
||||
// We're about to run script via JS_CallFunctionValue, so we need an
|
||||
// AutoEntryScript. NPAPI plugins are Gecko-specific and not in any spec.
|
||||
dom::AutoEntryScript aes(globalObject);
|
||||
dom::AutoEntryScript aes(globalObject, "NPAPI doInvoke");
|
||||
JSContext *cx = aes.cx();
|
||||
|
||||
if (!npobj || !result) {
|
||||
@ -901,7 +901,7 @@ nsJSObjWrapper::NP_GetProperty(NPObject *npobj, NPIdentifier id,
|
||||
|
||||
// We're about to run script via JS_CallFunctionValue, so we need an
|
||||
// AutoEntryScript. NPAPI plugins are Gecko-specific and not in any spec.
|
||||
dom::AutoEntryScript aes(globalObject);
|
||||
dom::AutoEntryScript aes(globalObject, "NPAPI get");
|
||||
JSContext *cx = aes.cx();
|
||||
|
||||
if (!npobj) {
|
||||
@ -935,7 +935,7 @@ nsJSObjWrapper::NP_SetProperty(NPObject *npobj, NPIdentifier npid,
|
||||
|
||||
// We're about to run script via JS_CallFunctionValue, so we need an
|
||||
// AutoEntryScript. NPAPI plugins are Gecko-specific and not in any spec.
|
||||
dom::AutoEntryScript aes(globalObject);
|
||||
dom::AutoEntryScript aes(globalObject, "NPAPI set");
|
||||
JSContext *cx = aes.cx();
|
||||
|
||||
if (!npobj) {
|
||||
|
@ -1498,7 +1498,7 @@ _evaluate(NPP npp, NPObject* npobj, NPString *script, NPVariant *result)
|
||||
return false;
|
||||
}
|
||||
|
||||
dom::AutoEntryScript aes(win);
|
||||
dom::AutoEntryScript aes(win, "NPAPI NPN_evaluate");
|
||||
JSContext* cx = aes.cx();
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, nsNPObjWrapper::GetNewOrUsed(npp, cx, npobj));
|
||||
|
@ -225,7 +225,7 @@ protected:
|
||||
JS::Rooted<JSObject*> rootedThenable(cx, mThenable);
|
||||
|
||||
mThen->Call(rootedThenable, resolveFunc, rejectFunc, rv,
|
||||
CallbackObject::eRethrowExceptions,
|
||||
"promise thenable", CallbackObject::eRethrowExceptions,
|
||||
mPromise->Compartment());
|
||||
|
||||
rv.WouldReportJSException();
|
||||
@ -630,8 +630,8 @@ Promise::CallInitFunction(const GlobalObject& aGlobal,
|
||||
return;
|
||||
}
|
||||
|
||||
aInit.Call(resolveFunc, rejectFunc, aRv, CallbackObject::eRethrowExceptions,
|
||||
Compartment());
|
||||
aInit.Call(resolveFunc, rejectFunc, aRv, "promise initializer",
|
||||
CallbackObject::eRethrowExceptions, Compartment());
|
||||
aRv.WouldReportJSException();
|
||||
|
||||
if (aRv.IsJSException()) {
|
||||
|
@ -205,7 +205,8 @@ WrapperPromiseCallback::Call(JSContext* aCx,
|
||||
|
||||
// PromiseReactionTask step 6
|
||||
JS::Rooted<JS::Value> retValue(aCx);
|
||||
mCallback->Call(value, &retValue, rv, CallbackObject::eRethrowExceptions,
|
||||
mCallback->Call(value, &retValue, rv, "promise callback",
|
||||
CallbackObject::eRethrowExceptions,
|
||||
mNextPromise->Compartment());
|
||||
|
||||
rv.WouldReportJSException();
|
||||
|
@ -4,13 +4,10 @@
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://www.w3.org/TR/2013/WD-webrtc-20130910/#idl-def-RTCIdentityAssertion
|
||||
* http://w3c.github.io/webrtc-pc/#idl-def-RTCIdentityAssertion
|
||||
*/
|
||||
|
||||
[Pref="media.peerconnection.identity.enabled",
|
||||
JSImplementation="@mozilla.org/dom/rtcidentityassertion;1",
|
||||
Constructor(DOMString idp, DOMString name)]
|
||||
interface RTCIdentityAssertion {
|
||||
attribute DOMString idp;
|
||||
attribute DOMString name;
|
||||
dictionary RTCIdentityAssertion {
|
||||
DOMString idp;
|
||||
DOMString name;
|
||||
};
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsGlobalWindow.h"
|
||||
@ -3110,6 +3111,28 @@ ServiceWorkerManager::GetAllRegistrations(nsIArray** aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
UpdateEachRegistration(const nsACString& aKey,
|
||||
ServiceWorkerRegistrationInfo* aInfo,
|
||||
void* aUserArg) {
|
||||
auto This = static_cast<ServiceWorkerManager*>(aUserArg);
|
||||
MOZ_ASSERT(!aInfo->mScope.IsEmpty());
|
||||
nsresult res = This->Update(NS_ConvertUTF8toUTF16(aInfo->mScope));
|
||||
unused << NS_WARN_IF(NS_FAILED(res));
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::UpdateAllRegistrations()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
mServiceWorkerRegistrationInfos.EnumerateRead(UpdateEachRegistration, this);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
ServiceWorkerInfo::AppendWorker(ServiceWorker* aWorker)
|
||||
{
|
||||
|
79
dom/workers/ServiceWorkerPeriodicUpdater.cpp
Normal file
79
dom/workers/ServiceWorkerPeriodicUpdater.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ServiceWorkerPeriodicUpdater.h"
|
||||
#include "mozilla/ClearOnShutdown.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "nsIServiceWorkerManager.h"
|
||||
|
||||
#define OBSERVER_TOPIC_IDLE_DAILY "idle-daily"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
|
||||
NS_IMPL_ISUPPORTS(ServiceWorkerPeriodicUpdater, nsIObserver)
|
||||
|
||||
StaticRefPtr<ServiceWorkerPeriodicUpdater>
|
||||
ServiceWorkerPeriodicUpdater::sInstance;
|
||||
bool
|
||||
ServiceWorkerPeriodicUpdater::sPeriodicUpdatesEnabled = true;
|
||||
|
||||
already_AddRefed<ServiceWorkerPeriodicUpdater>
|
||||
ServiceWorkerPeriodicUpdater::GetSingleton()
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
|
||||
if (!sInstance) {
|
||||
sInstance = new ServiceWorkerPeriodicUpdater();
|
||||
ClearOnShutdown(&sInstance);
|
||||
}
|
||||
nsRefPtr<ServiceWorkerPeriodicUpdater> copy(sInstance.get());
|
||||
return copy.forget();
|
||||
}
|
||||
|
||||
ServiceWorkerPeriodicUpdater::ServiceWorkerPeriodicUpdater()
|
||||
{
|
||||
Preferences::AddBoolVarCache(&sPeriodicUpdatesEnabled,
|
||||
"dom.serviceWorkers.periodic-updates.enabled",
|
||||
true);
|
||||
}
|
||||
|
||||
ServiceWorkerPeriodicUpdater::~ServiceWorkerPeriodicUpdater()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerPeriodicUpdater::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
if (strcmp(aTopic, OBSERVER_TOPIC_IDLE_DAILY) == 0 &&
|
||||
sPeriodicUpdatesEnabled) {
|
||||
// First, update all registrations in the parent process.
|
||||
nsCOMPtr<nsIServiceWorkerManager> swm =
|
||||
mozilla::services::GetServiceWorkerManager();
|
||||
if (swm) {
|
||||
swm->UpdateAllRegistrations();
|
||||
}
|
||||
|
||||
// Now, tell all child processes to update their registrations as well.
|
||||
nsTArray<ContentParent*> children;
|
||||
ContentParent::GetAll(children);
|
||||
for (uint32_t i = 0; i < children.Length(); i++) {
|
||||
unused << children[i]->SendUpdateServiceWorkerRegistrations();
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace workers
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
46
dom/workers/ServiceWorkerPeriodicUpdater.h
Normal file
46
dom/workers/ServiceWorkerPeriodicUpdater.h
Normal file
@ -0,0 +1,46 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
* vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ :
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_ServiceWorkerPeriodicUpdater_h
|
||||
#define mozilla_ServiceWorkerPeriodicUpdater_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
namespace workers {
|
||||
|
||||
/**
|
||||
* This XPCOM component is main-process only, which means that it will never
|
||||
* get instantiated in child processes. When we receive the idle-daily
|
||||
* notification in this component, we iterate over all PContent children, and
|
||||
* send each one a message that will trigger a call to
|
||||
* nsIServiceWorkerManager::UpdateAllRegistrations() in all child processes.
|
||||
*/
|
||||
|
||||
class ServiceWorkerPeriodicUpdater final : public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
static already_AddRefed<ServiceWorkerPeriodicUpdater> GetSingleton();
|
||||
|
||||
private:
|
||||
ServiceWorkerPeriodicUpdater();
|
||||
~ServiceWorkerPeriodicUpdater();
|
||||
|
||||
static StaticRefPtr<ServiceWorkerPeriodicUpdater> sInstance;
|
||||
static bool sPeriodicUpdatesEnabled;
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
@ -297,7 +297,7 @@ WorkerRunnable::Run()
|
||||
MOZ_ASSERT(IsCanceled(), "Subclass Cancel() didn't set IsCanceled()!");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
// Track down the appropriate global to use for the AutoJSAPI/AutoEntryScript.
|
||||
nsCOMPtr<nsIGlobalObject> globalObject;
|
||||
@ -332,8 +332,9 @@ WorkerRunnable::Run()
|
||||
Maybe<mozilla::dom::AutoEntryScript> aes;
|
||||
JSContext* cx;
|
||||
if (globalObject) {
|
||||
aes.emplace(globalObject, isMainThread, isMainThread ? nullptr :
|
||||
GetCurrentThreadJSContext());
|
||||
aes.emplace(globalObject, "Worker runnable",
|
||||
isMainThread,
|
||||
isMainThread ? nullptr : GetCurrentThreadJSContext());
|
||||
cx = aes->cx();
|
||||
} else {
|
||||
jsapi.Init();
|
||||
@ -352,7 +353,8 @@ WorkerRunnable::Run()
|
||||
// In the case of CompileScriptRunnnable, WorkerRun above can cause us to
|
||||
// lazily create a global, so we construct aes here before calling PostRun.
|
||||
if (targetIsWorkerThread && !aes && DefaultGlobalObject()) {
|
||||
aes.emplace(DefaultGlobalObject(), false, GetCurrentThreadJSContext());
|
||||
aes.emplace(DefaultGlobalObject(), "worker runnable",
|
||||
false, GetCurrentThreadJSContext());
|
||||
cx = aes->cx();
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,7 @@ EXPORTS.mozilla.dom += [
|
||||
|
||||
EXPORTS.mozilla.dom.workers += [
|
||||
'ServiceWorkerManager.h',
|
||||
'ServiceWorkerPeriodicUpdater.h',
|
||||
'WorkerDebuggerManager.h',
|
||||
'Workers.h',
|
||||
]
|
||||
@ -68,6 +69,7 @@ UNIFIED_SOURCES += [
|
||||
'ServiceWorkerContainer.cpp',
|
||||
'ServiceWorkerEvents.cpp',
|
||||
'ServiceWorkerManager.cpp',
|
||||
'ServiceWorkerPeriodicUpdater.cpp',
|
||||
'ServiceWorkerRegistrar.cpp',
|
||||
'ServiceWorkerRegistration.cpp',
|
||||
'ServiceWorkerScriptCache.cpp',
|
||||
|
@ -46,6 +46,19 @@ fetchXHR('synthesized-headers.txt', function(xhr) {
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('synthesized-redirect-real-file.txt', function(xhr) {
|
||||
dump("Got status AARRGH " + xhr.status + " " + xhr.responseText + "\n");
|
||||
my_ok(xhr.status == 200, "load should be successful");
|
||||
my_ok(xhr.responseText == "This is a real file.\n", "Redirect to real file should complete.");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('synthesized-redirect-synthesized.txt', function(xhr) {
|
||||
my_ok(xhr.status == 200, "load should be successful");
|
||||
my_ok(xhr.responseText == "synthesized response body", "load should have synthesized response");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetchXHR('ignored.txt', function(xhr) {
|
||||
my_ok(xhr.status == 404, "load should be uninterrupted");
|
||||
finish();
|
||||
|
1
dom/workers/test/serviceworkers/fetch/real-file.txt
Normal file
1
dom/workers/test/serviceworkers/fetch/real-file.txt
Normal file
@ -0,0 +1 @@
|
||||
This is a real file.
|
@ -27,6 +27,18 @@ onfetch = function(ev) {
|
||||
ev.respondWith(new Response("test-respondwith-response response body", {}));
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("synthesized-redirect-real-file.txt")) {
|
||||
ev.respondWith(Promise.resolve(
|
||||
Response.redirect("fetch/real-file.txt")
|
||||
));
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("synthesized-redirect-synthesized.txt")) {
|
||||
ev.respondWith(Promise.resolve(
|
||||
Response.redirect("synthesized.txt")
|
||||
));
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("ignored.txt")) {
|
||||
}
|
||||
|
||||
|
@ -27,6 +27,7 @@ support-files =
|
||||
fetch/fetch_worker_script.js
|
||||
fetch/fetch_tests.js
|
||||
fetch/deliver-gzip.sjs
|
||||
fetch/real-file.txt
|
||||
fetch/context/index.html
|
||||
fetch/context/register.html
|
||||
fetch/context/unregister.html
|
||||
@ -68,11 +69,15 @@ support-files =
|
||||
bug1151916_worker.js
|
||||
bug1151916_driver.html
|
||||
empty.js
|
||||
periodic.sjs
|
||||
periodic/frame.html
|
||||
periodic/register.html
|
||||
periodic/unregister.html
|
||||
|
||||
[test_unregister.html]
|
||||
[test_installation_simple.html]
|
||||
[test_fetch_event.html]
|
||||
skip-if = true # Bug 1136780
|
||||
skip-if = os != "linux" # Bug 1136780
|
||||
[test_https_fetch.html]
|
||||
[test_https_fetch_cloned_response.html]
|
||||
[test_match_all.html]
|
||||
@ -97,3 +102,5 @@ skip-if = true # Bug 1136780
|
||||
[test_client_focus.html]
|
||||
[test_bug1151916.html]
|
||||
[test_empty_serviceworker.html]
|
||||
[test_periodic_update.html]
|
||||
skip-if = true # bug 1151974
|
||||
|
18
dom/workers/test/serviceworkers/periodic.sjs
Normal file
18
dom/workers/test/serviceworkers/periodic.sjs
Normal file
@ -0,0 +1,18 @@
|
||||
function handleRequest(request, response) {
|
||||
if (!getState('periodiccounter')) {
|
||||
setState('periodiccounter', '1');
|
||||
} else {
|
||||
// Make sure that we pass a string value to setState!
|
||||
setState('periodiccounter', "" + (parseInt(getState('periodiccounter')) + 1));
|
||||
}
|
||||
response.setHeader("Content-Type", "application/javascript", false);
|
||||
response.write(getScript());
|
||||
}
|
||||
|
||||
function getScript() {
|
||||
return "onfetch = function(e) {" +
|
||||
"if (e.request.url.indexOf('get-sw-version') > -1) {" +
|
||||
"e.respondWith(new Response('" + getState('periodiccounter') + "'));" +
|
||||
"}" +
|
||||
"};";
|
||||
}
|
8
dom/workers/test/serviceworkers/periodic/frame.html
Normal file
8
dom/workers/test/serviceworkers/periodic/frame.html
Normal file
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
fetch("get-sw-version").then(function(r) {
|
||||
return r.text();
|
||||
}).then(function(body) {
|
||||
parent.callback(body);
|
||||
});
|
||||
</script>
|
21
dom/workers/test/serviceworkers/periodic/register.html
Normal file
21
dom/workers/test/serviceworkers/periodic/register.html
Normal file
@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
var isDone = false;
|
||||
function done() {
|
||||
if (!isDone) {
|
||||
parent.callback();
|
||||
isDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
navigator.serviceWorker.register("../periodic.sjs", {scope: "."})
|
||||
.then(function(registration) {
|
||||
if (registration.installing) {
|
||||
registration.installing.onstatechange = function(e) {
|
||||
done();
|
||||
};
|
||||
} else {
|
||||
done();
|
||||
}
|
||||
});
|
||||
</script>
|
12
dom/workers/test/serviceworkers/periodic/unregister.html
Normal file
12
dom/workers/test/serviceworkers/periodic/unregister.html
Normal file
@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<script>
|
||||
navigator.serviceWorker.getRegistration(".").then(function(registration) {
|
||||
registration.unregister().then(function(success) {
|
||||
if (success) {
|
||||
parent.callback();
|
||||
} else {
|
||||
dump("Unregister failed\n");
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
98
dom/workers/test/serviceworkers/test_periodic_update.html
Normal file
98
dom/workers/test/serviceworkers/test_periodic_update.html
Normal file
@ -0,0 +1,98 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 1112469 - Test the periodic update of service workers</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
|
||||
var oldSWVersion, newSWVersion;
|
||||
|
||||
function start() {
|
||||
const Cc = SpecialPowers.Cc;
|
||||
const Ci = SpecialPowers.Ci;
|
||||
|
||||
function testVersion(sw) {
|
||||
// Verify that the service worker has been correctly updated.
|
||||
testFrame("periodic/frame.html").then(function(body) {
|
||||
newSWVersion = parseInt(body);
|
||||
todo_is(newSWVersion, "2", "Expected correct new version");
|
||||
ok(newSWVersion > oldSWVersion,
|
||||
"The SW should be successfully updated, old: " + oldSWVersion +
|
||||
", new: " + newSWVersion);
|
||||
unregisterSW().then(function() {
|
||||
SimpleTest.finish();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
registerSW().then(function() {
|
||||
return testFrame("periodic/frame.html").then(function(body) {
|
||||
oldSWVersion = parseInt(body);
|
||||
todo_is(oldSWVersion, "1", "Expected correct old version");
|
||||
});
|
||||
}).then(function() {
|
||||
return navigator.serviceWorker.getRegistration("periodic/foo");
|
||||
}).then(function(reg) {
|
||||
reg.onupdatefound = function() {
|
||||
reg.onupdatefound = null;
|
||||
var sw = reg.installing;
|
||||
sw.onstatechange = function() {
|
||||
sw.onstatechange = null;
|
||||
ok(!reg.waiting && reg.active, "New worker must get activated immediately");
|
||||
testVersion(reg.active);
|
||||
};
|
||||
};
|
||||
}).then(function() {
|
||||
SpecialPowers.startPeriodicServiceWorkerUpdates();
|
||||
});
|
||||
}
|
||||
|
||||
function testFrame(src) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var iframe = document.createElement("iframe");
|
||||
iframe.src = src;
|
||||
window.callback = function(result) {
|
||||
iframe.src = "about:blank";
|
||||
document.body.removeChild(iframe);
|
||||
iframe = null;
|
||||
SpecialPowers.exactGC(window, function() {
|
||||
resolve(result);
|
||||
});
|
||||
};
|
||||
document.body.appendChild(iframe);
|
||||
});
|
||||
}
|
||||
|
||||
function registerSW() {
|
||||
return testFrame("periodic/register.html");
|
||||
}
|
||||
|
||||
function unregisterSW() {
|
||||
return testFrame("periodic/unregister.html");
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.exemptFromPerDomainMax", true],
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.serviceWorkers.periodic-updates.enabled", true],
|
||||
]}, function() {
|
||||
start();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -402,7 +402,7 @@ nsXBLProtoImplField::InstallField(JS::Handle<JSObject*> aBoundNode,
|
||||
|
||||
// We are going to run script via EvaluateString, so we need a script entry
|
||||
// point, but as this is XBL related it does not appear in the HTML spec.
|
||||
AutoEntryScript entryScript(globalObject, true);
|
||||
AutoEntryScript entryScript(globalObject, "XBL <field> initialization", true);
|
||||
JSContext* cx = entryScript.cx();
|
||||
|
||||
NS_ASSERTION(!::JS_IsExceptionPending(cx),
|
||||
|
@ -294,7 +294,7 @@ nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement, JSAddonId* aAd
|
||||
|
||||
// We are going to run script via JS::Call, so we need a script entry point,
|
||||
// but as this is XBL related it does not appear in the HTML spec.
|
||||
dom::AutoEntryScript aes(global);
|
||||
dom::AutoEntryScript aes(global, "XBL <constructor>/<destructor> invocation");
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = aes.cx();
|
||||
|
||||
|
@ -3563,7 +3563,7 @@ XULDocument::ExecuteScript(nsXULPrototypeScript *aScript)
|
||||
// Execute the precompiled script with the given version.
|
||||
// We're about to run script via JS::CloneAndExecuteScript, so we need an
|
||||
// AutoEntryScript. This is Gecko specific and not in any spec.
|
||||
AutoEntryScript aes(mScriptGlobalObject);
|
||||
AutoEntryScript aes(mScriptGlobalObject, "precompiled XUL <script> element");
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = aes.cx();
|
||||
JS::Rooted<JSObject*> baseGlobal(cx, JS::CurrentGlobalOrNull(cx));
|
||||
|
@ -1385,7 +1385,7 @@ nsXULTemplateBuilder::InitHTMLTemplateRoot()
|
||||
|
||||
// We are going to run script via JS_SetProperty, so we need a script entry
|
||||
// point, but as this is XUL related it does not appear in the HTML spec.
|
||||
AutoEntryScript entryScript(innerWin, true);
|
||||
AutoEntryScript entryScript(innerWin, "nsXULTemplateBuilder creation", true);
|
||||
JSContext* jscontext = entryScript.cx();
|
||||
|
||||
JS::Rooted<JS::Value> v(jscontext);
|
||||
|
@ -96,6 +96,14 @@ public:
|
||||
return mContext;
|
||||
}
|
||||
|
||||
EGLSurface GetEGLSurface() {
|
||||
return mSurface;
|
||||
}
|
||||
|
||||
EGLDisplay GetEGLDisplay() {
|
||||
return EGL_DISPLAY();
|
||||
}
|
||||
|
||||
bool BindTex2DOffscreen(GLContext *aOffscreen);
|
||||
void UnbindTex2DOffscreen(GLContext *aOffscreen);
|
||||
void BindOffscreenFramebuffer();
|
||||
|
@ -230,17 +230,6 @@ GLContextEGL::GLContextEGL(
|
||||
#ifdef DEBUG
|
||||
printf_stderr("Initializing context %p surface %p on display %p\n", mContext, mSurface, EGL_DISPLAY());
|
||||
#endif
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
if (!mIsOffscreen) {
|
||||
mHwc = HwcComposer2D::GetInstance();
|
||||
MOZ_ASSERT(!mHwc->Initialized());
|
||||
|
||||
if (mHwc->Init(EGL_DISPLAY(), mSurface, this)) {
|
||||
NS_WARNING("HWComposer initialization failed!");
|
||||
mHwc = nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
GLContextEGL::~GLContextEGL()
|
||||
@ -466,16 +455,13 @@ GLContextEGL::SwapBuffers()
|
||||
? mSurfaceOverride
|
||||
: mSurface;
|
||||
if (surface) {
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION < 17
|
||||
if (!mIsOffscreen) {
|
||||
if (mHwc) {
|
||||
return mHwc->Render(EGL_DISPLAY(), surface);
|
||||
} else {
|
||||
return GetGonkDisplay()->SwapBuffers(EGL_DISPLAY(), surface);
|
||||
}
|
||||
} else
|
||||
// eglSwapBuffers() is called by hwcomposer.
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), surface);
|
||||
return sEGLLibrary.fSwapBuffers(EGL_DISPLAY(), surface);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -661,16 +661,12 @@ LayerManagerComposite::Render()
|
||||
|
||||
/** Our more efficient but less powerful alter ego, if one is available. */
|
||||
nsRefPtr<Composer2D> composer2D;
|
||||
composer2D = mCompositor->GetWidget()->GetComposer2D();
|
||||
|
||||
// We can't use composert2D if we have layer effects, so only get it
|
||||
// when we don't have any effects.
|
||||
if (!haveLayerEffects) {
|
||||
composer2D = mCompositor->GetWidget()->GetComposer2D();
|
||||
}
|
||||
|
||||
if (!mTarget &&
|
||||
// We can't use composert2D if we have layer effects
|
||||
if (!mTarget && !haveLayerEffects &&
|
||||
gfxPrefs::Composer2DCompositionEnabled() &&
|
||||
composer2D && composer2D->TryRender(mRoot, mGeometryChanged))
|
||||
composer2D && composer2D->HasHwc() && composer2D->TryRenderWithHwc(mRoot, mGeometryChanged))
|
||||
{
|
||||
LayerScope::SetHWComposed();
|
||||
if (mFPS) {
|
||||
@ -684,7 +680,7 @@ LayerManagerComposite::Render()
|
||||
mInvalidRegion.SetEmpty();
|
||||
mLastFrameMissedHWC = false;
|
||||
return;
|
||||
} else if (!mTarget) {
|
||||
} else if (!mTarget && !haveLayerEffects) {
|
||||
mLastFrameMissedHWC = !!composer2D;
|
||||
}
|
||||
|
||||
@ -775,6 +771,10 @@ LayerManagerComposite::Render()
|
||||
mCompositor->SetFBAcquireFence(mRoot);
|
||||
}
|
||||
|
||||
if (composer2D) {
|
||||
composer2D->Render();
|
||||
}
|
||||
|
||||
mCompositor->GetWidget()->PostRender(this);
|
||||
|
||||
RecordFrame();
|
||||
|
@ -52,7 +52,19 @@ public:
|
||||
* Currently, when TryRender() returns true, the entire framebuffer
|
||||
* must have been rendered.
|
||||
*/
|
||||
virtual bool TryRender(Layer* aRoot, bool aGeometryChanged) = 0;
|
||||
virtual bool TryRenderWithHwc(Layer* aRoot, bool aGeometryChanged) = 0;
|
||||
|
||||
/**
|
||||
* Return true if Composer2D does composition. Return false if Composer2D
|
||||
* failed the composition.
|
||||
*/
|
||||
virtual bool Render() = 0;
|
||||
|
||||
/**
|
||||
* Return true if Composer2D has a fast composition hardware.
|
||||
* Return false if Composer2D does not have a fast composition hardware.
|
||||
*/
|
||||
virtual bool HasHwc() = 0;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -131,13 +131,19 @@ CompositorOGL::CreateContext()
|
||||
caps, requireCompatProfile);
|
||||
}
|
||||
|
||||
if (!context)
|
||||
if (!context) {
|
||||
context = gl::GLContextProvider::CreateForWindow(mWidget);
|
||||
}
|
||||
|
||||
if (!context) {
|
||||
NS_WARNING("Failed to create CompositorOGL context");
|
||||
}
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
mWidget->SetNativeData(NS_NATIVE_OPENGL_CONTEXT,
|
||||
reinterpret_cast<uintptr_t>(context.get()));
|
||||
#endif
|
||||
|
||||
return context.forget();
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,8 @@ TestShellCommandParent::RunCallback(const nsString& aResponse)
|
||||
// We're about to run script via JS_CallFunctionValue, so we need an
|
||||
// AutoEntryScript. This is just for testing and not in any spec.
|
||||
dom::AutoEntryScript aes(
|
||||
xpc::NativeGlobal(js::GetGlobalForObjectCrossCompartment(&mCallback.toObject())));
|
||||
xpc::NativeGlobal(js::GetGlobalForObjectCrossCompartment(&mCallback.toObject())),
|
||||
"TestShellCommand");
|
||||
JSContext* cx = aes.cx();
|
||||
JS::Rooted<JSObject*> global(cx, JS::CurrentGlobalOrNull(cx));
|
||||
|
||||
|
@ -281,7 +281,8 @@ WrapperAnswer::RecvGet(const ObjectId& objId, const ObjectVariant& receiverVar,
|
||||
const JSIDVariant& idVar, ReturnStatus* rs, JSVariant* result)
|
||||
{
|
||||
// We may run scripted getters.
|
||||
AutoEntryScript aes(xpc::NativeGlobal(scopeForTargetObjects()));
|
||||
AutoEntryScript aes(xpc::NativeGlobal(scopeForTargetObjects()),
|
||||
"Cross-Process Object Wrapper 'get'");
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = aes.cx();
|
||||
|
||||
@ -318,7 +319,8 @@ WrapperAnswer::RecvSet(const ObjectId& objId, const JSIDVariant& idVar, const JS
|
||||
const JSVariant& receiverVar, ReturnStatus* rs)
|
||||
{
|
||||
// We may run scripted setters.
|
||||
AutoEntryScript aes(xpc::NativeGlobal(scopeForTargetObjects()));
|
||||
AutoEntryScript aes(xpc::NativeGlobal(scopeForTargetObjects()),
|
||||
"Cross-Process Object Wrapper 'set'");
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = aes.cx();
|
||||
|
||||
@ -379,7 +381,8 @@ WrapperAnswer::RecvCallOrConstruct(const ObjectId& objId,
|
||||
JSVariant* result,
|
||||
nsTArray<JSParam>* outparams)
|
||||
{
|
||||
AutoEntryScript aes(xpc::NativeGlobal(scopeForTargetObjects()));
|
||||
AutoEntryScript aes(xpc::NativeGlobal(scopeForTargetObjects()),
|
||||
"Cross-Process Object Wrapper call/construct");
|
||||
aes.TakeOwnershipOfErrorReporting();
|
||||
JSContext* cx = aes.cx();
|
||||
|
||||
|
@ -80,11 +80,6 @@ GCTraceKindToAscii(JSGCTraceKind kind);
|
||||
typedef void
|
||||
(* JSTraceCallback)(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind);
|
||||
|
||||
// Callback that JSTraceOp implementation can provide to return a string
|
||||
// describing the reference traced with JS_CallTracer.
|
||||
typedef void
|
||||
(* JSTraceNamePrinter)(JSTracer* trc, char* buf, size_t bufsize);
|
||||
|
||||
enum WeakMapTraceKind {
|
||||
DoNotTraceWeakMaps = 0,
|
||||
TraceWeakMapValues = 1,
|
||||
@ -94,80 +89,12 @@ enum WeakMapTraceKind {
|
||||
class JS_PUBLIC_API(JSTracer)
|
||||
{
|
||||
public:
|
||||
// Set debugging information about a reference to a traceable thing to prepare
|
||||
// for the following call to JS_CallTracer.
|
||||
//
|
||||
// When printer is null, arg must be const char * or char * C string naming
|
||||
// the reference and index must be either (size_t)-1 indicating that the name
|
||||
// alone describes the reference or it must be an index into some array vector
|
||||
// that stores the reference.
|
||||
//
|
||||
// When printer callback is not null, the arg and index arguments are
|
||||
// available to the callback as debugPrintArg_ and debugPrintIndex_ fields
|
||||
// of JSTracer.
|
||||
//
|
||||
// The storage for name or callback's arguments needs to live only until
|
||||
// the following call to JS_CallTracer returns.
|
||||
void setTracingDetails(JSTraceNamePrinter printer, const void* arg, size_t index) {
|
||||
debugPrinter_ = printer;
|
||||
debugPrintArg_ = arg;
|
||||
debugPrintIndex_ = index;
|
||||
}
|
||||
|
||||
void setTracingIndex(const char* name, size_t index) {
|
||||
setTracingDetails(nullptr, (void*)name, index);
|
||||
}
|
||||
|
||||
void setTracingName(const char* name) {
|
||||
setTracingDetails(nullptr, (void*)name, InvalidIndex);
|
||||
}
|
||||
|
||||
// Remove the currently set tracing details.
|
||||
void clearTracingDetails() {
|
||||
debugPrinter_ = nullptr;
|
||||
debugPrintArg_ = nullptr;
|
||||
}
|
||||
|
||||
const static size_t InvalidIndex = size_t(-1);
|
||||
|
||||
// Return true if tracing details are currently set.
|
||||
bool hasTracingDetails() const;
|
||||
|
||||
// Get the string set with the most recent call to setTracingName or return
|
||||
// fallback if a name printer function has been installed.
|
||||
const char* tracingName(const char* fallback) const;
|
||||
|
||||
// Build a description of this edge in the heap graph. This call may invoke
|
||||
// the debug printer, which may inspect arbitrary areas of the heap.
|
||||
const char* getTracingEdgeName(char* buffer, size_t bufferSize);
|
||||
|
||||
// Access the currently active tracing details.
|
||||
JSTraceNamePrinter debugPrinter() const;
|
||||
const void* debugPrintArg() const;
|
||||
size_t debugPrintIndex() const;
|
||||
|
||||
// Return the runtime set on the tracer.
|
||||
JSRuntime* runtime() const { return runtime_; }
|
||||
|
||||
// Return the weak map tracing behavior set on this tracer.
|
||||
WeakMapTraceKind eagerlyTraceWeakMaps() const { return eagerlyTraceWeakMaps_; }
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
// Sets the "real" location for a marked reference, when passing the address
|
||||
// directly is not feasable. This address is used for matching against the
|
||||
// store buffer when verifying the correctness of the entrees there.
|
||||
//
|
||||
// This is currently complicated by our need to nest calls for Values
|
||||
// stored as keys in hash tables.
|
||||
void setTracingLocation(void* location);
|
||||
void unsetTracingLocation();
|
||||
void** tracingLocation(void** thingp);
|
||||
#else
|
||||
void setTracingLocation(void* location) {}
|
||||
void unsetTracingLocation() {}
|
||||
void** tracingLocation(void** thingp) { return nullptr; }
|
||||
#endif
|
||||
|
||||
// An intermediate state on the road from C to C++ style dispatch.
|
||||
enum TracerKindTag {
|
||||
MarkingTracer,
|
||||
@ -184,23 +111,24 @@ class JS_PUBLIC_API(JSTracer)
|
||||
private:
|
||||
JSRuntime* runtime_;
|
||||
TracerKindTag tag;
|
||||
JSTraceNamePrinter debugPrinter_;
|
||||
const void* debugPrintArg_;
|
||||
size_t debugPrintIndex_;
|
||||
WeakMapTraceKind eagerlyTraceWeakMaps_;
|
||||
#ifdef JS_GC_ZEAL
|
||||
void* realLocation_;
|
||||
#endif
|
||||
};
|
||||
|
||||
namespace JS {
|
||||
|
||||
class AutoTracingName;
|
||||
class AutoTracingIndex;
|
||||
class AutoTracingCallback;
|
||||
class AutoOriginalTraceLocation;
|
||||
|
||||
class JS_PUBLIC_API(CallbackTracer) : public JSTracer
|
||||
{
|
||||
public:
|
||||
CallbackTracer(JSRuntime* rt, JSTraceCallback traceCallback,
|
||||
WeakMapTraceKind weakTraceKind = TraceWeakMapValues)
|
||||
: JSTracer(rt, JSTracer::CallbackTracer, weakTraceKind), callback(traceCallback)
|
||||
: JSTracer(rt, JSTracer::CallbackTracer, weakTraceKind), callback(traceCallback),
|
||||
contextName_(nullptr), contextIndex_(InvalidIndex), contextFunctor_(nullptr),
|
||||
contextRealLocation_(nullptr)
|
||||
{}
|
||||
|
||||
// Update the trace callback.
|
||||
@ -216,10 +144,173 @@ class JS_PUBLIC_API(CallbackTracer) : public JSTracer
|
||||
callback(this, thing, kind);
|
||||
}
|
||||
|
||||
// Access to the tracing context:
|
||||
// When tracing with a JS::CallbackTracer, we invoke the callback with the
|
||||
// edge location and the type of target. This is useful for operating on
|
||||
// the edge in the abstract or on the target thing, satisfying most common
|
||||
// use cases. However, some tracers need additional detail about the
|
||||
// specific edge that is being traced in order to be useful. Unfortunately,
|
||||
// the raw pointer to the edge that we provide is not enough information to
|
||||
// infer much of anything useful about that edge.
|
||||
//
|
||||
// In order to better support use cases that care in particular about edges
|
||||
// -- as opposed to the target thing -- tracing implementations are
|
||||
// responsible for providing extra context information about each edge they
|
||||
// trace, as it is traced. This contains, at a minimum, an edge name and,
|
||||
// when tracing an array, the index. Further specialization can be achived
|
||||
// (with some complexity), by associating a functor with the tracer so
|
||||
// that, when requested, the user can generate totally custom edge
|
||||
// descriptions.
|
||||
|
||||
// Returns the current edge's name. It is only valid to call this when
|
||||
// inside the trace callback, however, the edge name will always be set.
|
||||
const char* contextName() const { MOZ_ASSERT(contextName_); return contextName_; }
|
||||
|
||||
// Returns the current edge's index, if marked as part of an array of edges.
|
||||
// This must be called only inside the trace callback. When not tracing an
|
||||
// array, the value will be InvalidIndex.
|
||||
const static size_t InvalidIndex = size_t(-1);
|
||||
size_t contextIndex() const { return contextIndex_; }
|
||||
|
||||
// Build a description of this edge in the heap graph. This call may invoke
|
||||
// the context functor, if set, which may inspect arbitrary areas of the
|
||||
// heap. On the other hand, the description provided by this method may be
|
||||
// substantially more accurate and useful than those provided by only the
|
||||
// contextName and contextIndex.
|
||||
const char* getTracingEdgeName(char* buffer, size_t bufferSize);
|
||||
|
||||
// The trace implementation may associate a callback with one or more edges
|
||||
// using AutoTracingDetails. This functor is called by getTracingEdgeName
|
||||
// and is responsible for providing a textual representation of the
|
||||
// currently being traced edge. The callback has access to the full heap,
|
||||
// including the currently set tracing context.
|
||||
class ContextFunctor {
|
||||
public:
|
||||
virtual void operator()(CallbackTracer* trc, char* buf, size_t bufsize) = 0;
|
||||
};
|
||||
|
||||
// Return the original heap tracing location if the raw thingp reference
|
||||
// has been moved. This is generally only useful for heap analyses that
|
||||
// need to build an accurate model of the heap, and thus is only accurate
|
||||
// when built with JS_GC_ZEAL.
|
||||
void*const* tracingLocation(void** thingp) {
|
||||
return contextRealLocation_ ? contextRealLocation_ : thingp;
|
||||
}
|
||||
|
||||
private:
|
||||
// Exposed publicly for several callers that need to check if the tracer
|
||||
// calling them is of the right type.
|
||||
JSTraceCallback callback;
|
||||
|
||||
friend class AutoTracingName;
|
||||
const char* contextName_;
|
||||
|
||||
friend class AutoTracingIndex;
|
||||
size_t contextIndex_;
|
||||
|
||||
friend class AutoTracingDetails;
|
||||
ContextFunctor* contextFunctor_;
|
||||
|
||||
friend class AutoOriginalTraceLocation;
|
||||
void*const* contextRealLocation_;
|
||||
};
|
||||
|
||||
// Set the name portion of the tracer's context for the current edge.
|
||||
class AutoTracingName
|
||||
{
|
||||
CallbackTracer* trc_;
|
||||
const char *prior_;
|
||||
|
||||
public:
|
||||
AutoTracingName(CallbackTracer* trc, const char* name) : trc_(trc), prior_(trc->contextName_) {
|
||||
MOZ_ASSERT(name);
|
||||
trc->contextName_ = name;
|
||||
}
|
||||
~AutoTracingName() {
|
||||
MOZ_ASSERT(trc_->contextName_);
|
||||
trc_->contextName_ = prior_;
|
||||
}
|
||||
};
|
||||
|
||||
// Set the index portion of the tracer's context for the current range.
|
||||
class AutoTracingIndex
|
||||
{
|
||||
CallbackTracer* trc_;
|
||||
|
||||
public:
|
||||
explicit AutoTracingIndex(JSTracer* trc, size_t initial = 0) : trc_(nullptr) {
|
||||
if (trc->isCallbackTracer()) {
|
||||
trc_ = trc->asCallbackTracer();
|
||||
MOZ_ASSERT(trc_->contextIndex_ == CallbackTracer::InvalidIndex);
|
||||
trc_->contextIndex_ = initial;
|
||||
}
|
||||
}
|
||||
~AutoTracingIndex() {
|
||||
if (trc_) {
|
||||
MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex);
|
||||
trc_->contextIndex_ = CallbackTracer::InvalidIndex;
|
||||
}
|
||||
}
|
||||
|
||||
void operator++() {
|
||||
if (trc_) {
|
||||
MOZ_ASSERT(trc_->contextIndex_ != CallbackTracer::InvalidIndex);
|
||||
++trc_->contextIndex_;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Set a context callback for the trace callback to use, if it needs a detailed
|
||||
// edge description.
|
||||
class AutoTracingDetails
|
||||
{
|
||||
CallbackTracer* trc_;
|
||||
|
||||
public:
|
||||
AutoTracingDetails(JSTracer* trc, CallbackTracer::ContextFunctor& func) : trc_(nullptr) {
|
||||
if (trc->isCallbackTracer()) {
|
||||
trc_ = trc->asCallbackTracer();
|
||||
MOZ_ASSERT(trc_->contextFunctor_ == nullptr);
|
||||
trc_->contextFunctor_ = &func;
|
||||
}
|
||||
}
|
||||
~AutoTracingDetails() {
|
||||
if (trc_) {
|
||||
MOZ_ASSERT(trc_->contextFunctor_);
|
||||
trc_->contextFunctor_ = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Some dynamic analyses depend on knowing the edge source location as it
|
||||
// exists in the object graph. When marking some types of things, e.g. Value
|
||||
// edges, it is necessary to copy into a temporary on the stack. This class
|
||||
// records the original location if we need to copy the tracee, so that the
|
||||
// relevant analyses can continue to operate correctly.
|
||||
class AutoOriginalTraceLocation
|
||||
{
|
||||
#ifdef JS_GC_ZEAL
|
||||
CallbackTracer *trc_;
|
||||
|
||||
public:
|
||||
template <typename T>
|
||||
AutoOriginalTraceLocation(JSTracer* trc, T*const* realLocation) : trc_(nullptr) {
|
||||
if (trc->isCallbackTracer() && trc->asCallbackTracer()->contextRealLocation_ == nullptr) {
|
||||
trc_ = trc->asCallbackTracer();
|
||||
trc_->contextRealLocation_ = reinterpret_cast<void*const*>(realLocation);
|
||||
}
|
||||
}
|
||||
~AutoOriginalTraceLocation() {
|
||||
if (trc_) {
|
||||
MOZ_ASSERT(trc_->contextRealLocation_);
|
||||
trc_->contextRealLocation_ = nullptr;
|
||||
}
|
||||
}
|
||||
#else
|
||||
public:
|
||||
template <typename T>
|
||||
AutoOriginalTraceLocation(JSTracer* trc, T*const* realLocation) {}
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace JS
|
||||
@ -284,7 +375,7 @@ inline void
|
||||
JS_CallHashSetObjectTracer(JSTracer* trc, HashSetEnum& e, JSObject* const& key, const char* name)
|
||||
{
|
||||
JSObject* updated = key;
|
||||
trc->setTracingLocation(reinterpret_cast<void*>(&const_cast<JSObject*&>(key)));
|
||||
JS::AutoOriginalTraceLocation reloc(trc, &key);
|
||||
JS_CallUnbarrieredObjectTracer(trc, &updated, name);
|
||||
if (updated != key)
|
||||
e.rekeyFront(updated);
|
||||
|
@ -2043,6 +2043,9 @@ class MOZ_STACK_CLASS ModuleCompiler
|
||||
case JS::AsmJSCache_QuotaExceeded:
|
||||
cacheString = "not enough temporary storage quota to store in cache";
|
||||
break;
|
||||
case JS::AsmJSCache_StorageInitFailure:
|
||||
cacheString = "storage initialization failed (consider filing a bug)";
|
||||
break;
|
||||
case JS::AsmJSCache_Disabled_Internal:
|
||||
cacheString = "caching disabled by internal configuration (consider filing a bug)";
|
||||
break;
|
||||
|
@ -839,7 +839,7 @@ HashableValue
|
||||
HashableValue::mark(JSTracer* trc) const
|
||||
{
|
||||
HashableValue hv(*this);
|
||||
trc->setTracingLocation((void*)this);
|
||||
JS::AutoOriginalTraceLocation reloc(trc, (void**)this);
|
||||
TraceEdge(trc, &hv.value, "key");
|
||||
return hv;
|
||||
}
|
||||
|
@ -42,36 +42,6 @@ void * const js::NullPtr::constNullValue = nullptr;
|
||||
|
||||
JS_PUBLIC_DATA(void * const) JS::NullPtr::constNullValue = nullptr;
|
||||
|
||||
/*
|
||||
* There are two mostly separate mark paths. The first is a fast path used
|
||||
* internally in the GC. The second is a slow path used for root marking and
|
||||
* for API consumers like the cycle collector or Class::trace implementations.
|
||||
*
|
||||
* The fast path uses explicit stacks. The basic marking process during a GC is
|
||||
* that all roots are pushed on to a mark stack, and then each item on the
|
||||
* stack is scanned (possibly pushing more stuff) until the stack is empty.
|
||||
*
|
||||
* PushMarkStack pushes a GC thing onto the mark stack. In some cases (shapes
|
||||
* or strings) it eagerly marks the object rather than pushing it. Popping and
|
||||
* scanning is done by the processMarkStackTop method. For efficiency reasons
|
||||
* like tail recursion elimination that method also implements the scanning of
|
||||
* objects. For other GC things it uses helper methods.
|
||||
*
|
||||
* Most of the marking code outside Marking.cpp uses functions like MarkObject,
|
||||
* MarkString, etc. These functions check if an object is in the compartment
|
||||
* currently being GCed. If it is, they call PushMarkStack. Roots are pushed
|
||||
* this way as well as pointers traversed inside trace hooks (for things like
|
||||
* PropertyIteratorObjects). It is always valid to call a MarkX function
|
||||
* instead of PushMarkStack, although it may be slower.
|
||||
*
|
||||
* The MarkX functions also handle non-GC object traversal. In this case, they
|
||||
* call a callback for each object visited. This is a recursive process; the
|
||||
* mark stacks are not involved. These callbacks may ask for the outgoing
|
||||
* pointers to be visited. Eventually, this leads to the MarkChildren functions
|
||||
* being called. These functions duplicate much of the functionality of
|
||||
* scanning functions, but they don't push onto an explicit stack.
|
||||
*/
|
||||
|
||||
static inline void
|
||||
PushMarkStack(GCMarker* gcmarker, JSObject* thing) {
|
||||
gcmarker->traverse(thing);
|
||||
@ -106,14 +76,6 @@ PushMarkStack(GCMarker* gcmarker, JSString* thing);
|
||||
static inline void
|
||||
PushMarkStack(GCMarker* gcmarker, JS::Symbol* thing);
|
||||
|
||||
namespace js {
|
||||
namespace gc {
|
||||
|
||||
static void MarkChildren(JSTracer* trc, ObjectGroup* group);
|
||||
|
||||
} /* namespace gc */
|
||||
} /* namespace js */
|
||||
|
||||
/*** Object Marking ***/
|
||||
|
||||
#if defined(DEBUG)
|
||||
@ -272,17 +234,6 @@ CheckMarkedThing<jsid>(JSTracer* trc, jsid id)
|
||||
trc->runtime()->gc.state() == NO_INCREMENTAL || \
|
||||
trc->runtime()->gc.state() == MARK_ROOTS);
|
||||
|
||||
#define FOR_EACH_GC_LAYOUT(D) \
|
||||
D(Object, JSObject) \
|
||||
D(String, JSString) \
|
||||
D(Symbol, JS::Symbol) \
|
||||
D(Script, JSScript) \
|
||||
D(Shape, js::Shape) \
|
||||
D(BaseShape, js::BaseShape) \
|
||||
D(JitCode, js::jit::JitCode) \
|
||||
D(LazyScript, js::LazyScript) \
|
||||
D(ObjectGroup, js::ObjectGroup)
|
||||
|
||||
// A C++ version of JSGCTraceKind
|
||||
enum class TraceKind {
|
||||
#define NAMES(name, _) name,
|
||||
@ -368,8 +319,8 @@ ConvertToBase(T* thingp)
|
||||
return reinterpret_cast<typename PtrBaseGCType<T>::type*>(thingp);
|
||||
}
|
||||
|
||||
template <typename T> void DispatchToTracer(JSTracer* trc, T* thingp, const char* name, size_t i);
|
||||
template <typename T> void DoTracing(JS::CallbackTracer* trc, T* thingp, const char* name, size_t i);
|
||||
template <typename T> void DispatchToTracer(JSTracer* trc, T* thingp, const char* name);
|
||||
template <typename T> void DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name);
|
||||
template <typename T> void DoMarking(GCMarker* gcmarker, T thing);
|
||||
static bool ShouldMarkCrossCompartment(JSTracer* trc, JSObject* src, Cell* cell);
|
||||
static bool ShouldMarkCrossCompartment(JSTracer* trc, JSObject* src, Value val);
|
||||
@ -378,14 +329,14 @@ template <typename T>
|
||||
void
|
||||
js::TraceEdge(JSTracer* trc, BarrieredBase<T>* thingp, const char* name)
|
||||
{
|
||||
DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name, JSTracer::InvalidIndex);
|
||||
DispatchToTracer(trc, ConvertToBase(thingp->unsafeGet()), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceManuallyBarrieredEdge(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
DispatchToTracer(trc, ConvertToBase(thingp), name, JSTracer::InvalidIndex);
|
||||
DispatchToTracer(trc, ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -393,16 +344,18 @@ void
|
||||
js::TraceRoot(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
JS_ROOT_MARKING_ASSERT(trc);
|
||||
DispatchToTracer(trc, ConvertToBase(thingp), name, JSTracer::InvalidIndex);
|
||||
DispatchToTracer(trc, ConvertToBase(thingp), name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
js::TraceRange(JSTracer* trc, size_t len, BarrieredBase<T>* vec, const char* name)
|
||||
{
|
||||
JS::AutoTracingIndex index(trc);
|
||||
for (auto i : MakeRange(len)) {
|
||||
if (InternalGCMethods<T>::isMarkable(vec[i].get()))
|
||||
DispatchToTracer(trc, ConvertToBase(vec[i].unsafeGet()), name, i);
|
||||
DispatchToTracer(trc, ConvertToBase(vec[i].unsafeGet()), name);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
@ -411,9 +364,11 @@ void
|
||||
js::TraceRootRange(JSTracer* trc, size_t len, T* vec, const char* name)
|
||||
{
|
||||
JS_ROOT_MARKING_ASSERT(trc);
|
||||
JS::AutoTracingIndex index(trc);
|
||||
for (auto i : MakeRange(len)) {
|
||||
if (InternalGCMethods<T>::isMarkable(vec[i]))
|
||||
DispatchToTracer(trc, ConvertToBase(&vec[i]), name, i);
|
||||
DispatchToTracer(trc, ConvertToBase(&vec[i]), name);
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
@ -433,7 +388,7 @@ js::TraceManuallyBarrieredCrossCompartmentEdge(JSTracer* trc, JSObject* src, T*
|
||||
const char* name)
|
||||
{
|
||||
if (ShouldMarkCrossCompartment(trc, src, *dst))
|
||||
DispatchToTracer(trc, dst, name, -1);
|
||||
DispatchToTracer(trc, dst, name);
|
||||
}
|
||||
template void js::TraceManuallyBarrieredCrossCompartmentEdge<JSObject*>(JSTracer*, JSObject*,
|
||||
JSObject**, const char*);
|
||||
@ -445,7 +400,7 @@ void
|
||||
js::TraceCrossCompartmentEdge(JSTracer* trc, JSObject* src, BarrieredBase<T>* dst, const char* name)
|
||||
{
|
||||
if (ShouldMarkCrossCompartment(trc, src, dst->get()))
|
||||
DispatchToTracer(trc, dst->unsafeGet(), name, -1);
|
||||
DispatchToTracer(trc, dst->unsafeGet(), name);
|
||||
}
|
||||
template void js::TraceCrossCompartmentEdge<Value>(JSTracer*, JSObject*, BarrieredBase<Value>*,
|
||||
const char*);
|
||||
@ -455,7 +410,7 @@ template void js::TraceCrossCompartmentEdge<Value>(JSTracer*, JSObject*, Barrier
|
||||
// a sufficiently smart C++ compiler may be able to devirtualize some paths.
|
||||
template <typename T>
|
||||
void
|
||||
DispatchToTracer(JSTracer* trc, T* thingp, const char* name, size_t i)
|
||||
DispatchToTracer(JSTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
#define IS_SAME_TYPE_OR(name, type) mozilla::IsSame<type*, T>::value ||
|
||||
static_assert(
|
||||
@ -468,7 +423,7 @@ DispatchToTracer(JSTracer* trc, T* thingp, const char* name, size_t i)
|
||||
|
||||
if (trc->isMarkingTracer())
|
||||
return DoMarking(static_cast<GCMarker*>(trc), *thingp);
|
||||
return DoTracing(static_cast<JS::CallbackTracer*>(trc), thingp, name, i);
|
||||
return DoCallback(trc->asCallbackTracer(), thingp, name);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -542,8 +497,6 @@ DoMarking<Value>(GCMarker* gcmarker, Value val)
|
||||
DoMarking(gcmarker, &val.toObject());
|
||||
else if (val.isSymbol())
|
||||
DoMarking(gcmarker, val.toSymbol());
|
||||
else
|
||||
gcmarker->clearTracingDetails();
|
||||
}
|
||||
|
||||
template <>
|
||||
@ -554,110 +507,6 @@ DoMarking<jsid>(GCMarker* gcmarker, jsid id)
|
||||
DoMarking(gcmarker, JSID_TO_STRING(id));
|
||||
else if (JSID_IS_SYMBOL(id))
|
||||
DoMarking(gcmarker, JSID_TO_SYMBOL(id));
|
||||
else
|
||||
gcmarker->clearTracingDetails();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
DoTracing(JS::CallbackTracer* trc, T* thingp, const char* name, size_t i)
|
||||
{
|
||||
JSGCTraceKind kind = MapTypeToTraceKind<typename mozilla::RemovePointer<T>::Type>::kind;
|
||||
trc->setTracingIndex(name, i);
|
||||
trc->invoke((void**)thingp, kind);
|
||||
trc->unsetTracingLocation();
|
||||
}
|
||||
|
||||
template <>
|
||||
void
|
||||
DoTracing<Value>(JS::CallbackTracer* trc, Value* vp, const char* name, size_t i)
|
||||
{
|
||||
if (vp->isObject()) {
|
||||
JSObject* prior = &vp->toObject();
|
||||
JSObject* obj = prior;
|
||||
DoTracing(trc, &obj, name, i);
|
||||
if (obj != prior)
|
||||
vp->setObjectOrNull(obj);
|
||||
} else if (vp->isString()) {
|
||||
JSString* prior = vp->toString();
|
||||
JSString* str = prior;
|
||||
DoTracing(trc, &str, name, i);
|
||||
if (str != prior)
|
||||
vp->setString(str);
|
||||
} else if (vp->isSymbol()) {
|
||||
JS::Symbol* prior = vp->toSymbol();
|
||||
JS::Symbol* sym = prior;
|
||||
DoTracing(trc, &sym, name, i);
|
||||
if (sym != prior)
|
||||
vp->setSymbol(sym);
|
||||
} else {
|
||||
/* Unset realLocation manually if we do not call MarkInternal. */
|
||||
trc->unsetTracingLocation();
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void
|
||||
DoTracing<jsid>(JS::CallbackTracer* trc, jsid* idp, const char* name, size_t i)
|
||||
{
|
||||
if (JSID_IS_STRING(*idp)) {
|
||||
JSString* prior = JSID_TO_STRING(*idp);
|
||||
JSString* str = prior;
|
||||
DoTracing(trc, &str, name, i);
|
||||
if (str != prior)
|
||||
*idp = NON_INTEGER_ATOM_TO_JSID(reinterpret_cast<JSAtom*>(str));
|
||||
} else if (JSID_IS_SYMBOL(*idp)) {
|
||||
JS::Symbol* prior = JSID_TO_SYMBOL(*idp);
|
||||
JS::Symbol* sym = prior;
|
||||
DoTracing(trc, &sym, name, i);
|
||||
if (sym != prior)
|
||||
*idp = SYMBOL_TO_JSID(sym);
|
||||
} else {
|
||||
/* Unset realLocation manually if we do not call MarkInternal. */
|
||||
trc->unsetTracingLocation();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void
|
||||
MarkInternal(JSTracer* trc, T** thingp)
|
||||
{
|
||||
T* thing = *thingp;
|
||||
CheckMarkedThing(trc, thing);
|
||||
|
||||
if (trc->isMarkingTracer()) {
|
||||
/*
|
||||
* We may mark a Nursery thing outside the context of the
|
||||
* MinorCollectionTracer because of a pre-barrier. The pre-barrier is
|
||||
* not needed in this case because we perform a minor collection before
|
||||
* each incremental slice.
|
||||
*/
|
||||
if (IsInsideNursery(thing))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Don't mark permanent atoms, as they may be associated with another
|
||||
* runtime. Note that PushMarkStack() also checks this, but the tests
|
||||
* and maybeAlive write below should only be done on the main thread.
|
||||
*/
|
||||
if (ThingIsPermanentAtomOrWellKnownSymbol(thing))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Don't mark things outside a compartment if we are in a
|
||||
* per-compartment GC.
|
||||
*/
|
||||
if (!thing->zone()->isGCMarking())
|
||||
return;
|
||||
|
||||
PushMarkStack(AsGCMarker(trc), thing);
|
||||
SetMaybeAliveFlag(thing);
|
||||
} else {
|
||||
trc->asCallbackTracer()->invoke((void**)thingp, MapTypeToTraceKind<T>::kind);
|
||||
trc->unsetTracingLocation();
|
||||
}
|
||||
|
||||
trc->clearTracingDetails();
|
||||
}
|
||||
|
||||
namespace js {
|
||||
@ -666,24 +515,17 @@ namespace gc {
|
||||
void
|
||||
MarkPermanentAtom(JSTracer* trc, JSAtom* atom, const char* name)
|
||||
{
|
||||
trc->setTracingName(name);
|
||||
|
||||
MOZ_ASSERT(atom->isPermanent());
|
||||
|
||||
// We have to mark permanent atoms through a special method because the
|
||||
// default DoMarking implementation automatically skips them. Fortunatly,
|
||||
// atoms cannot refer to other GC things, so they do not need to go through
|
||||
// the mark stack and may simply be marked directly.
|
||||
CheckMarkedThing(trc, atom);
|
||||
|
||||
if (trc->isMarkingTracer()) {
|
||||
// Atoms do not refer to other GC things so don't need to go on the mark stack.
|
||||
// Additionally, PushMarkStack will ignore permanent atoms.
|
||||
if (trc->isMarkingTracer())
|
||||
atom->markIfUnmarked();
|
||||
} else {
|
||||
void* thing = atom;
|
||||
trc->asCallbackTracer()->invoke(&thing, JSTRACE_STRING);
|
||||
MOZ_ASSERT(thing == atom);
|
||||
trc->unsetTracingLocation();
|
||||
}
|
||||
|
||||
trc->clearTracingDetails();
|
||||
else
|
||||
DoCallback(trc->asCallbackTracer(), reinterpret_cast<JSString**>(&atom), name);
|
||||
}
|
||||
|
||||
void
|
||||
@ -691,23 +533,17 @@ MarkWellKnownSymbol(JSTracer* trc, JS::Symbol* sym)
|
||||
{
|
||||
if (!sym)
|
||||
return;
|
||||
|
||||
trc->setTracingName("wellKnownSymbols");
|
||||
|
||||
MOZ_ASSERT(sym->isWellKnownSymbol());
|
||||
|
||||
// As per permanent atoms, the normal marking path is not adequate.
|
||||
CheckMarkedThing(trc, sym);
|
||||
if (trc->isMarkingTracer()) {
|
||||
// Permanent atoms are marked before well-known symbols.
|
||||
MOZ_ASSERT(sym->description()->isMarked());
|
||||
sym->markIfUnmarked();
|
||||
} else {
|
||||
void* thing = sym;
|
||||
trc->asCallbackTracer()->invoke(&thing, JSTRACE_SYMBOL);
|
||||
MOZ_ASSERT(thing == sym);
|
||||
trc->unsetTracingLocation();
|
||||
DoCallback(trc->asCallbackTracer(), &sym, "wellKnownSymbol");
|
||||
}
|
||||
|
||||
trc->clearTracingDetails();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@ -974,38 +810,6 @@ js::gc::TraceManuallyBarrieredGenericPointerEdge(JSTracer* trc, Cell** thingp, c
|
||||
CallTyped(f, (*thingp)->getTraceKind(), trc, thingp, name);
|
||||
}
|
||||
|
||||
/*** Value Marking ***/
|
||||
|
||||
static inline void
|
||||
MarkValueInternal(JSTracer* trc, Value* v)
|
||||
{
|
||||
if (v->isMarkable()) {
|
||||
MOZ_ASSERT(v->toGCThing());
|
||||
void* thing = v->toGCThing();
|
||||
trc->setTracingLocation((void*)v);
|
||||
if (v->isString()) {
|
||||
JSString* str = static_cast<JSString*>(thing);
|
||||
MarkInternal(trc, &str);
|
||||
if (str != thing)
|
||||
v->setString(str);
|
||||
} else if (v->isObject()) {
|
||||
JSObject* obj = static_cast<JSObject*>(thing);
|
||||
MarkInternal(trc, &obj);
|
||||
if (obj != thing)
|
||||
v->setObjectOrNull(obj);
|
||||
} else {
|
||||
MOZ_ASSERT(v->isSymbol());
|
||||
JS::Symbol* sym = static_cast<JS::Symbol*>(thing);
|
||||
MarkInternal(trc, &sym);
|
||||
if (sym != thing)
|
||||
v->setSymbol(sym);
|
||||
}
|
||||
} else {
|
||||
/* Unset realLocation manually if we do not call MarkInternal. */
|
||||
trc->unsetTracingLocation();
|
||||
}
|
||||
}
|
||||
|
||||
/*** Type Marking ***/
|
||||
|
||||
void
|
||||
@ -1018,14 +822,13 @@ TypeSet::MarkTypeRoot(JSTracer* trc, TypeSet::Type* v, const char* name)
|
||||
void
|
||||
TypeSet::MarkTypeUnbarriered(JSTracer* trc, TypeSet::Type* v, const char* name)
|
||||
{
|
||||
trc->setTracingName(name);
|
||||
if (v->isSingletonUnchecked()) {
|
||||
JSObject* obj = v->singleton();
|
||||
MarkInternal(trc, &obj);
|
||||
DispatchToTracer(trc, &obj, name);
|
||||
*v = TypeSet::ObjectType(obj);
|
||||
} else if (v->isGroupUnchecked()) {
|
||||
ObjectGroup* group = v->group();
|
||||
MarkInternal(trc, &group);
|
||||
DispatchToTracer(trc, &group, name);
|
||||
*v = TypeSet::ObjectType(group);
|
||||
}
|
||||
}
|
||||
@ -1035,10 +838,12 @@ TypeSet::MarkTypeUnbarriered(JSTracer* trc, TypeSet::Type* v, const char* name)
|
||||
void
|
||||
gc::MarkObjectSlots(JSTracer* trc, NativeObject* obj, uint32_t start, uint32_t nslots)
|
||||
{
|
||||
MOZ_ASSERT(obj->isNative());
|
||||
JS::AutoTracingIndex index(trc, start);
|
||||
for (uint32_t i = start; i < (start + nslots); ++i) {
|
||||
trc->setTracingDetails(GetObjectSlotName, obj, i);
|
||||
MarkValueInternal(trc, obj->getSlotRef(i).unsafeGet());
|
||||
HeapSlot& slot = obj->getSlotRef(i);
|
||||
if (InternalGCMethods<Value>::isMarkable(slot))
|
||||
DispatchToTracer(trc, slot.unsafeGet(), "object slot");
|
||||
++index;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1143,7 +948,7 @@ static inline void
|
||||
ScanBaseShape(GCMarker* gcmarker, BaseShape* base);
|
||||
|
||||
void
|
||||
BaseShape::markChildren(JSTracer* trc)
|
||||
BaseShape::traceChildren(JSTracer* trc)
|
||||
{
|
||||
if (isOwned())
|
||||
TraceEdge(trc, &unowned_, "base");
|
||||
@ -1413,40 +1218,40 @@ ScanObjectGroup(GCMarker* gcmarker, ObjectGroup* group)
|
||||
gcmarker->traverse(fun);
|
||||
}
|
||||
|
||||
static void
|
||||
gc::MarkChildren(JSTracer* trc, ObjectGroup* group)
|
||||
void
|
||||
js::ObjectGroup::traceChildren(JSTracer* trc)
|
||||
{
|
||||
unsigned count = group->getPropertyCount();
|
||||
unsigned count = getPropertyCount();
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
if (ObjectGroup::Property* prop = group->getProperty(i))
|
||||
if (ObjectGroup::Property* prop = getProperty(i))
|
||||
TraceEdge(trc, &prop->id, "group_property");
|
||||
}
|
||||
|
||||
if (group->proto().isObject())
|
||||
TraceEdge(trc, &group->protoRaw(), "group_proto");
|
||||
if (proto().isObject())
|
||||
TraceEdge(trc, &protoRaw(), "group_proto");
|
||||
|
||||
if (group->newScript())
|
||||
group->newScript()->trace(trc);
|
||||
if (newScript())
|
||||
newScript()->trace(trc);
|
||||
|
||||
if (group->maybePreliminaryObjects())
|
||||
group->maybePreliminaryObjects()->trace(trc);
|
||||
if (maybePreliminaryObjects())
|
||||
maybePreliminaryObjects()->trace(trc);
|
||||
|
||||
if (group->maybeUnboxedLayout())
|
||||
group->unboxedLayout().trace(trc);
|
||||
if (maybeUnboxedLayout())
|
||||
unboxedLayout().trace(trc);
|
||||
|
||||
if (ObjectGroup* unboxedGroup = group->maybeOriginalUnboxedGroup()) {
|
||||
if (ObjectGroup* unboxedGroup = maybeOriginalUnboxedGroup()) {
|
||||
TraceManuallyBarrieredEdge(trc, &unboxedGroup, "group_original_unboxed_group");
|
||||
group->setOriginalUnboxedGroup(unboxedGroup);
|
||||
setOriginalUnboxedGroup(unboxedGroup);
|
||||
}
|
||||
|
||||
if (JSObject* descr = group->maybeTypeDescr()) {
|
||||
if (JSObject* descr = maybeTypeDescr()) {
|
||||
TraceManuallyBarrieredEdge(trc, &descr, "group_type_descr");
|
||||
group->setTypeDescr(&descr->as<TypeDescr>());
|
||||
setTypeDescr(&descr->as<TypeDescr>());
|
||||
}
|
||||
|
||||
if (JSObject* fun = group->maybeInterpretedFunction()) {
|
||||
if (JSObject* fun = maybeInterpretedFunction()) {
|
||||
TraceManuallyBarrieredEdge(trc, &fun, "group_function");
|
||||
group->setInterpretedFunction(&fun->as<JSFunction>());
|
||||
setInterpretedFunction(&fun->as<JSFunction>());
|
||||
}
|
||||
}
|
||||
|
||||
@ -1625,7 +1430,7 @@ GCMarker::processMarkStackOther(uintptr_t tag, uintptr_t addr)
|
||||
else
|
||||
repush(obj);
|
||||
} else if (tag == JitCodeTag) {
|
||||
reinterpret_cast<jit::JitCode*>(addr)->trace(this);
|
||||
reinterpret_cast<jit::JitCode*>(addr)->traceChildren(this);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1888,54 +1693,24 @@ GCMarker::drainMarkStack(SliceBudget& budget)
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
GCMarker::markChildren(T* thing)
|
||||
GCMarker::dispatchToTraceChildren(T* thing)
|
||||
{
|
||||
thing->markChildren(this);
|
||||
thing->traceChildren(this);
|
||||
}
|
||||
|
||||
struct TraceChildrenFunctor {
|
||||
template <typename T>
|
||||
void operator()(JSTracer* trc, void* thing) {
|
||||
static_cast<T*>(thing)->traceChildren(trc);
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
js::TraceChildren(JSTracer* trc, void* thing, JSGCTraceKind kind)
|
||||
{
|
||||
switch (kind) {
|
||||
case JSTRACE_OBJECT:
|
||||
static_cast<JSObject*>(thing)->markChildren(trc);
|
||||
break;
|
||||
|
||||
case JSTRACE_SCRIPT:
|
||||
static_cast<JSScript*>(thing)->markChildren(trc);
|
||||
break;
|
||||
|
||||
case JSTRACE_STRING:
|
||||
static_cast<JSString*>(thing)->markChildren(trc);
|
||||
break;
|
||||
|
||||
case JSTRACE_SYMBOL:
|
||||
static_cast<JS::Symbol*>(thing)->markChildren(trc);
|
||||
break;
|
||||
|
||||
case JSTRACE_BASE_SHAPE:
|
||||
static_cast<BaseShape*>(thing)->markChildren(trc);
|
||||
break;
|
||||
|
||||
case JSTRACE_JITCODE:
|
||||
static_cast<jit::JitCode*>(thing)->trace(trc);
|
||||
break;
|
||||
|
||||
case JSTRACE_LAZY_SCRIPT:
|
||||
static_cast<LazyScript*>(thing)->markChildren(trc);
|
||||
break;
|
||||
|
||||
case JSTRACE_SHAPE:
|
||||
static_cast<Shape*>(thing)->markChildren(trc);
|
||||
break;
|
||||
|
||||
case JSTRACE_OBJECT_GROUP:
|
||||
MarkChildren(trc, (ObjectGroup*)thing);
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Invalid trace kind in TraceChildren.");
|
||||
}
|
||||
MOZ_ASSERT(thing);
|
||||
TraceChildrenFunctor f;
|
||||
CallTyped(f, kind, trc, thing);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -77,14 +77,6 @@ IsNullTaggedPointer(void* p)
|
||||
|
||||
/*** Externally Typed Marking ***/
|
||||
|
||||
/*
|
||||
* Note: this must only be called by the GC and only when we are tracing through
|
||||
* MarkRoots. It is explicitly for ConservativeStackMarking and should go away
|
||||
* after we transition to exact rooting.
|
||||
*/
|
||||
void
|
||||
MarkKind(JSTracer* trc, void** thingp, JSGCTraceKind kind);
|
||||
|
||||
void
|
||||
TraceGenericPointerRoot(JSTracer* trc, Cell** thingp, const char* name);
|
||||
|
||||
@ -167,7 +159,7 @@ class HashKeyRef : public BufferableRef
|
||||
typename Map::Ptr p = map->lookup(key);
|
||||
if (!p)
|
||||
return;
|
||||
trc->setTracingLocation(&*p);
|
||||
JS::AutoOriginalTraceLocation reloc(trc, (void**)&*p);
|
||||
TraceManuallyBarrieredEdge(trc, &key, "HashKeyRef");
|
||||
map->rekeyIfMoved(prior, key);
|
||||
}
|
||||
|
@ -221,8 +221,8 @@ AutoGCRooter::trace(JSTracer* trc)
|
||||
AutoObjectObjectHashMap::HashMapImpl& map = static_cast<AutoObjectObjectHashMap*>(this)->map;
|
||||
for (AutoObjectObjectHashMap::Enum e(map); !e.empty(); e.popFront()) {
|
||||
TraceRoot(trc, &e.front().value(), "AutoObjectObjectHashMap value");
|
||||
trc->setTracingLocation((void*)&e.front().key());
|
||||
JSObject* key = e.front().key();
|
||||
JS::AutoOriginalTraceLocation reloc(trc, &e.front().key());
|
||||
TraceRoot(trc, &key, "AutoObjectObjectHashMap key");
|
||||
if (key != e.front().key())
|
||||
e.rekeyFront(key);
|
||||
@ -583,21 +583,14 @@ struct SetMaybeAliveFunctor {
|
||||
};
|
||||
|
||||
void
|
||||
BufferGrayRootsTracer::appendGrayRoot(Cell* thing, JSGCTraceKind kind)
|
||||
BufferGrayRootsTracer::appendGrayRoot(TenuredCell* thing, JSGCTraceKind kind)
|
||||
{
|
||||
MOZ_ASSERT(runtime()->isHeapBusy());
|
||||
|
||||
if (bufferingGrayRootsFailed)
|
||||
return;
|
||||
|
||||
GrayRoot root(thing, kind);
|
||||
#ifdef DEBUG
|
||||
root.debugPrinter = debugPrinter();
|
||||
root.debugPrintArg = debugPrintArg();
|
||||
root.debugPrintIndex = debugPrintIndex();
|
||||
#endif
|
||||
|
||||
Zone* zone = TenuredCell::fromPointer(thing)->zone();
|
||||
Zone* zone = thing->zone();
|
||||
if (zone->isCollecting()) {
|
||||
// See the comment on SetMaybeAliveFlag to see why we only do this for
|
||||
// objects and scripts. We rely on gray root buffering for this to work,
|
||||
@ -605,7 +598,7 @@ BufferGrayRootsTracer::appendGrayRoot(Cell* thing, JSGCTraceKind kind)
|
||||
// incremental GCs (when we do gray root buffering).
|
||||
CallTyped(SetMaybeAliveFunctor(), kind, thing);
|
||||
|
||||
if (!zone->gcGrayRoots.append(root))
|
||||
if (!zone->gcGrayRoots.append(thing))
|
||||
bufferingGrayRootsFailed = true;
|
||||
}
|
||||
}
|
||||
@ -616,13 +609,8 @@ GCRuntime::markBufferedGrayRoots(JS::Zone* zone)
|
||||
MOZ_ASSERT(grayBufferState == GrayBufferState::Okay);
|
||||
MOZ_ASSERT(zone->isGCMarkingGray() || zone->isGCCompacting());
|
||||
|
||||
for (GrayRoot* elem = zone->gcGrayRoots.begin(); elem != zone->gcGrayRoots.end(); elem++) {
|
||||
#ifdef DEBUG
|
||||
marker.setTracingDetails(elem->debugPrinter, elem->debugPrintArg, elem->debugPrintIndex);
|
||||
#endif
|
||||
TraceManuallyBarrieredGenericPointerEdge(&marker, reinterpret_cast<Cell**>(&elem->thing),
|
||||
"buffered gray root");
|
||||
}
|
||||
for (auto cell : zone->gcGrayRoots)
|
||||
TraceManuallyBarrieredGenericPointerEdge(&marker, &cell, "buffered gray root");
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -55,11 +55,11 @@ StoreBuffer::WholeCellEdges::mark(JSTracer* trc) const
|
||||
JSObject* object = static_cast<JSObject*>(edge);
|
||||
if (object->is<ArgumentsObject>())
|
||||
ArgumentsObject::trace(trc, object);
|
||||
object->markChildren(trc);
|
||||
object->traceChildren(trc);
|
||||
return;
|
||||
}
|
||||
MOZ_ASSERT(kind == JSTRACE_JITCODE);
|
||||
static_cast<jit::JitCode*>(edge)->trace(trc);
|
||||
static_cast<jit::JitCode*>(edge)->traceChildren(trc);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -29,6 +29,63 @@ using namespace js;
|
||||
using namespace js::gc;
|
||||
using mozilla::DebugOnly;
|
||||
|
||||
template <typename T>
|
||||
void
|
||||
DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name)
|
||||
{
|
||||
JSGCTraceKind kind = MapTypeToTraceKind<typename mozilla::RemovePointer<T>::Type>::kind;
|
||||
JS::AutoTracingName ctx(trc, name);
|
||||
trc->invoke((void**)thingp, kind);
|
||||
}
|
||||
#define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(name, type) \
|
||||
template void DoCallback<type*>(JS::CallbackTracer*, type**, const char*);
|
||||
FOR_EACH_GC_LAYOUT(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS);
|
||||
#undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS
|
||||
|
||||
template <>
|
||||
void
|
||||
DoCallback<Value>(JS::CallbackTracer* trc, Value* vp, const char* name)
|
||||
{
|
||||
if (vp->isObject()) {
|
||||
JSObject* prior = &vp->toObject();
|
||||
JSObject* obj = prior;
|
||||
DoCallback(trc, &obj, name);
|
||||
if (obj != prior)
|
||||
vp->setObjectOrNull(obj);
|
||||
} else if (vp->isString()) {
|
||||
JSString* prior = vp->toString();
|
||||
JSString* str = prior;
|
||||
DoCallback(trc, &str, name);
|
||||
if (str != prior)
|
||||
vp->setString(str);
|
||||
} else if (vp->isSymbol()) {
|
||||
JS::Symbol* prior = vp->toSymbol();
|
||||
JS::Symbol* sym = prior;
|
||||
DoCallback(trc, &sym, name);
|
||||
if (sym != prior)
|
||||
vp->setSymbol(sym);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void
|
||||
DoCallback<jsid>(JS::CallbackTracer* trc, jsid* idp, const char* name)
|
||||
{
|
||||
if (JSID_IS_STRING(*idp)) {
|
||||
JSString* prior = JSID_TO_STRING(*idp);
|
||||
JSString* str = prior;
|
||||
DoCallback(trc, &str, name);
|
||||
if (str != prior)
|
||||
*idp = NON_INTEGER_ATOM_TO_JSID(reinterpret_cast<JSAtom*>(str));
|
||||
} else if (JSID_IS_SYMBOL(*idp)) {
|
||||
JS::Symbol* prior = JSID_TO_SYMBOL(*idp);
|
||||
JS::Symbol* sym = prior;
|
||||
DoCallback(trc, &sym, name);
|
||||
if (sym != prior)
|
||||
*idp = SYMBOL_TO_JSID(sym);
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_CallUnbarrieredValueTracer(JSTracer* trc, Value* valuep, const char* name)
|
||||
{
|
||||
@ -102,7 +159,7 @@ JS_CallTenuredObjectTracer(JSTracer* trc, JS::TenuredHeap<JSObject*>* objp, cons
|
||||
if (!obj)
|
||||
return;
|
||||
|
||||
trc->setTracingLocation((void*)objp);
|
||||
JS::AutoOriginalTraceLocation reloc(trc, (void**)objp);
|
||||
TraceManuallyBarrieredEdge(trc, &obj, name);
|
||||
|
||||
objp->setPtr(obj);
|
||||
@ -329,61 +386,22 @@ JSTracer::JSTracer(JSRuntime* rt, TracerKindTag kindTag,
|
||||
WeakMapTraceKind weakTraceKind /* = TraceWeakMapValues */)
|
||||
: runtime_(rt)
|
||||
, tag(kindTag)
|
||||
, debugPrinter_(nullptr)
|
||||
, debugPrintArg_(nullptr)
|
||||
, debugPrintIndex_(size_t(-1))
|
||||
, eagerlyTraceWeakMaps_(weakTraceKind)
|
||||
#ifdef JS_GC_ZEAL
|
||||
, realLocation_(nullptr)
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
JSTracer::hasTracingDetails() const
|
||||
{
|
||||
return debugPrinter_ || debugPrintArg_;
|
||||
}
|
||||
|
||||
const char*
|
||||
JSTracer::tracingName(const char* fallback) const
|
||||
JS::CallbackTracer::getTracingEdgeName(char* buffer, size_t bufferSize)
|
||||
{
|
||||
MOZ_ASSERT(hasTracingDetails());
|
||||
return debugPrinter_ ? fallback : (const char*)debugPrintArg_;
|
||||
}
|
||||
|
||||
const char*
|
||||
JSTracer::getTracingEdgeName(char* buffer, size_t bufferSize)
|
||||
{
|
||||
if (debugPrinter_) {
|
||||
debugPrinter_(this, buffer, bufferSize);
|
||||
if (contextFunctor_) {
|
||||
(*contextFunctor_)(this, buffer, bufferSize);
|
||||
return buffer;
|
||||
}
|
||||
if (debugPrintIndex_ != size_t(-1)) {
|
||||
JS_snprintf(buffer, bufferSize, "%s[%lu]",
|
||||
(const char*)debugPrintArg_,
|
||||
debugPrintIndex_);
|
||||
if (contextIndex_ != InvalidIndex) {
|
||||
JS_snprintf(buffer, bufferSize, "%s[%lu]", contextName_, contextIndex_);
|
||||
return buffer;
|
||||
}
|
||||
return (const char*)debugPrintArg_;
|
||||
}
|
||||
|
||||
JSTraceNamePrinter
|
||||
JSTracer::debugPrinter() const
|
||||
{
|
||||
return debugPrinter_;
|
||||
}
|
||||
|
||||
const void*
|
||||
JSTracer::debugPrintArg() const
|
||||
{
|
||||
return debugPrintArg_;
|
||||
}
|
||||
|
||||
size_t
|
||||
JSTracer::debugPrintIndex() const
|
||||
{
|
||||
return debugPrintIndex_;
|
||||
return contextName_;
|
||||
}
|
||||
|
||||
void
|
||||
@ -392,27 +410,6 @@ JS::CallbackTracer::setTraceCallback(JSTraceCallback traceCallback)
|
||||
callback = traceCallback;
|
||||
}
|
||||
|
||||
#ifdef JS_GC_ZEAL
|
||||
void
|
||||
JSTracer::setTracingLocation(void* location)
|
||||
{
|
||||
if (!realLocation_ || !location)
|
||||
realLocation_ = location;
|
||||
}
|
||||
|
||||
void
|
||||
JSTracer::unsetTracingLocation()
|
||||
{
|
||||
realLocation_ = nullptr;
|
||||
}
|
||||
|
||||
void**
|
||||
JSTracer::tracingLocation(void** thingp)
|
||||
{
|
||||
return realLocation_ ? (void**)realLocation_ : thingp;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool
|
||||
MarkStack::init(JSGCMode gcMode)
|
||||
{
|
||||
|
@ -253,11 +253,12 @@ class GCMarker : public JSTracer
|
||||
template <typename T>
|
||||
void markAndTraverse(T* thing) {
|
||||
if (mark(thing))
|
||||
markChildren(thing);
|
||||
dispatchToTraceChildren(thing);
|
||||
}
|
||||
|
||||
// We may not have concrete types yet, so this has to be out of the header.
|
||||
template <typename T>
|
||||
void markChildren(T* thing);
|
||||
void dispatchToTraceChildren(T* thing);
|
||||
|
||||
// Mark the given GC thing, but do not trace its children. Return true
|
||||
// if the thing became marked.
|
||||
@ -304,8 +305,6 @@ class GCMarker : public JSTracer
|
||||
void markAndScanString(JSObject* source, JSString* str);
|
||||
void markAndScanSymbol(JSObject* source, JS::Symbol* sym);
|
||||
|
||||
void appendGrayRoot(void* thing, JSGCTraceKind kind);
|
||||
|
||||
/* The color is only applied to objects and functions. */
|
||||
uint32_t color;
|
||||
|
||||
@ -332,7 +331,7 @@ class BufferGrayRootsTracer : public JS::CallbackTracer
|
||||
// Set to false if we OOM while buffering gray roots.
|
||||
bool bufferingGrayRootsFailed;
|
||||
|
||||
void appendGrayRoot(gc::Cell* thing, JSGCTraceKind kind);
|
||||
void appendGrayRoot(gc::TenuredCell* thing, JSGCTraceKind kind);
|
||||
|
||||
public:
|
||||
explicit BufferGrayRootsTracer(JSRuntime* rt)
|
||||
@ -340,8 +339,8 @@ class BufferGrayRootsTracer : public JS::CallbackTracer
|
||||
{}
|
||||
|
||||
static void grayTraceCallback(JS::CallbackTracer* trc, void** thingp, JSGCTraceKind kind) {
|
||||
static_cast<BufferGrayRootsTracer*>(trc)->appendGrayRoot(static_cast<gc::Cell*>(*thingp),
|
||||
kind);
|
||||
auto tracer = static_cast<BufferGrayRootsTracer*>(trc);
|
||||
tracer->appendGrayRoot(gc::TenuredCell::fromPointer(*thingp), kind);
|
||||
}
|
||||
|
||||
bool failed() const { return bufferingGrayRootsFailed; }
|
||||
|
@ -133,7 +133,7 @@ AccumulateEdge(JS::CallbackTracer* jstrc, void** thingp, JSGCTraceKind kind)
|
||||
|
||||
node->edges[i].thing = *thingp;
|
||||
node->edges[i].kind = kind;
|
||||
node->edges[i].label = trc->tracingName("<unknown>");
|
||||
node->edges[i].label = trc->contextName();
|
||||
node->count++;
|
||||
}
|
||||
|
||||
@ -312,9 +312,7 @@ AssertMarkedOrAllocated(const EdgeValue& edge)
|
||||
return;
|
||||
|
||||
char msgbuf[1024];
|
||||
const char* label = edge.label;
|
||||
|
||||
JS_snprintf(msgbuf, sizeof(msgbuf), "[barrier verifier] Unmarked edge: %s", label);
|
||||
JS_snprintf(msgbuf, sizeof(msgbuf), "[barrier verifier] Unmarked edge: %s", edge.label);
|
||||
MOZ_ReportAssertionFailure(msgbuf, __FILE__, __LINE__);
|
||||
MOZ_CRASH();
|
||||
}
|
||||
@ -389,7 +387,7 @@ struct VerifyPostTracer : JS::CallbackTracer
|
||||
int count;
|
||||
|
||||
/* The set of edges in the StoreBuffer at the end of verification. */
|
||||
typedef HashSet<void**, PointerHasher<void**, 3>, SystemAllocPolicy> EdgeSet;
|
||||
typedef HashSet<void*const*, PointerHasher<void*const*, 3>, SystemAllocPolicy> EdgeSet;
|
||||
EdgeSet* edges;
|
||||
|
||||
VerifyPostTracer(JSRuntime* rt, JSTraceCallback callback)
|
||||
@ -438,13 +436,13 @@ PostVerifierCollectStoreBufferEdges(JS::CallbackTracer* jstrc, void** thingp, JS
|
||||
* only things that enter this callback are marked by the store buffer. The
|
||||
* store buffer ensures that the real tracing location is set correctly.
|
||||
*/
|
||||
void** loc = trc->tracingLocation(thingp);
|
||||
void*const* loc = trc->tracingLocation(thingp);
|
||||
|
||||
trc->edges->put(loc);
|
||||
}
|
||||
|
||||
static void
|
||||
AssertStoreBufferContainsEdge(VerifyPostTracer::EdgeSet* edges, void** loc, JSObject* dst)
|
||||
AssertStoreBufferContainsEdge(VerifyPostTracer::EdgeSet* edges, void*const* loc, JSObject* dst)
|
||||
{
|
||||
if (edges->has(loc))
|
||||
return;
|
||||
@ -477,7 +475,7 @@ PostVerifierVisitEdge(JS::CallbackTracer* jstrc, void** thingp, JSGCTraceKind ki
|
||||
* below. Since JSObject::markChildren handles this, the real trace
|
||||
* location will be set correctly in these cases.
|
||||
*/
|
||||
void** loc = trc->tracingLocation(thingp);
|
||||
void*const* loc = trc->tracingLocation(thingp);
|
||||
|
||||
AssertStoreBufferContainsEdge(trc->edges, loc, dst);
|
||||
}
|
||||
|
@ -248,7 +248,7 @@ struct Zone : public JS::shadow::Zone,
|
||||
CompartmentVector compartments;
|
||||
|
||||
// This compartment's gray roots.
|
||||
typedef js::Vector<js::GrayRoot, 0, js::SystemAllocPolicy> GrayRootVector;
|
||||
typedef js::Vector<js::gc::Cell*, 0, js::SystemAllocPolicy> GrayRootVector;
|
||||
GrayRootVector gcGrayRoots;
|
||||
|
||||
// A set of edges from this zone to other zones.
|
||||
|
@ -639,7 +639,7 @@ JitCode::copyFrom(MacroAssembler& masm)
|
||||
}
|
||||
|
||||
void
|
||||
JitCode::trace(JSTracer* trc)
|
||||
JitCode::traceChildren(JSTracer* trc)
|
||||
{
|
||||
// Note that we cannot mark invalidated scripts, since we've basically
|
||||
// corrupted the code stream by injecting bailouts.
|
||||
@ -2610,7 +2610,7 @@ InvalidateActivation(FreeOp* fop, const JitActivationIterator& activations, bool
|
||||
// embedded in the JitCode. Perform one final trace of the
|
||||
// JitCode for the incremental GC, as it must know about
|
||||
// those edges.
|
||||
ionCode->trace(zone->barrierTracer());
|
||||
ionCode->traceChildren(zone->barrierTracer());
|
||||
}
|
||||
ionCode->setInvalidated();
|
||||
|
||||
|
@ -107,7 +107,7 @@ class JitCode : public gc::TenuredCell
|
||||
size_t instructionsSize() const {
|
||||
return insnSize_;
|
||||
}
|
||||
void trace(JSTracer* trc);
|
||||
void traceChildren(JSTracer* trc);
|
||||
void finalize(FreeOp* fop);
|
||||
void fixupAfterMovingGC() {}
|
||||
void setInvalidated() {
|
||||
|
@ -5059,6 +5059,7 @@ enum AsmJSCacheResult
|
||||
AsmJSCache_ModuleTooSmall,
|
||||
AsmJSCache_SynchronousScript,
|
||||
AsmJSCache_QuotaExceeded,
|
||||
AsmJSCache_StorageInitFailure,
|
||||
AsmJSCache_Disabled_Internal,
|
||||
AsmJSCache_Disabled_ShellFlags,
|
||||
AsmJSCache_Disabled_JitInspector,
|
||||
|
@ -86,7 +86,7 @@ js::TraceCycleDetectionSet(JSTracer* trc, js::ObjectSet& set)
|
||||
{
|
||||
for (js::ObjectSet::Enum e(set); !e.empty(); e.popFront()) {
|
||||
JSObject* key = e.front();
|
||||
trc->setTracingLocation((void*)&e.front());
|
||||
JS::AutoOriginalTraceLocation reloc(trc, &e.front());
|
||||
TraceRoot(trc, &key, "cycle detector table entry");
|
||||
if (key != e.front())
|
||||
e.rekeyFront(key);
|
||||
|
@ -23,6 +23,18 @@
|
||||
|
||||
#include "vm/NativeObject.h"
|
||||
|
||||
#define FOR_EACH_GC_LAYOUT(D) \
|
||||
D(Object, JSObject) \
|
||||
D(String, JSString) \
|
||||
D(Symbol, JS::Symbol) \
|
||||
D(Script, JSScript) \
|
||||
D(AccessorShape, js::AccessorShape) \
|
||||
D(Shape, js::Shape) \
|
||||
D(BaseShape, js::BaseShape) \
|
||||
D(JitCode, js::jit::JitCode) \
|
||||
D(LazyScript, js::LazyScript) \
|
||||
D(ObjectGroup, js::ObjectGroup)
|
||||
|
||||
namespace js {
|
||||
|
||||
unsigned GetCPUCount();
|
||||
@ -1089,19 +1101,6 @@ struct GCChunkHasher {
|
||||
|
||||
typedef HashSet<js::gc::Chunk*, GCChunkHasher, SystemAllocPolicy> GCChunkSet;
|
||||
|
||||
struct GrayRoot {
|
||||
void* thing;
|
||||
JSGCTraceKind kind;
|
||||
#ifdef DEBUG
|
||||
JSTraceNamePrinter debugPrinter;
|
||||
const void* debugPrintArg;
|
||||
size_t debugPrintIndex;
|
||||
#endif
|
||||
|
||||
GrayRoot(void* thing, JSGCTraceKind kind)
|
||||
: thing(thing), kind(kind) {}
|
||||
};
|
||||
|
||||
typedef void (*IterateChunkCallback)(JSRuntime* rt, void* data, gc::Chunk* chunk);
|
||||
typedef void (*IterateZoneCallback)(JSRuntime* rt, void* data, JS::Zone* zone);
|
||||
typedef void (*IterateArenaCallback)(JSRuntime* rt, void* data, gc::Arena* arena,
|
||||
|
@ -2165,8 +2165,8 @@ JSObject::swap(JSContext* cx, HandleObject a, HandleObject b)
|
||||
*/
|
||||
JS::Zone* zone = a->zone();
|
||||
if (zone->needsIncrementalBarrier()) {
|
||||
a->markChildren(zone->barrierTracer());
|
||||
b->markChildren(zone->barrierTracer());
|
||||
a->traceChildren(zone->barrierTracer());
|
||||
b->traceChildren(zone->barrierTracer());
|
||||
}
|
||||
|
||||
NotifyGCPostSwap(a, b, r);
|
||||
@ -3490,13 +3490,21 @@ js::ToObjectSlow(JSContext* cx, JS::HandleValue val, bool reportScanStack)
|
||||
return PrimitiveToObject(cx, val);
|
||||
}
|
||||
|
||||
void
|
||||
js::GetObjectSlotName(JSTracer* trc, char* buf, size_t bufsize)
|
||||
class GetObjectSlotNameFunctor : public JS::CallbackTracer::ContextFunctor
|
||||
{
|
||||
MOZ_ASSERT(trc->debugPrinter() == GetObjectSlotName);
|
||||
JSObject* obj;
|
||||
|
||||
JSObject* obj = (JSObject*)trc->debugPrintArg();
|
||||
uint32_t slot = uint32_t(trc->debugPrintIndex());
|
||||
public:
|
||||
explicit GetObjectSlotNameFunctor(JSObject* ctx) : obj(ctx) {}
|
||||
virtual void operator()(JS::CallbackTracer* trc, char* buf, size_t bufsize) override;
|
||||
};
|
||||
|
||||
void
|
||||
GetObjectSlotNameFunctor::operator()(JS::CallbackTracer* trc, char* buf, size_t bufsize)
|
||||
{
|
||||
MOZ_ASSERT(trc->contextIndex() != JS::CallbackTracer::InvalidIndex);
|
||||
|
||||
uint32_t slot = uint32_t(trc->contextIndex());
|
||||
|
||||
Shape* shape;
|
||||
if (obj->isNative()) {
|
||||
@ -4056,7 +4064,7 @@ template<> const char16_t JS::ubi::TracerConcrete<JSObject>::concreteTypeName[]
|
||||
MOZ_UTF16("JSObject");
|
||||
|
||||
void
|
||||
JSObject::markChildren(JSTracer* trc)
|
||||
JSObject::traceChildren(JSTracer* trc)
|
||||
{
|
||||
TraceEdge(trc, &group_, "group");
|
||||
|
||||
@ -4069,7 +4077,11 @@ JSObject::markChildren(JSTracer* trc)
|
||||
|
||||
TraceEdge(trc, &nobj->shape_, "shape");
|
||||
|
||||
MarkObjectSlots(trc, nobj, 0, nobj->slotSpan());
|
||||
{
|
||||
GetObjectSlotNameFunctor func(nobj);
|
||||
JS::AutoTracingDetails ctx(trc, func);
|
||||
MarkObjectSlots(trc, nobj, 0, nobj->slotSpan());
|
||||
}
|
||||
|
||||
do {
|
||||
if (nobj->denseElementsAreCopyOnWrite()) {
|
||||
|
@ -263,7 +263,7 @@ class JSObject : public js::gc::Cell
|
||||
|
||||
/* GC support. */
|
||||
|
||||
void markChildren(JSTracer* trc);
|
||||
void traceChildren(JSTracer* trc);
|
||||
|
||||
void fixupAfterMovingGC();
|
||||
|
||||
@ -1258,9 +1258,6 @@ XDRObjectLiteral(XDRState<mode>* xdr, MutableHandleObject obj);
|
||||
extern JSObject*
|
||||
CloneObjectLiteral(JSContext* cx, HandleObject srcObj);
|
||||
|
||||
extern void
|
||||
GetObjectSlotName(JSTracer* trc, char* buf, size_t bufsize);
|
||||
|
||||
extern bool
|
||||
ReportGetterOnlyAssignment(JSContext* cx, bool strict);
|
||||
|
||||
|
@ -3423,7 +3423,7 @@ JSScript::hasBreakpointsAt(jsbytecode* pc)
|
||||
}
|
||||
|
||||
void
|
||||
JSScript::markChildren(JSTracer* trc)
|
||||
JSScript::traceChildren(JSTracer* trc)
|
||||
{
|
||||
// NOTE: this JSScript may be partially initialized at this point. E.g. we
|
||||
// may have created it and partially initialized it with
|
||||
@ -3481,7 +3481,7 @@ JSScript::markChildren(JSTracer* trc)
|
||||
}
|
||||
|
||||
void
|
||||
LazyScript::markChildren(JSTracer* trc)
|
||||
LazyScript::traceChildren(JSTracer* trc)
|
||||
{
|
||||
if (function_)
|
||||
TraceEdge(trc, &function_, "function");
|
||||
|
@ -1717,7 +1717,7 @@ class JSScript : public js::gc::TenuredCell
|
||||
|
||||
static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SCRIPT; }
|
||||
|
||||
void markChildren(JSTracer* trc);
|
||||
void traceChildren(JSTracer* trc);
|
||||
|
||||
// A helper class to prevent relazification of the given function's script
|
||||
// while it's holding on to it. This class automatically roots the script.
|
||||
@ -2133,7 +2133,7 @@ class LazyScript : public gc::TenuredCell
|
||||
bool hasUncompiledEnclosingScript() const;
|
||||
uint32_t staticLevel(JSContext* cx) const;
|
||||
|
||||
void markChildren(JSTracer* trc);
|
||||
void traceChildren(JSTracer* trc);
|
||||
void finalize(js::FreeOp* fop);
|
||||
void fixupAfterMovingGC() {}
|
||||
|
||||
|
@ -416,7 +416,7 @@ class ObjectGroupCompartment::NewTableRef : public gc::BufferableRef
|
||||
|
||||
void mark(JSTracer* trc) {
|
||||
JSObject* prior = proto;
|
||||
trc->setTracingLocation(&*prior);
|
||||
JS::AutoOriginalTraceLocation reloc(trc, &proto);
|
||||
TraceManuallyBarrieredEdge(trc, &proto, "newObjectGroups set prototype");
|
||||
if (prior == proto)
|
||||
return;
|
||||
|
@ -540,6 +540,7 @@ class ObjectGroup : public gc::TenuredCell
|
||||
|
||||
inline void clearProperties();
|
||||
void maybeSweep(AutoClearTypeInferenceStateOnOOM* oom);
|
||||
void traceChildren(JSTracer *trc);
|
||||
|
||||
private:
|
||||
#ifdef DEBUG
|
||||
|
@ -457,7 +457,7 @@ class BaseShape : public gc::TenuredCell
|
||||
|
||||
static inline ThingRootKind rootKind() { return THING_ROOT_BASE_SHAPE; }
|
||||
|
||||
void markChildren(JSTracer* trc);
|
||||
void traceChildren(JSTracer* trc);
|
||||
|
||||
void fixupAfterMovingGC() {}
|
||||
|
||||
@ -965,7 +965,7 @@ class Shape : public gc::TenuredCell
|
||||
|
||||
static inline ThingRootKind rootKind() { return THING_ROOT_SHAPE; }
|
||||
|
||||
inline void markChildren(JSTracer* trc);
|
||||
inline void traceChildren(JSTracer* trc);
|
||||
|
||||
inline Shape* search(ExclusiveContext* cx, jsid id);
|
||||
inline Shape* searchLinear(jsid id);
|
||||
@ -1352,7 +1352,7 @@ Shape::searchLinear(jsid id)
|
||||
}
|
||||
|
||||
inline void
|
||||
Shape::markChildren(JSTracer* trc)
|
||||
Shape::traceChildren(JSTracer* trc)
|
||||
{
|
||||
TraceEdge(trc, &base_, "base");
|
||||
TraceEdge(trc, &propidRef(), "propid");
|
||||
|
@ -466,7 +466,7 @@ class JSString : public js::gc::TenuredCell
|
||||
|
||||
inline JSLinearString* base() const;
|
||||
|
||||
void markBase(JSTracer* trc) {
|
||||
void traceBase(JSTracer* trc) {
|
||||
MOZ_ASSERT(hasBase());
|
||||
js::TraceManuallyBarrieredEdge(trc, &d.s.u3.base, "base");
|
||||
}
|
||||
@ -509,7 +509,7 @@ class JSString : public js::gc::TenuredCell
|
||||
bool equals(const char* s);
|
||||
#endif
|
||||
|
||||
inline void markChildren(JSTracer* trc);
|
||||
inline void traceChildren(JSTracer* trc);
|
||||
|
||||
static MOZ_ALWAYS_INLINE void readBarrier(JSString* thing) {
|
||||
if (thing->isPermanentAtom())
|
||||
@ -578,7 +578,7 @@ class JSRope : public JSString
|
||||
return d.s.u3.right;
|
||||
}
|
||||
|
||||
void markChildren(JSTracer* trc) {
|
||||
void traceChildren(JSTracer* trc) {
|
||||
js::TraceManuallyBarrieredEdge(trc, &d.s.u2.left, "left child");
|
||||
js::TraceManuallyBarrieredEdge(trc, &d.s.u3.right, "right child");
|
||||
}
|
||||
@ -1273,12 +1273,12 @@ JSString::base() const
|
||||
}
|
||||
|
||||
inline void
|
||||
JSString::markChildren(JSTracer* trc)
|
||||
JSString::traceChildren(JSTracer* trc)
|
||||
{
|
||||
if (hasBase())
|
||||
markBase(trc);
|
||||
traceBase(trc);
|
||||
else if (isRope())
|
||||
asRope().markChildren(trc);
|
||||
asRope().traceChildren(trc);
|
||||
}
|
||||
|
||||
template<>
|
||||
|
@ -56,7 +56,7 @@ class Symbol : public js::gc::TenuredCell
|
||||
bool isWellKnownSymbol() const { return uint32_t(code_) < WellKnownSymbolLimit; }
|
||||
|
||||
static inline js::ThingRootKind rootKind() { return js::THING_ROOT_SYMBOL; }
|
||||
inline void markChildren(JSTracer* trc) {
|
||||
inline void traceChildren(JSTracer* trc) {
|
||||
if (description_)
|
||||
js::TraceManuallyBarrieredEdge(trc, &description_, "description");
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user