diff --git a/accessible/base/NotificationController.cpp b/accessible/base/NotificationController.cpp index ec7d7cd46c..77f161048c 100644 --- a/accessible/base/NotificationController.cpp +++ b/accessible/base/NotificationController.cpp @@ -141,6 +141,7 @@ NotificationController::IsUpdatePending() void NotificationController::WillRefresh(mozilla::TimeStamp aTime) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); Telemetry::AutoTimer updateTimer; // If the document accessible that notification collector was created for is diff --git a/configure.in b/configure.in index d828cd720c..5a9338f616 100644 --- a/configure.in +++ b/configure.in @@ -4722,6 +4722,21 @@ then fi AC_SUBST(MOZ_ENABLE_DBUS) +dnl ======================================================== +dnl = speech-dispatcher support +dnl ======================================================== + +if test "$MOZ_ENABLE_GTK" -o "$MOZ_ENABLE_QT" +then + MOZ_SYNTH_SPEECHD=1 + + MOZ_ARG_DISABLE_BOOL(synth-speechd, + [ --disable-synth-speechd Disable speech-dispatcher support ], + MOZ_SYNTH_SPEECHD=, + MOZ_SYNTH_SPEECHD=1) +fi +AC_SUBST(MOZ_SYNTH_SPEECHD) + dnl ======================================================== dnl = Enable Android History instead of Places dnl ======================================================== diff --git a/docshell/test/chrome/test_bug565388.xul b/docshell/test/chrome/test_bug565388.xul index 8cf1bbb80b..47b5c07e4e 100644 --- a/docshell/test/chrome/test_bug565388.xul +++ b/docshell/test/chrome/test_bug565388.xul @@ -55,9 +55,10 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=565388 var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"]. createInstance(Ci.nsIPrincipal); - var docShell = Cc["@mozilla.org/appshell/appShellService;1"]. + var webNav = Cc["@mozilla.org/appshell/appShellService;1"]. getService(Ci.nsIAppShellService). - createWindowlessBrowser(true). + createWindowlessBrowser(true); + var docShell = webNav. QueryInterface(Ci.nsIInterfaceRequestor). getInterface(Ci.nsIDocShell); docShell.createAboutBlankContentViewer(systemPrincipal); @@ -65,6 +66,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=565388 progressListener.add(docShell, function(){ is(win.document.documentURI, "data:application/vnd.mozilla.xul+xml;charset=utf-8,"); + webNav.close(); SimpleTest.finish(); }); diff --git a/docshell/test/chrome/test_bug846906.xul b/docshell/test/chrome/test_bug846906.xul index 066c75224e..2003384f0b 100644 --- a/docshell/test/chrome/test_bug846906.xul +++ b/docshell/test/chrome/test_bug846906.xul @@ -21,15 +21,21 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=846906 .getService(Components.interfaces.nsIAppShellService); ok(appShellService, "Should be able to get app shell service"); - var webNavigation = appShellService.createWindowlessBrowser(); - ok(webNavigation, "Should be able to create windowless browser"); + var windowlessBrowser = appShellService.createWindowlessBrowser(); + ok(windowlessBrowser, "Should be able to create windowless browser"); - var interfaceRequestor = webNavigation.QueryInterface(Components.interfaces.nsIInterfaceRequestor); + ok(windowlessBrowser instanceof Components.interfaces.nsIWindowlessBrowser, + "Windowless browser should implement nsIWindowlessBrowser"); + + var webNavigation = windowlessBrowser.QueryInterface(Components.interfaces.nsIWebNavigation); + ok(webNavigation, "Windowless browser should implement nsIWebNavigation"); + + var interfaceRequestor = windowlessBrowser.QueryInterface(Components.interfaces.nsIInterfaceRequestor); ok(interfaceRequestor, "Should be able to query interface requestor interface"); var docShell = interfaceRequestor.getInterface(Components.interfaces.nsIDocShell); ok(docShell, "Should be able to get doc shell interface"); - + var document = webNavigation.document; ok(document, "Should be able to get document"); @@ -55,12 +61,30 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=846906 is(rect.width, 1024); is(rect.height, 768); + windowlessBrowser.close(); + + // Once the browser is closed, nsIWebNavigation and + // nsIInterfaceRequestor methods should no longer be accessible. + try { + windowlessBrowser.getInterface(Components.interfaces.nsIDocShell); + ok(false); + } catch (e) { + is(e.result, Components.results.NS_ERROR_NULL_POINTER); + } + + try { + windowlessBrowser.document; + ok(false); + } catch (e) { + is(e.result, Components.results.NS_ERROR_NULL_POINTER); + } + SimpleTest.finish(); }; iframe.setAttribute("src", "http://mochi.test:8888/chrome/docshell/test/chrome/bug846906.html"); }; document.documentElement.appendChild(iframe); - + ]]> diff --git a/dom/archivereader/ArchiveZipEvent.cpp b/dom/archivereader/ArchiveZipEvent.cpp index 31bd85cd14..56251eef66 100644 --- a/dom/archivereader/ArchiveZipEvent.cpp +++ b/dom/archivereader/ArchiveZipEvent.cpp @@ -10,6 +10,9 @@ #include "nsContentUtils.h" #include "nsCExternalHandlerService.h" +#include "mozilla/UniquePtr.h" + +using namespace mozilla; using namespace mozilla::dom; USING_ARCHIVEREADER_NAMESPACE @@ -191,8 +194,8 @@ ArchiveReaderZipEvent::Exec() } // Read the name: - nsAutoArrayPtr filename(new char[filenameLen + 1]); - rv = inputStream->Read(filename, filenameLen, &ret); + auto filename = MakeUnique(filenameLen + 1); + rv = inputStream->Read(filename.get(), filenameLen, &ret); if (NS_FAILED(rv) || ret != filenameLen) { return RunShare(NS_ERROR_UNEXPECTED); } @@ -201,7 +204,8 @@ ArchiveReaderZipEvent::Exec() // We ignore the directories: if (filename[filenameLen - 1] != '/') { - mFileList.AppendElement(new ArchiveZipItem(filename, centralStruct, mEncoding)); + mFileList.AppendElement(new ArchiveZipItem(filename.get(), centralStruct, + mEncoding)); } // Ignore the rest diff --git a/dom/base/Console.cpp b/dom/base/Console.cpp index 270b7c9c18..948617e00b 100644 --- a/dom/base/Console.cpp +++ b/dom/base/Console.cpp @@ -1595,9 +1595,14 @@ Console::ProcessArguments(JSContext* aCx, return false; } - nsCString format; - MakeFormatString(format, integer, mantissa, 'f'); - output.AppendPrintf(format.get(), v); + // nspr returns "nan", but we want to expose it as "NaN" + if (std::isnan(v)) { + output.AppendFloat(v); + } else { + nsCString format; + MakeFormatString(format, integer, mantissa, 'f'); + output.AppendPrintf(format.get(), v); + } } break; diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index e2fdd5bdc6..e781224981 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -2225,7 +2225,7 @@ Navigator::GetMozAudioChannelManager(ErrorResult& aRv) bool Navigator::DoResolve(JSContext* aCx, JS::Handle aObject, JS::Handle aId, - JS::MutableHandle aDesc) + JS::MutableHandle aDesc) { // Note: Keep this in sync with MayResolve. if (!JSID_IS_STRING(aId)) { diff --git a/dom/base/Navigator.h b/dom/base/Navigator.h index f7fa6f1449..c9b3b24172 100644 --- a/dom/base/Navigator.h +++ b/dom/base/Navigator.h @@ -301,7 +301,7 @@ public: bool DoResolve(JSContext* aCx, JS::Handle aObject, JS::Handle aId, - JS::MutableHandle aDesc); + JS::MutableHandle aDesc); // The return value is whether DoResolve might end up resolving the given id. // If in doubt, return true. static bool MayResolve(jsid aId); diff --git a/dom/base/WindowNamedPropertiesHandler.cpp b/dom/base/WindowNamedPropertiesHandler.cpp index 1ee3a8d5b5..64cfe9c77f 100644 --- a/dom/base/WindowNamedPropertiesHandler.cpp +++ b/dom/base/WindowNamedPropertiesHandler.cpp @@ -80,7 +80,7 @@ WindowNamedPropertiesHandler::getOwnPropDescriptor(JSContext* aCx, JS::Handle aProxy, JS::Handle aId, bool /* unused */, - JS::MutableHandle aDesc) + JS::MutableHandle aDesc) const { if (!JSID_IS_STRING(aId)) { @@ -158,7 +158,7 @@ bool WindowNamedPropertiesHandler::defineProperty(JSContext* aCx, JS::Handle aProxy, JS::Handle aId, - JS::Handle aDesc, + JS::Handle aDesc, JS::ObjectOpResult &result) const { ErrorResult rv; @@ -223,7 +223,7 @@ WindowNamedPropertiesHandler::delete_(JSContext* aCx, static bool ResolveWindowNamedProperty(JSContext* aCx, JS::Handle aWrapper, JS::Handle aObj, JS::Handle aId, - JS::MutableHandle aDesc) + JS::MutableHandle aDesc) { { JSAutoCompartment ac(aCx, aObj); diff --git a/dom/base/WindowNamedPropertiesHandler.h b/dom/base/WindowNamedPropertiesHandler.h index 088eb4b8af..e17010d7d4 100644 --- a/dom/base/WindowNamedPropertiesHandler.h +++ b/dom/base/WindowNamedPropertiesHandler.h @@ -23,12 +23,12 @@ public: getOwnPropDescriptor(JSContext* aCx, JS::Handle aProxy, JS::Handle aId, bool /* unused */, - JS::MutableHandle aDesc) + JS::MutableHandle aDesc) const override; virtual bool defineProperty(JSContext* aCx, JS::Handle aProxy, JS::Handle aId, - JS::Handle aDesc, + JS::Handle aDesc, JS::ObjectOpResult &result) const override; virtual bool ownPropNames(JSContext* aCx, JS::Handle aProxy, unsigned flags, diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 90a7feb3e8..533617aa97 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -2137,7 +2137,7 @@ nsContentUtils::IsCallerContentXBL() bool nsContentUtils::LookupBindingMember(JSContext* aCx, nsIContent *aContent, JS::Handle aId, - JS::MutableHandle aDesc) + JS::MutableHandle aDesc) { nsXBLBinding* binding = aContent->GetXBLBinding(); if (!binding) diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index 30891f0d8f..7b1991ee20 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -104,7 +104,6 @@ class nsITransferable; class nsPIWindowRoot; class nsIWindowProvider; -struct JSPropertyDescriptor; struct JSRuntime; template class nsCOMArray; @@ -238,7 +237,7 @@ public: static bool LookupBindingMember(JSContext* aCx, nsIContent *aContent, JS::Handle aId, - JS::MutableHandle aDesc); + JS::MutableHandle aDesc); // Check whether we should avoid leaking distinguishing information to JS/CSS. static bool ShouldResistFingerprinting(nsIDocShell* aDocShell); diff --git a/dom/base/nsDOMClassInfo.cpp b/dom/base/nsDOMClassInfo.cpp index c8c324e5d8..97657971fd 100644 --- a/dom/base/nsDOMClassInfo.cpp +++ b/dom/base/nsDOMClassInfo.cpp @@ -927,7 +927,7 @@ nsDOMClassInfo::Resolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, JS::Rooted global(cx, ::JS_GetGlobalForObject(cx, obj)); - JS::Rooted desc(cx); + JS::Rooted desc(cx); if (!JS_GetPropertyDescriptor(cx, global, mData->mName, &desc)) { return NS_ERROR_UNEXPECTED; } @@ -1029,7 +1029,7 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx, const nsGlobalNameStruct *name_struct, nsScriptNameSpaceManager *nameSpaceManager, JSObject *dot_prototype, - JS::MutableHandle ctorDesc); + JS::MutableHandle ctorDesc); NS_IMETHODIMP nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto) @@ -1123,7 +1123,7 @@ nsDOMClassInfo::PostCreatePrototype(JSContext * cx, JSObject * aProto) nsScriptNameSpaceManager *nameSpaceManager = GetNameSpaceManager(); NS_ENSURE_TRUE(nameSpaceManager, NS_OK); - JS::Rooted desc(cx); + JS::Rooted desc(cx); nsresult rv = ResolvePrototype(sXPConnect, win, cx, global, mData->mNameUTF16, mData, nullptr, nameSpaceManager, proto, &desc); @@ -1506,7 +1506,7 @@ nsDOMConstructor::HasInstance(nsIXPConnectWrappedNative *wrapper, if (!name_struct) { // This isn't a normal DOM object, see if this constructor lives on its // prototype chain. - JS::Rooted desc(cx); + JS::Rooted desc(cx); if (!JS_GetPropertyDescriptor(cx, obj, "prototype", &desc)) { return NS_ERROR_UNEXPECTED; } @@ -1721,7 +1721,7 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx, const nsGlobalNameStruct *name_struct, nsScriptNameSpaceManager *nameSpaceManager, JSObject* aDot_prototype, - JS::MutableHandle ctorDesc) + JS::MutableHandle ctorDesc) { JS::Rooted dot_prototype(cx, aDot_prototype); NS_ASSERTION(ci_data || @@ -1819,7 +1819,7 @@ ResolvePrototype(nsIXPConnect *aXPConnect, nsGlobalWindow *aWin, JSContext *cx, if (class_parent_name) { JSAutoCompartment ac(cx, winobj); - JS::Rooted desc(cx); + JS::Rooted desc(cx); if (!JS_GetPropertyDescriptor(cx, winobj, CutPrefix(class_parent_name), &desc)) { return NS_ERROR_UNEXPECTED; } @@ -1906,7 +1906,7 @@ OldBindingConstructorEnabled(const nsGlobalNameStruct *aStruct, static nsresult LookupComponentsShim(JSContext *cx, JS::Handle global, nsPIDOMWindow *win, - JS::MutableHandle desc); + JS::MutableHandle desc); // static bool @@ -1943,7 +1943,7 @@ static const JSClass ControllersShimClass = { nsresult nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, JS::Handle obj, JS::Handle id, - JS::MutableHandle desc) + JS::MutableHandle desc) { if (id == XPCJSRuntime::Get()->GetStringID(XPCJSRuntime::IDX_COMPONENTS)) { return LookupComponentsShim(cx, obj, aWin, desc); @@ -2043,7 +2043,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, // // Unfortunately, there's a bit of an impedance-mismatch between the Xray // and non-Xray machinery. The Xray machinery wants an API that returns a - // JSPropertyDescriptor, so that the resolve hook doesn't have to get + // JS::PropertyDescriptor, so that the resolve hook doesn't have to get // snared up with trying to define a property on the Xray holder. At the // same time, the DefineInterface callbacks are set up to define things // directly on the global. And re-jiggering them to return property @@ -2052,7 +2052,7 @@ nsWindowSH::GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, // // So the setup is as-follows: // - // * The resolve function takes a JSPropertyDescriptor, but in the + // * The resolve function takes a JS::PropertyDescriptor, but in the // non-Xray case, callees may define things directly on the global, and // set the value on the property descriptor to |undefined| to indicate // that there's nothing more for the caller to do. We assert against @@ -2306,7 +2306,7 @@ const InterfaceShimEntry kInterfaceShimMap[] = static nsresult LookupComponentsShim(JSContext *cx, JS::Handle global, nsPIDOMWindow *win, - JS::MutableHandle desc) + JS::MutableHandle desc) { // Keep track of how often this happens. Telemetry::Accumulate(Telemetry::COMPONENTS_SHIM_ACCESSED_BY_CONTENT, true); diff --git a/dom/base/nsDOMClassInfo.h b/dom/base/nsDOMClassInfo.h index d952fc54de..032046cad0 100644 --- a/dom/base/nsDOMClassInfo.h +++ b/dom/base/nsDOMClassInfo.h @@ -223,7 +223,7 @@ class nsWindowSH protected: static nsresult GlobalResolve(nsGlobalWindow *aWin, JSContext *cx, JS::Handle obj, JS::Handle id, - JS::MutableHandle desc); + JS::MutableHandle desc); friend class nsGlobalWindow; public: diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 737d7e85d6..e75b5441b6 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -6142,8 +6142,8 @@ nsDocument::RegisterElement(JSContext* aCx, const nsAString& aType, return; } - JS::Rooted descRoot(aCx); - JS::MutableHandle desc(&descRoot); + JS::Rooted descRoot(aCx); + JS::MutableHandle desc(&descRoot); // This check may go through a wrapper, but as we checked above // it should be transparent or an xray. This should be fine for now, // until the spec is sorted out. diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index e71c0ca565..14fe171dff 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -787,6 +787,7 @@ bool nsFrameLoader::ShowRemoteFrame(const ScreenIntSize& size, nsSubDocumentFrame *aFrame) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS); NS_ASSERTION(IsRemoteFrame(), "ShowRemote only makes sense on remote frames."); if (!mRemoteBrowser && !TryRemoteBrowser()) { @@ -2598,6 +2599,8 @@ nsFrameLoader::EnsureMessageManager() if (!parentManager) { chromeWindow->GetMessageManager(getter_AddRefs(parentManager)); } + } else { + parentManager = do_GetService("@mozilla.org/globalmessagemanager;1"); } mMessageManager = new nsFrameMessageManager(nullptr, diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index ec2364b395..a01f402737 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -653,12 +653,12 @@ public: virtual bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::MutableHandle desc) + JS::MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult &result) const override; virtual bool ownPropertyKeys(JSContext *cx, JS::Handle proxy, @@ -688,7 +688,7 @@ public: virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::MutableHandle desc) + JS::MutableHandle desc) const override; virtual bool hasOwn(JSContext *cx, JS::Handle proxy, JS::Handle id, bool *bp) const override; @@ -777,7 +777,7 @@ bool nsOuterWindowProxy::getPropertyDescriptor(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::MutableHandle desc) const + JS::MutableHandle desc) const { // The only thing we can do differently from js::Wrapper is shadow stuff with // our indexed properties, so we can just try getOwnPropertyDescriptor and if @@ -798,7 +798,7 @@ bool nsOuterWindowProxy::getOwnPropertyDescriptor(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::MutableHandle desc) + JS::MutableHandle desc) const { bool found; @@ -821,7 +821,7 @@ bool nsOuterWindowProxy::defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult &result) const { int32_t index = GetArrayIndexFromId(cx, id); @@ -4330,7 +4330,7 @@ nsGlobalWindow::GetSupportedNames(nsTArray& aNames) bool nsGlobalWindow::DoResolve(JSContext* aCx, JS::Handle aObj, JS::Handle aId, - JS::MutableHandle aDesc) + JS::MutableHandle aDesc) { MOZ_ASSERT(IsInnerWindow()); diff --git a/dom/base/nsGlobalWindow.h b/dom/base/nsGlobalWindow.h index 0e431df5f9..488baf32f8 100644 --- a/dom/base/nsGlobalWindow.h +++ b/dom/base/nsGlobalWindow.h @@ -489,7 +489,7 @@ public: bool DoResolve(JSContext* aCx, JS::Handle aObj, JS::Handle aId, - JS::MutableHandle aDesc); + JS::MutableHandle aDesc); // The return value is whether DoResolve might end up resolving the given id. // If in doubt, return true. static bool MayResolve(jsid aId); diff --git a/dom/base/nsJSEnvironment.cpp b/dom/base/nsJSEnvironment.cpp index a5b3b1f717..7392b0280d 100644 --- a/dom/base/nsJSEnvironment.cpp +++ b/dom/base/nsJSEnvironment.cpp @@ -1335,6 +1335,8 @@ nsJSContext::ShrinkGCBuffersNow() static void FinishAnyIncrementalGC() { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GC); + if (sCCLockedOut) { // We're in the middle of an incremental GC, so finish it. JS::PrepareForIncrementalGC(sRuntime); diff --git a/dom/base/nsObjectLoadingContent.cpp b/dom/base/nsObjectLoadingContent.cpp index 42d1d00c4c..307a42cc7a 100644 --- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -3029,6 +3029,7 @@ nsObjectLoadingContent::DoStopPlugin(nsPluginInstanceOwner* aInstanceOwner, NS_IMETHODIMP nsObjectLoadingContent::StopPluginInstance() { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); // Clear any pending events mPendingInstantiateEvent = nullptr; mPendingCheckPluginStopEvent = nullptr; @@ -3672,7 +3673,7 @@ nsObjectLoadingContent::TeardownProtoChain() bool nsObjectLoadingContent::DoResolve(JSContext* aCx, JS::Handle aObject, JS::Handle aId, - JS::MutableHandle aDesc) + JS::MutableHandle aDesc) { // We don't resolve anything; we just try to make sure we're instantiated. // This purposefully does not fire for chrome/xray resolves, see bug 967694 diff --git a/dom/base/nsObjectLoadingContent.h b/dom/base/nsObjectLoadingContent.h index acd23874b6..e8516d6779 100644 --- a/dom/base/nsObjectLoadingContent.h +++ b/dom/base/nsObjectLoadingContent.h @@ -171,7 +171,7 @@ class nsObjectLoadingContent : public nsImageLoadingContent // Helper for WebIDL NeedResolve bool DoResolve(JSContext* aCx, JS::Handle aObject, JS::Handle aId, - JS::MutableHandle aDesc); + JS::MutableHandle aDesc); // The return value is whether DoResolve might end up resolving the given // id. If in doubt, return true. static bool MayResolve(jsid aId); diff --git a/dom/bindings/BindingUtils.cpp b/dom/bindings/BindingUtils.cpp index fbe14c6663..098ab21c36 100644 --- a/dom/bindings/BindingUtils.cpp +++ b/dom/bindings/BindingUtils.cpp @@ -1172,7 +1172,8 @@ static bool XrayResolveAttribute(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, const Prefable* attributes, jsid* attributeIds, - const JSPropertySpec* attributeSpecs, JS::MutableHandle desc, + const JSPropertySpec* attributeSpecs, + JS::MutableHandle desc, bool& cacheOnHolder) { for (; attributes->specs; ++attributes) { @@ -1222,7 +1223,7 @@ XrayResolveMethod(JSContext* cx, JS::Handle wrapper, const Prefable* methods, jsid* methodIds, const JSFunctionSpec* methodSpecs, - JS::MutableHandle desc, + JS::MutableHandle desc, bool& cacheOnHolder) { const Prefable* method; @@ -1273,7 +1274,7 @@ XrayResolveMethod(JSContext* cx, JS::Handle wrapper, static bool XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, - JS::MutableHandle desc, + JS::MutableHandle desc, bool& cacheOnHolder, const NativeProperties* nativeProperties) { @@ -1315,7 +1316,7 @@ XrayResolveUnforgeableProperty(JSContext* cx, JS::Handle wrapper, static bool XrayResolveProperty(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, - JS::MutableHandle desc, + JS::MutableHandle desc, bool& cacheOnHolder, DOMObjectType type, const NativeProperties* nativeProperties) { @@ -1406,7 +1407,7 @@ static bool ResolvePrototypeOrConstructor(JSContext* cx, JS::Handle wrapper, JS::Handle obj, size_t protoAndIfaceCacheIndex, unsigned attrs, - JS::MutableHandle desc, + JS::MutableHandle desc, bool& cacheOnHolder) { JS::Rooted global(cx, js::GetGlobalForObjectCrossCompartment(obj)); @@ -1446,7 +1447,7 @@ DEBUG_CheckXBLCallable(JSContext *cx, JSObject *obj) } static void -DEBUG_CheckXBLLookup(JSContext *cx, JSPropertyDescriptor *desc) +DEBUG_CheckXBLLookup(JSContext *cx, JS::PropertyDescriptor *desc) { if (!desc->obj) return; @@ -1470,7 +1471,7 @@ DEBUG_CheckXBLLookup(JSContext *cx, JSPropertyDescriptor *desc) /* static */ bool XrayResolveOwnProperty(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, - JS::MutableHandle desc, + JS::MutableHandle desc, bool& cacheOnHolder) { cacheOnHolder = false; @@ -1600,7 +1601,7 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle wrapper, bool XrayDefineProperty(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult &result, bool *defined) { if (!js::IsProxy(obj)) diff --git a/dom/bindings/BindingUtils.h b/dom/bindings/BindingUtils.h index fec76d07f6..128ef05800 100644 --- a/dom/bindings/BindingUtils.h +++ b/dom/bindings/BindingUtils.h @@ -2433,7 +2433,7 @@ bool XrayResolveOwnProperty(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, - JS::MutableHandle desc, + JS::MutableHandle desc, bool& cacheOnHolder); /** @@ -2450,7 +2450,7 @@ XrayResolveOwnProperty(JSContext* cx, JS::Handle wrapper, bool XrayDefineProperty(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult &result, bool *defined); diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 326c5911ef..b98e24c42d 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -8305,7 +8305,7 @@ class CGResolveHook(CGAbstractClassHook): def generate_code(self): return dedent(""" - JS::Rooted desc(cx); + JS::Rooted desc(cx); if (!self->DoResolve(cx, obj, id, &desc)) { return false; } @@ -10371,7 +10371,7 @@ class CGResolveOwnProperty(CGAbstractStaticMethod): Argument('JS::Handle', 'wrapper'), Argument('JS::Handle', 'obj'), Argument('JS::Handle', 'id'), - Argument('JS::MutableHandle', 'desc'), + Argument('JS::MutableHandle', 'desc'), ] CGAbstractStaticMethod.__init__(self, descriptor, "ResolveOwnProperty", "bool", args) @@ -10390,7 +10390,7 @@ class CGResolveOwnPropertyViaResolve(CGAbstractBindingMethod): Argument('JS::Handle', 'wrapper'), Argument('JS::Handle', 'obj'), Argument('JS::Handle', 'id'), - Argument('JS::MutableHandle', 'desc')] + Argument('JS::MutableHandle', 'desc')] CGAbstractBindingMethod.__init__(self, descriptor, "ResolveOwnPropertyViaResolve", args, getThisObj="", @@ -10406,7 +10406,7 @@ class CGResolveOwnPropertyViaResolve(CGAbstractBindingMethod): // to avoid re-resolving the properties if someone deletes // them. JSAutoCompartment ac(cx, obj); - JS::Rooted objDesc(cx); + JS::Rooted objDesc(cx); if (!self->DoResolve(cx, obj, id, &objDesc)) { return false; } @@ -10842,7 +10842,7 @@ class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod): Argument('JS::Handle', 'proxy'), Argument('JS::Handle', 'id'), Argument('bool', 'ignoreNamedProps'), - Argument('JS::MutableHandle', 'desc')] + Argument('JS::MutableHandle', 'desc')] ClassMethod.__init__(self, "getOwnPropDescriptor", "bool", args, virtual=True, override=True, const=True) self.descriptor = descriptor @@ -10958,7 +10958,7 @@ class CGDOMJSProxyHandler_defineProperty(ClassMethod): args = [Argument('JSContext*', 'cx'), Argument('JS::Handle', 'proxy'), Argument('JS::Handle', 'id'), - Argument('JS::Handle', 'desc'), + Argument('JS::Handle', 'desc'), Argument('JS::ObjectOpResult&', 'opresult'), Argument('bool*', 'defined')] ClassMethod.__init__(self, "defineProperty", "bool", args, virtual=True, override=True, const=True) diff --git a/dom/bindings/DOMJSClass.h b/dom/bindings/DOMJSClass.h index 8360e45078..f35b6a1abf 100644 --- a/dom/bindings/DOMJSClass.h +++ b/dom/bindings/DOMJSClass.h @@ -32,7 +32,7 @@ namespace dom { typedef bool (* ResolveOwnProperty)(JSContext* cx, JS::Handle wrapper, JS::Handle obj, JS::Handle id, - JS::MutableHandle desc); + JS::MutableHandle desc); typedef bool (* EnumerateOwnProperties)(JSContext* cx, JS::Handle wrapper, diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index 0ad4b207aa..720bf306e4 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -166,7 +166,7 @@ bool BaseDOMProxyHandler::getOwnPropertyDescriptor(JSContext* cx, JS::Handle proxy, JS::Handle id, - MutableHandle desc) const + MutableHandle desc) const { return getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ false, desc); @@ -174,7 +174,7 @@ BaseDOMProxyHandler::getOwnPropertyDescriptor(JSContext* cx, bool DOMProxyHandler::defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id, - Handle desc, + Handle desc, JS::ObjectOpResult &result, bool *defined) const { if (desc.hasGetterObject() && desc.setter() == JS_StrictPropertyStub) { @@ -214,7 +214,7 @@ DOMProxyHandler::set(JSContext *cx, Handle proxy, Handle id, // Make sure to ignore our named properties when checking for own // property descriptors for a set. - JS::Rooted ownDesc(cx); + JS::Rooted ownDesc(cx); if (!getOwnPropDescriptor(cx, proxy, id, /* ignoreNamedProps = */ true, &ownDesc)) { return false; diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h index 9d8742571a..93ba36e7eb 100644 --- a/dom/bindings/DOMJSProxyHandler.h +++ b/dom/bindings/DOMJSProxyHandler.h @@ -55,7 +55,7 @@ public: // other lower-level methods. bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; virtual bool ownPropertyKeys(JSContext* cx, JS::Handle proxy, JS::AutoIdVector &props) const override; @@ -91,7 +91,7 @@ protected: JS::Handle proxy, JS::Handle id, bool ignoreNamedProps, - JS::MutableHandle desc) const = 0; + JS::MutableHandle desc) const = 0; }; class DOMProxyHandler : public BaseDOMProxyHandler @@ -102,14 +102,14 @@ public: {} bool defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult &result) const override { bool unused; return defineProperty(cx, proxy, id, desc, result, &unused); } virtual bool defineProperty(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult &result, bool *defined) const; bool delete_(JSContext* cx, JS::Handle proxy, JS::Handle id, JS::ObjectOpResult &result) const override; @@ -198,7 +198,7 @@ IsArrayIndex(int32_t index) } inline void -FillPropertyDescriptor(JS::MutableHandle desc, +FillPropertyDescriptor(JS::MutableHandle desc, JSObject* obj, bool readonly, bool enumerable = true) { desc.object().set(obj); @@ -209,7 +209,7 @@ FillPropertyDescriptor(JS::MutableHandle desc, } inline void -FillPropertyDescriptor(JS::MutableHandle desc, +FillPropertyDescriptor(JS::MutableHandle desc, JSObject* obj, JS::Value v, bool readonly, bool enumerable = true) { @@ -218,7 +218,7 @@ FillPropertyDescriptor(JS::MutableHandle desc, } inline void -FillPropertyDescriptor(JS::MutableHandle desc, +FillPropertyDescriptor(JS::MutableHandle desc, JSObject* obj, unsigned attributes, JS::Value v) { desc.object().set(obj); diff --git a/dom/camera/GonkCameraControl.cpp b/dom/camera/GonkCameraControl.cpp index b58c8a5644..9c1bc29229 100644 --- a/dom/camera/GonkCameraControl.cpp +++ b/dom/camera/GonkCameraControl.cpp @@ -2282,8 +2282,7 @@ nsGonkCameraControl::CreatePoster(Image* aImage, uint32_t aWidth, uint32_t aHeig // ARGB is 32 bits / pixel size_t tmpLength = mWidth * mHeight * sizeof(uint32_t); - nsAutoArrayPtr tmp; - tmp = new uint8_t[tmpLength]; + UniquePtr tmp = MakeUnique(tmpLength); GrallocImage* nativeImage = static_cast(mImage.get()); android::sp graphicBuffer = nativeImage->GetGraphicBuffer(); @@ -2293,7 +2292,7 @@ nsGonkCameraControl::CreatePoster(Image* aImage, uint32_t aWidth, uint32_t aHeig uint32_t stride = mWidth * 4; int err = libyuv::ConvertToARGB(static_cast(graphicSrc), - srcLength, tmp, stride, 0, 0, + srcLength, tmp.get(), stride, 0, 0, mWidth, mHeight, mWidth, mHeight, libyuv::kRotate0, libyuv::FOURCC_NV21); @@ -2316,7 +2315,7 @@ nsGonkCameraControl::CreatePoster(Image* aImage, uint32_t aWidth, uint32_t aHeig } nsString opt; - nsresult rv = encoder->InitFromData(tmp, tmpLength, mWidth, + nsresult rv = encoder->InitFromData(tmp.get(), tmpLength, mWidth, mHeight, stride, imgIEncoder::INPUT_FORMAT_HOSTARGB, opt); diff --git a/dom/encoding/TextDecoder.cpp b/dom/encoding/TextDecoder.cpp index b1d6f0c605..24f7ec166e 100644 --- a/dom/encoding/TextDecoder.cpp +++ b/dom/encoding/TextDecoder.cpp @@ -7,6 +7,7 @@ #include "mozilla/dom/TextDecoder.h" #include "mozilla/dom/EncodingUtils.h" #include "mozilla/dom/UnionTypes.h" +#include "mozilla/UniquePtrExtensions.h" #include "nsContentUtils.h" #include @@ -65,18 +66,18 @@ TextDecoder::Decode(const char* aInput, const int32_t aLength, } // Need a fallible allocator because the caller may be a content // and the content can specify the length of the string. - nsAutoArrayPtr buf(new (fallible) char16_t[outLen + 1]); + auto buf = MakeUniqueFallible(outLen + 1); if (!buf) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } int32_t length = aLength; - rv = mDecoder->Convert(aInput, &length, buf, &outLen); + rv = mDecoder->Convert(aInput, &length, buf.get(), &outLen); MOZ_ASSERT(mFatal || rv != NS_ERROR_ILLEGAL_INPUT); buf[outLen] = 0; - if (!aOutDecodedString.Append(buf, outLen, fallible)) { + if (!aOutDecodedString.Append(buf.get(), outLen, fallible)) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } diff --git a/dom/encoding/TextEncoder.cpp b/dom/encoding/TextEncoder.cpp index 96e615876a..85bc0ff3cb 100644 --- a/dom/encoding/TextEncoder.cpp +++ b/dom/encoding/TextEncoder.cpp @@ -6,6 +6,7 @@ #include "mozilla/dom/TextEncoder.h" #include "mozilla/dom/EncodingUtils.h" +#include "mozilla/UniquePtrExtensions.h" #include "nsContentUtils.h" namespace mozilla { @@ -54,18 +55,18 @@ TextEncoder::Encode(JSContext* aCx, } // Need a fallible allocator because the caller may be a content // and the content can specify the length of the string. - nsAutoArrayPtr buf(new (fallible) char[maxLen + 1]); + auto buf = MakeUniqueFallible(maxLen + 1); if (!buf) { aRv.Throw(NS_ERROR_OUT_OF_MEMORY); return; } int32_t dstLen = maxLen; - rv = mEncoder->Convert(data, &srcLen, buf, &dstLen); + rv = mEncoder->Convert(data, &srcLen, buf.get(), &dstLen); // Now reset the encoding algorithm state to the default values for encoding. int32_t finishLen = maxLen - dstLen; - rv = mEncoder->Finish(buf + dstLen, &finishLen); + rv = mEncoder->Finish(&buf[dstLen], &finishLen); if (NS_SUCCEEDED(rv)) { dstLen += finishLen; } diff --git a/dom/html/HTMLFrameSetElement.cpp b/dom/html/HTMLFrameSetElement.cpp index 8991c60f40..b5996c100c 100644 --- a/dom/html/HTMLFrameSetElement.cpp +++ b/dom/html/HTMLFrameSetElement.cpp @@ -8,6 +8,7 @@ #include "mozilla/dom/HTMLFrameSetElementBinding.h" #include "mozilla/dom/EventHandlerBinding.h" #include "nsGlobalWindow.h" +#include "mozilla/UniquePtrExtensions.h" NS_IMPL_NS_NEW_HTML_ELEMENT(FrameSet) @@ -81,7 +82,7 @@ HTMLFrameSetElement::SetAttr(int32_t aNameSpaceID, */ if (aAttribute == nsGkAtoms::rows && aNameSpaceID == kNameSpaceID_None) { int32_t oldRows = mNumRows; - ParseRowCol(aValue, mNumRows, getter_Transfers(mRowSpecs)); + ParseRowCol(aValue, mNumRows, &mRowSpecs); if (mNumRows != oldRows) { mCurrentRowColHint = NS_STYLE_HINT_FRAMECHANGE; @@ -89,7 +90,7 @@ HTMLFrameSetElement::SetAttr(int32_t aNameSpaceID, } else if (aAttribute == nsGkAtoms::cols && aNameSpaceID == kNameSpaceID_None) { int32_t oldCols = mNumCols; - ParseRowCol(aValue, mNumCols, getter_Transfers(mColSpecs)); + ParseRowCol(aValue, mNumCols, &mColSpecs); if (mNumCols != oldCols) { mCurrentRowColHint = NS_STYLE_HINT_FRAMECHANGE; @@ -116,19 +117,19 @@ HTMLFrameSetElement::GetRowSpec(int32_t *aNumValues, const nsAttrValue* value = GetParsedAttr(nsGkAtoms::rows); if (value && value->Type() == nsAttrValue::eString) { nsresult rv = ParseRowCol(value->GetStringValue(), mNumRows, - getter_Transfers(mRowSpecs)); + &mRowSpecs); NS_ENSURE_SUCCESS(rv, rv); } if (!mRowSpecs) { // we may not have had an attr or had an empty attr - mRowSpecs = new nsFramesetSpec[1]; + mRowSpecs = MakeUnique(1); mNumRows = 1; mRowSpecs[0].mUnit = eFramesetUnit_Relative; mRowSpecs[0].mValue = 1; } } - *aSpecs = mRowSpecs; + *aSpecs = mRowSpecs.get(); *aNumValues = mNumRows; return NS_OK; } @@ -146,19 +147,19 @@ HTMLFrameSetElement::GetColSpec(int32_t *aNumValues, const nsAttrValue* value = GetParsedAttr(nsGkAtoms::cols); if (value && value->Type() == nsAttrValue::eString) { nsresult rv = ParseRowCol(value->GetStringValue(), mNumCols, - getter_Transfers(mColSpecs)); + &mColSpecs); NS_ENSURE_SUCCESS(rv, rv); } if (!mColSpecs) { // we may not have had an attr or had an empty attr - mColSpecs = new nsFramesetSpec[1]; + mColSpecs = MakeUnique(1); mNumCols = 1; mColSpecs[0].mUnit = eFramesetUnit_Relative; mColSpecs[0].mValue = 1; } } - *aSpecs = mColSpecs; + *aSpecs = mColSpecs.get(); *aNumValues = mNumCols; return NS_OK; } @@ -205,7 +206,7 @@ HTMLFrameSetElement::GetAttributeChangeHint(const nsIAtom* aAttribute, nsresult HTMLFrameSetElement::ParseRowCol(const nsAString & aValue, int32_t& aNumSpecs, - nsFramesetSpec** aSpecs) + UniquePtr* aSpecs) { if (aValue.IsEmpty()) { aNumSpecs = 0; @@ -233,7 +234,7 @@ HTMLFrameSetElement::ParseRowCol(const nsAString & aValue, commaX = spec.FindChar(sComma, commaX + 1); } - nsFramesetSpec* specs = new (fallible) nsFramesetSpec[count]; + auto specs = MakeUniqueFallible(count); if (!specs) { *aSpecs = nullptr; aNumSpecs = 0; @@ -327,8 +328,8 @@ HTMLFrameSetElement::ParseRowCol(const nsAString & aValue, aNumSpecs = count; // Transfer ownership to caller here - *aSpecs = specs; - + *aSpecs = Move(specs); + return NS_OK; } diff --git a/dom/html/HTMLFrameSetElement.h b/dom/html/HTMLFrameSetElement.h index 5470e668f7..b6bbe5d957 100644 --- a/dom/html/HTMLFrameSetElement.h +++ b/dom/html/HTMLFrameSetElement.h @@ -8,6 +8,7 @@ #define HTMLFrameSetElement_h #include "mozilla/Attributes.h" +#include "mozilla/UniquePtr.h" #include "nsIDOMHTMLFrameSetElement.h" #include "nsGenericHTMLElement.h" @@ -144,8 +145,8 @@ protected: private: nsresult ParseRowCol(const nsAString& aValue, - int32_t& aNumSpecs, - nsFramesetSpec** aSpecs); + int32_t& aNumSpecs, + UniquePtr* aSpecs); /** * The number of size specs in our "rows" attr @@ -163,11 +164,11 @@ private: /** * The parsed representation of the "rows" attribute */ - nsAutoArrayPtr mRowSpecs; // parsed, non-computed dimensions + UniquePtr mRowSpecs; // parsed, non-computed dimensions /** * The parsed representation of the "cols" attribute */ - nsAutoArrayPtr mColSpecs; // parsed, non-computed dimensions + UniquePtr mColSpecs; // parsed, non-computed dimensions }; } // namespace dom diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 28abd006f1..d89a25aa86 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1233,6 +1233,8 @@ ContentParent::CreateBrowserOrApp(const TabContext& aContext, Element* aFrameElement, ContentParent* aOpenerContentParent) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + if (!sCanLaunchSubprocesses) { return nullptr; } @@ -2382,6 +2384,8 @@ ContentParent::InitializeMembers() bool ContentParent::LaunchSubprocess(ProcessPriority aInitialPriority /* = PROCESS_PRIORITY_FOREGROUND */) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + std::vector extraArgs; if (mIsNuwaProcess) { extraArgs.push_back("-nuwa"); @@ -3643,6 +3647,8 @@ ContentParent::ForceKillTimerCallback(nsITimer* aTimer, void* aClosure) void ContentParent::KillHard(const char* aReason) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + // On Windows, calling KillHard multiple times causes problems - the // process handle becomes invalid on the first call, causing a second call // to crash our process - more details in bug 890840. diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index a42f0cbb9d..b45b74c33d 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -38,6 +38,7 @@ #include "mozilla/Preferences.h" #include "mozilla/TextEvents.h" #include "mozilla/TouchEvents.h" +#include "mozilla/UniquePtr.h" #include "mozilla/unused.h" #include "BlobParent.h" #include "nsCOMPtr.h" @@ -2107,25 +2108,25 @@ TabParent::RecvEnableDisableCommands(const nsString& aAction, { nsCOMPtr remoteBrowser = do_QueryInterface(mFrameElement); if (remoteBrowser) { - nsAutoArrayPtr enabledCommands, disabledCommands; + UniquePtr enabledCommands, disabledCommands; if (aEnabledCommands.Length()) { - enabledCommands = new const char* [aEnabledCommands.Length()]; + enabledCommands = MakeUnique(aEnabledCommands.Length()); for (uint32_t c = 0; c < aEnabledCommands.Length(); c++) { enabledCommands[c] = aEnabledCommands[c].get(); } } if (aDisabledCommands.Length()) { - disabledCommands = new const char* [aDisabledCommands.Length()]; + disabledCommands = MakeUnique(aDisabledCommands.Length()); for (uint32_t c = 0; c < aDisabledCommands.Length(); c++) { disabledCommands[c] = aDisabledCommands[c].get(); } } remoteBrowser->EnableDisableCommands(aAction, - aEnabledCommands.Length(), enabledCommands, - aDisabledCommands.Length(), disabledCommands); + aEnabledCommands.Length(), enabledCommands.get(), + aDisabledCommands.Length(), disabledCommands.get()); } return true; diff --git a/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerModule.cpp b/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerModule.cpp new file mode 100644 index 0000000000..17370a25a3 --- /dev/null +++ b/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerModule.cpp @@ -0,0 +1,57 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "mozilla/ModuleUtils.h" +#include "nsIClassInfoImpl.h" + +#include "OSXSpeechSynthesizerService.h" + +using namespace mozilla::dom; + +#define OSXSPEECHSYNTHESIZERSERVICE_CID \ + {0x914e73b4, 0x6337, 0x4bef, {0x97, 0xf3, 0x4d, 0x06, 0x9e, 0x05, 0x3a, 0x12}} + +#define OSXSPEECHSYNTHESIZERSERVICE_CONTRACTID "@mozilla.org/synthsystem;1" + +// Defines OSXSpeechSynthesizerServiceConstructor +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(OSXSpeechSynthesizerService, + OSXSpeechSynthesizerService::GetInstanceForService) + +// Defines kSAPISERVICE_CID +NS_DEFINE_NAMED_CID(OSXSPEECHSYNTHESIZERSERVICE_CID); + +static const mozilla::Module::CIDEntry kCIDs[] = { + { &kOSXSPEECHSYNTHESIZERSERVICE_CID, true, nullptr, OSXSpeechSynthesizerServiceConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kContracts[] = { + { OSXSPEECHSYNTHESIZERSERVICE_CONTRACTID, &kOSXSPEECHSYNTHESIZERSERVICE_CID }, + { nullptr } +}; + +static const mozilla::Module::CategoryEntry kCategories[] = { + { "profile-after-change", "Sapi Speech Synth", OSXSPEECHSYNTHESIZERSERVICE_CONTRACTID }, + { nullptr } +}; + +static void +UnloadOSXSpeechSynthesizerModule() +{ + OSXSpeechSynthesizerService::Shutdown(); +} + +static const mozilla::Module kModule = { + mozilla::Module::kVersion, + kCIDs, + kContracts, + kCategories, + nullptr, + nullptr, + UnloadOSXSpeechSynthesizerModule +}; + +NSMODULE_DEFN(osxsynth) = &kModule; diff --git a/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.h b/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.h new file mode 100644 index 0000000000..35ff6f0a81 --- /dev/null +++ b/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.h @@ -0,0 +1,45 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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_dom_OsxSpeechSynthesizerService_h +#define mozilla_dom_OsxSpeechSynthesizerService_h + +#include "nsAutoPtr.h" +#include "nsISpeechService.h" +#include "nsIObserver.h" +#include "mozilla/StaticPtr.h" + +namespace mozilla { +namespace dom { + +class OSXSpeechSynthesizerService final : public nsISpeechService + , public nsIObserver +{ +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSISPEECHSERVICE + NS_DECL_NSIOBSERVER + + bool Init(); + + static OSXSpeechSynthesizerService* GetInstance(); + static already_AddRefed GetInstanceForService(); + static void Shutdown(); + +private: + OSXSpeechSynthesizerService(); + virtual ~OSXSpeechSynthesizerService(); + + bool RegisterVoices(); + + bool mInitialized; + static mozilla::StaticRefPtr sSingleton; +}; + +} // namespace dom +} // namespace mozilla + +#endif diff --git a/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.mm b/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.mm new file mode 100644 index 0000000000..d78a99bb3c --- /dev/null +++ b/dom/media/webspeech/synth/cocoa/OSXSpeechSynthesizerService.mm @@ -0,0 +1,457 @@ +/* -*- Mode: Objective-C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=2 sw=2 et tw=80: */ +/* 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 "nsISupports.h" +#include "nsServiceManagerUtils.h" +#include "nsObjCExceptions.h" +#include "nsCocoaUtils.h" +#include "nsThreadUtils.h" +#include "mozilla/dom/nsSynthVoiceRegistry.h" +#include "mozilla/dom/nsSpeechTask.h" +#include "mozilla/Preferences.h" +#include "mozilla/Assertions.h" +#include "OSXSpeechSynthesizerService.h" + +#import + +using namespace mozilla; + +class SpeechTaskCallback final : public nsISpeechTaskCallback +{ +public: + SpeechTaskCallback(nsISpeechTask* aTask, NSSpeechSynthesizer* aSynth) + : mTask(aTask) + , mSpeechSynthesizer(aSynth) + { + mStartingTime = TimeStamp::Now(); + } + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SpeechTaskCallback, nsISpeechTaskCallback) + + NS_DECL_NSISPEECHTASKCALLBACK + + void OnWillSpeakWord(uint32_t aIndex); + void OnError(uint32_t aIndex); + void OnDidFinishSpeaking(); + +private: + virtual ~SpeechTaskCallback() + { + [mSpeechSynthesizer release]; + } + + float GetTimeDurationFromStart(); + + nsCOMPtr mTask; + NSSpeechSynthesizer* mSpeechSynthesizer; + TimeStamp mStartingTime; + uint32_t mCurrentIndex; +}; + +NS_IMPL_CYCLE_COLLECTION(SpeechTaskCallback, mTask); + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechTaskCallback) + NS_INTERFACE_MAP_ENTRY(nsISpeechTaskCallback) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechTaskCallback) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechTaskCallback) +NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechTaskCallback) + +NS_IMETHODIMP +SpeechTaskCallback::OnCancel() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + [mSpeechSynthesizer stopSpeaking]; + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +NS_IMETHODIMP +SpeechTaskCallback::OnPause() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + [mSpeechSynthesizer pauseSpeakingAtBoundary:NSSpeechImmediateBoundary]; + if (!mTask) { + // When calling pause() on child porcess, it may not receive end event + // from chrome process yet. + return NS_ERROR_FAILURE; + } + mTask->DispatchPause(GetTimeDurationFromStart(), mCurrentIndex); + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +NS_IMETHODIMP +SpeechTaskCallback::OnResume() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + [mSpeechSynthesizer continueSpeaking]; + if (!mTask) { + // When calling resume() on child porcess, it may not receive end event + // from chrome process yet. + return NS_ERROR_FAILURE; + } + mTask->DispatchResume(GetTimeDurationFromStart(), mCurrentIndex); + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +NS_IMETHODIMP +SpeechTaskCallback::OnVolumeChanged(float aVolume) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + [mSpeechSynthesizer setObject:[NSNumber numberWithFloat:aVolume] + forProperty:NSSpeechVolumeProperty error:nil]; + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +float +SpeechTaskCallback::GetTimeDurationFromStart() +{ + TimeDuration duration = TimeStamp::Now() - mStartingTime; + return duration.ToMilliseconds(); +} + +void +SpeechTaskCallback::OnWillSpeakWord(uint32_t aIndex) +{ + mCurrentIndex = aIndex; + if (!mTask) { + return; + } + mTask->DispatchBoundary(NS_LITERAL_STRING("word"), + GetTimeDurationFromStart(), mCurrentIndex); +} + +void +SpeechTaskCallback::OnError(uint32_t aIndex) +{ + if (!mTask) { + return; + } + mTask->DispatchError(GetTimeDurationFromStart(), aIndex); +} + +void +SpeechTaskCallback::OnDidFinishSpeaking() +{ + mTask->DispatchEnd(GetTimeDurationFromStart(), mCurrentIndex); + // no longer needed + mTask = nullptr; +} + +@interface SpeechDelegate : NSObject +{ +@private + SpeechTaskCallback* mCallback; +} + + - (id)initWithCallback:(SpeechTaskCallback*)aCallback; +@end + +@implementation SpeechDelegate +- (id)initWithCallback:(SpeechTaskCallback*)aCallback +{ + [super init]; + mCallback = aCallback; + return self; +} + +- (void)speechSynthesizer:(NSSpeechSynthesizer *)aSender + willSpeakWord:(NSRange)aRange ofString:(NSString*)aString +{ + mCallback->OnWillSpeakWord(aRange.location); +} + +- (void)speechSynthesizer:(NSSpeechSynthesizer *)aSender + didFinishSpeaking:(BOOL)aFinishedSpeaking +{ + mCallback->OnDidFinishSpeaking(); +} + +- (void)speechSynthesizer:(NSSpeechSynthesizer*)aSender + didEncounterErrorAtIndex:(NSUInteger)aCharacterIndex + ofString:(NSString*)aString + message:(NSString*)aMessage +{ + mCallback->OnError(aCharacterIndex); +} +@end + +namespace mozilla { +namespace dom { + +struct OSXVoice +{ + OSXVoice() : mIsDefault(false) + { + } + + nsString mUri; + nsString mName; + nsString mLocale; + bool mIsDefault; +}; + +class RegisterVoicesRunnable final : public nsRunnable +{ +public: + RegisterVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService, + nsTArray& aList) + : mSpeechService(aSpeechService) + , mVoices(aList) + { + } + + NS_IMETHOD Run() override; + +private: + ~RegisterVoicesRunnable() + { + } + + // This runnable always use sync mode. It is unnecesarry to reference object + OSXSpeechSynthesizerService* mSpeechService; + nsTArray& mVoices; +}; + +NS_IMETHODIMP +RegisterVoicesRunnable::Run() +{ + nsresult rv; + nsCOMPtr registry = + do_GetService(NS_SYNTHVOICEREGISTRY_CONTRACTID, &rv); + if (!registry) { + return rv; + } + + for (OSXVoice voice : mVoices) { + rv = registry->AddVoice(mSpeechService, voice.mUri, voice.mName, voice.mLocale, true, false); + if (NS_WARN_IF(NS_FAILED(rv))) { + continue; + } + + if (voice.mIsDefault) { + registry->SetDefaultVoice(voice.mUri, true); + } + } + return NS_OK; +} + +class EnumVoicesRunnable final : public nsRunnable +{ +public: + explicit EnumVoicesRunnable(OSXSpeechSynthesizerService* aSpeechService) + : mSpeechService(aSpeechService) + { + } + + NS_IMETHOD Run() override; + +private: + ~EnumVoicesRunnable() + { + } + + RefPtr mSpeechService; +}; + +NS_IMETHODIMP +EnumVoicesRunnable::Run() +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + nsAutoTArray list; + + NSArray* voices = [NSSpeechSynthesizer availableVoices]; + NSString* defaultVoice = [NSSpeechSynthesizer defaultVoice]; + + for (NSString* voice in voices) { + OSXVoice item; + + NSDictionary* attr = [NSSpeechSynthesizer attributesForVoice:voice]; + + nsAutoString identifier; + nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceIdentifier], + identifier); + + nsCocoaUtils::GetStringForNSString([attr objectForKey:NSVoiceName], item.mName); + + nsCocoaUtils::GetStringForNSString( + [attr objectForKey:NSVoiceLocaleIdentifier], item.mLocale); + item.mLocale.ReplaceChar('_', '-'); + + item.mUri.AssignLiteral("urn:moz-tts:osx:"); + item.mUri.Append(identifier); + + if ([voice isEqualToString:defaultVoice]) { + item.mIsDefault = true; + } + + list.AppendElement(item); + } + + RefPtr runnable = new RegisterVoicesRunnable(mSpeechService, list); + NS_DispatchToMainThread(runnable, NS_DISPATCH_SYNC); + + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +StaticRefPtr OSXSpeechSynthesizerService::sSingleton; + +NS_INTERFACE_MAP_BEGIN(OSXSpeechSynthesizerService) + NS_INTERFACE_MAP_ENTRY(nsISpeechService) + NS_INTERFACE_MAP_ENTRY(nsIObserver) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechService) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(OSXSpeechSynthesizerService) +NS_IMPL_RELEASE(OSXSpeechSynthesizerService) + +OSXSpeechSynthesizerService::OSXSpeechSynthesizerService() + : mInitialized(false) +{ +} + +OSXSpeechSynthesizerService::~OSXSpeechSynthesizerService() +{ +} + +bool +OSXSpeechSynthesizerService::Init() +{ + if (Preferences::GetBool("media.webspeech.synth.test") || + !Preferences::GetBool("media.webspeech.synth.enabled")) { + // When test is enabled, we shouldn't add OS backend (Bug 1160844) + return false; + } + + nsCOMPtr thread; + if (NS_FAILED(NS_NewNamedThread("SpeechWorker", getter_AddRefs(thread)))) { + return false; + } + + // Get all the voices and register in the SynthVoiceRegistry + nsCOMPtr runnable = new EnumVoicesRunnable(this); + thread->Dispatch(runnable, NS_DISPATCH_NORMAL); + + mInitialized = true; + return true; +} + +NS_IMETHODIMP +OSXSpeechSynthesizerService::Speak(const nsAString& aText, + const nsAString& aUri, + float aVolume, + float aRate, + float aPitch, + nsISpeechTask* aTask) +{ + NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; + + MOZ_ASSERT(StringBeginsWith(aUri, NS_LITERAL_STRING("urn:moz-tts:osx:")), + "OSXSpeechSynthesizerService doesn't allow this voice URI"); + + NSSpeechSynthesizer* synth = [[NSSpeechSynthesizer alloc] init]; + // strlen("urn:moz-tts:osx:") == 16 + NSString* identifier = nsCocoaUtils::ToNSString(Substring(aUri, 16)); + [synth setVoice:identifier]; + + // default rate is 180-220 + [synth setObject:[NSNumber numberWithInt:aRate * 200] + forProperty:NSSpeechRateProperty error:nil]; + // volume allows 0.0-1.0 + [synth setObject:[NSNumber numberWithFloat:aVolume] + forProperty:NSSpeechVolumeProperty error:nil]; + // Use default pitch value to calculate this + NSNumber* defaultPitch = + [synth objectForProperty:NSSpeechPitchBaseProperty error:nil]; + if (defaultPitch) { + int newPitch = [defaultPitch intValue] * (aPitch / 2 + 0.5); + [synth setObject:[NSNumber numberWithInt:newPitch] + forProperty:NSSpeechPitchBaseProperty error:nil]; + } + + RefPtr callback = new SpeechTaskCallback(aTask, synth); + nsresult rv = aTask->Setup(callback, 0, 0, 0); + NS_ENSURE_SUCCESS(rv, rv); + + SpeechDelegate* delegate = [[SpeechDelegate alloc] initWithCallback:callback]; + [synth setDelegate:delegate]; + [delegate release ]; + + NSString* text = nsCocoaUtils::ToNSString(aText); + BOOL success = [synth startSpeakingString:text]; + NS_ENSURE_TRUE(success, NS_ERROR_FAILURE); + + aTask->DispatchStart(); + return NS_OK; + + NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; +} + +NS_IMETHODIMP +OSXSpeechSynthesizerService::GetServiceType(SpeechServiceType* aServiceType) +{ + *aServiceType = nsISpeechService::SERVICETYPE_INDIRECT_AUDIO; + return NS_OK; +} + +NS_IMETHODIMP +OSXSpeechSynthesizerService::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) +{ + if (!strcmp(aTopic, "profile-after-change")) { + Init(); + } + return NS_OK; +} + +OSXSpeechSynthesizerService* +OSXSpeechSynthesizerService::GetInstance() +{ + MOZ_ASSERT(NS_IsMainThread()); + if (XRE_GetProcessType() != GeckoProcessType_Default) { + return nullptr; + } + + if (!sSingleton) { + sSingleton = new OSXSpeechSynthesizerService(); + } + return sSingleton; +} + +already_AddRefed +OSXSpeechSynthesizerService::GetInstanceForService() +{ + RefPtr speechService = GetInstance(); + return speechService.forget(); +} + +void +OSXSpeechSynthesizerService::Shutdown() +{ + if (!sSingleton) { + return; + } + sSingleton = nullptr; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/media/webspeech/synth/cocoa/moz.build b/dom/media/webspeech/synth/cocoa/moz.build new file mode 100644 index 0000000000..af8b396e2a --- /dev/null +++ b/dom/media/webspeech/synth/cocoa/moz.build @@ -0,0 +1,12 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +SOURCES += [ + 'OSXSpeechSynthesizerModule.cpp', + 'OSXSpeechSynthesizerService.mm' +] + +FINAL_LIBRARY = 'xul' diff --git a/dom/media/webspeech/synth/moz.build b/dom/media/webspeech/synth/moz.build index b7f213e2c2..cc629267c8 100644 --- a/dom/media/webspeech/synth/moz.build +++ b/dom/media/webspeech/synth/moz.build @@ -42,11 +42,19 @@ if CONFIG['MOZ_WEBSPEECH']: 'test/nsFakeSynthServices.cpp' ] + DIRS = [] + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': - DIRS = ['windows'] + DIRS += ['windows'] + + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': + DIRS += ['cocoa'] + + if CONFIG['MOZ_SYNTH_SPEECHD']: + DIRS += ['speechd'] if CONFIG['MOZ_SYNTH_PICO']: - DIRS = ['pico'] + DIRS += ['pico'] IPDL_SOURCES += [ 'ipc/PSpeechSynthesis.ipdl', diff --git a/dom/media/webspeech/synth/nsISpeechService.idl b/dom/media/webspeech/synth/nsISpeechService.idl index 458b4774ea..c802837155 100644 --- a/dom/media/webspeech/synth/nsISpeechService.idl +++ b/dom/media/webspeech/synth/nsISpeechService.idl @@ -12,7 +12,7 @@ typedef unsigned short SpeechServiceType; * required to implement these, although it could be helpful to use the * cancel method for shutting down the speech resources. */ -[scriptable, uuid(408251b0-1d7b-4876-888f-718859ce8c9d)] +[scriptable, uuid(c576de0c-8a3d-4570-be7e-9876d3e5bed2)] interface nsISpeechTaskCallback : nsISupports { /** @@ -29,6 +29,12 @@ interface nsISpeechTaskCallback : nsISupports * The user or application has canceled the speech. */ void onCancel(); + + /** + * The user or application has changed the volume of this speech. + * This is only used on indirect audio service type. + */ + void onVolumeChanged(in float aVolume); }; diff --git a/dom/media/webspeech/synth/nsSpeechTask.cpp b/dom/media/webspeech/synth/nsSpeechTask.cpp index a93f07c3b3..5040e5a667 100644 --- a/dom/media/webspeech/synth/nsSpeechTask.cpp +++ b/dom/media/webspeech/synth/nsSpeechTask.cpp @@ -681,6 +681,10 @@ nsSpeechTask::CreateAudioChannelAgent() mAudioChannelAgent->InitWithWeakCallback(mUtterance->GetOwner(), static_cast(AudioChannelService::GetDefaultAudioChannel()), this); + float volume = 0.0f; + bool muted = true; + mAudioChannelAgent->NotifyStartedPlaying(nsIAudioChannelAgent::AUDIO_AGENT_NOTIFY, &volume, &muted); + WindowVolumeChanged(volume, muted); } void @@ -712,6 +716,9 @@ nsSpeechTask::SetAudioOutputVolume(float aVolume) if (mStream) { mStream->SetAudioOutputVolume(this, aVolume); } + if (mIndirectAudio) { + mCallback->OnVolumeChanged(aVolume); + } } } // namespace dom diff --git a/dom/media/webspeech/synth/pico/nsPicoService.cpp b/dom/media/webspeech/synth/pico/nsPicoService.cpp index 2d00907c43..0fe6e189e5 100644 --- a/dom/media/webspeech/synth/pico/nsPicoService.cpp +++ b/dom/media/webspeech/synth/pico/nsPicoService.cpp @@ -409,6 +409,12 @@ PicoCallbackRunnable::OnCancel() return NS_OK; } +NS_IMETHODIMP +PicoCallbackRunnable::OnVolumeChanged(float aVolume) +{ + return NS_OK; +} + NS_INTERFACE_MAP_BEGIN(nsPicoService) NS_INTERFACE_MAP_ENTRY(nsISpeechService) NS_INTERFACE_MAP_ENTRY(nsIObserver) diff --git a/dom/media/webspeech/synth/speechd/SpeechDispatcherModule.cpp b/dom/media/webspeech/synth/speechd/SpeechDispatcherModule.cpp new file mode 100644 index 0000000000..deed7c1d29 --- /dev/null +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherModule.cpp @@ -0,0 +1,56 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "mozilla/ModuleUtils.h" +#include "nsIClassInfoImpl.h" +#include "SpeechDispatcherService.h" + +using namespace mozilla::dom; + +#define SPEECHDISPATCHERSERVICE_CID \ + {0x8817b1cf, 0x5ada, 0x43bf, {0xbd, 0x73, 0x60, 0x76, 0x57, 0x70, 0x3d, 0x0d}} + +#define SPEECHDISPATCHERSERVICE_CONTRACTID "@mozilla.org/synthspeechdispatcher;1" + +// Defines SpeechDispatcherServiceConstructor +NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(SpeechDispatcherService, + SpeechDispatcherService::GetInstanceForService) + +// Defines kSPEECHDISPATCHERSERVICE_CID +NS_DEFINE_NAMED_CID(SPEECHDISPATCHERSERVICE_CID); + +static const mozilla::Module::CIDEntry kCIDs[] = { + { &kSPEECHDISPATCHERSERVICE_CID, true, nullptr, SpeechDispatcherServiceConstructor }, + { nullptr } +}; + +static const mozilla::Module::ContractIDEntry kContracts[] = { + { SPEECHDISPATCHERSERVICE_CONTRACTID, &kSPEECHDISPATCHERSERVICE_CID }, + { nullptr } +}; + +static const mozilla::Module::CategoryEntry kCategories[] = { + { "profile-after-change", "SpeechDispatcher Speech Synth", SPEECHDISPATCHERSERVICE_CONTRACTID }, + { nullptr } +}; + +static void +UnloadSpeechDispatcherModule() +{ + SpeechDispatcherService::Shutdown(); +} + +static const mozilla::Module kModule = { + mozilla::Module::kVersion, + kCIDs, + kContracts, + kCategories, + nullptr, + nullptr, + UnloadSpeechDispatcherModule +}; + +NSMODULE_DEFN(synthspeechdispatcher) = &kModule; diff --git a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp new file mode 100644 index 0000000000..e1310f1fcb --- /dev/null +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp @@ -0,0 +1,577 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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 "SpeechDispatcherService.h" + +#include "mozilla/dom/nsSpeechTask.h" +#include "mozilla/dom/nsSynthVoiceRegistry.h" +#include "mozilla/Preferences.h" +#include "nsEscape.h" +#include "nsISupports.h" +#include "nsPrintfCString.h" +#include "nsReadableUtils.h" +#include "nsServiceManagerUtils.h" +#include "nsThreadUtils.h" +#include "prlink.h" + +#define URI_PREFIX "urn:moz-tts:sapi:" + +// Some structures for libspeechd +typedef enum { + SPD_EVENT_BEGIN, + SPD_EVENT_END, + SPD_EVENT_INDEX_MARK, + SPD_EVENT_CANCEL, + SPD_EVENT_PAUSE, + SPD_EVENT_RESUME +} SPDNotificationType; + +typedef enum { + SPD_BEGIN = 1, + SPD_END = 2, + SPD_INDEX_MARKS = 4, + SPD_CANCEL = 8, + SPD_PAUSE = 16, + SPD_RESUME = 32, + + SPD_ALL = 0x3f +} SPDNotification; + +typedef enum { + SPD_MODE_SINGLE = 0, + SPD_MODE_THREADED = 1 +} SPDConnectionMode; + +typedef void (*SPDCallback) (size_t msg_id, size_t client_id, + SPDNotificationType state); + +typedef void (*SPDCallbackIM) (size_t msg_id, size_t client_id, + SPDNotificationType state, char* index_mark); + +struct SPDConnection +{ + SPDCallback callback_begin; + SPDCallback callback_end; + SPDCallback callback_cancel; + SPDCallback callback_pause; + SPDCallback callback_resume; + SPDCallbackIM callback_im; + + /* partial, more private fields in structure */ +}; + +struct SPDVoice +{ + char* name; + char* language; + char* variant; +}; + +typedef enum { + SPD_IMPORTANT = 1, + SPD_MESSAGE = 2, + SPD_TEXT = 3, + SPD_NOTIFICATION = 4, + SPD_PROGRESS = 5 +} SPDPriority; + +#define SPEECHD_FUNCTIONS \ + FUNC(spd_open, SPDConnection*, (const char*, const char*, const char*, SPDConnectionMode)) \ + FUNC(spd_close, void, (SPDConnection*)) \ + FUNC(spd_list_synthesis_voices, SPDVoice**, (SPDConnection*)) \ + FUNC(spd_say, int, (SPDConnection*, SPDPriority, const char*)) \ + FUNC(spd_cancel, int, (SPDConnection*)) \ + FUNC(spd_set_volume, int, (SPDConnection*, int)) \ + FUNC(spd_set_voice_rate, int, (SPDConnection*, int)) \ + FUNC(spd_set_voice_pitch, int, (SPDConnection*, int)) \ + FUNC(spd_set_synthesis_voice, int, (SPDConnection*, const char*)) \ + FUNC(spd_set_notification_on, int, (SPDConnection*, SPDNotification)) + +#define FUNC(name, type, params) \ + typedef type (*_##name##_fn) params; \ + static _##name##_fn _##name; + +SPEECHD_FUNCTIONS + +#undef FUNC + +#define spd_open _spd_open +#define spd_close _spd_close +#define spd_list_synthesis_voices _spd_list_synthesis_voices +#define spd_say _spd_say +#define spd_cancel _spd_cancel +#define spd_set_volume _spd_set_volume +#define spd_set_voice_rate _spd_set_voice_rate +#define spd_set_voice_pitch _spd_set_voice_pitch +#define spd_set_synthesis_voice _spd_set_synthesis_voice +#define spd_set_notification_on _spd_set_notification_on + +static PRLibrary* speechdLib = nullptr; + +typedef void (*nsSpeechDispatcherFunc)(); +struct nsSpeechDispatcherDynamicFunction +{ + const char* functionName; + nsSpeechDispatcherFunc* function; +}; + +namespace mozilla { +namespace dom { + +StaticRefPtr SpeechDispatcherService::sSingleton; + +class SpeechDispatcherVoice +{ +public: + + SpeechDispatcherVoice(const nsAString& aName, const nsAString& aLanguage) + : mName(aName), mLanguage(aLanguage) {} + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SpeechDispatcherVoice) + + // Voice name + nsString mName; + + // Voice language, in BCP-47 syntax + nsString mLanguage; + +private: + ~SpeechDispatcherVoice() {} +}; + + +class SpeechDispatcherCallback final : public nsISpeechTaskCallback +{ +public: + SpeechDispatcherCallback(nsISpeechTask* aTask, SpeechDispatcherService* aService) + : mTask(aTask) + , mService(aService) {} + + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(SpeechDispatcherCallback, nsISpeechTaskCallback) + + NS_DECL_NSISPEECHTASKCALLBACK + + bool OnSpeechEvent(SPDNotificationType state); + +private: + ~SpeechDispatcherCallback() { } + + // This pointer is used to dispatch events + nsCOMPtr mTask; + + // By holding a strong reference to the service we guarantee that it won't be + // destroyed before this runnable. + RefPtr mService; + + TimeStamp mStartTime; +}; + +NS_IMPL_CYCLE_COLLECTION(SpeechDispatcherCallback, mTask); + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechDispatcherCallback) + NS_INTERFACE_MAP_ENTRY(nsISpeechTaskCallback) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechTaskCallback) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechDispatcherCallback) +NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechDispatcherCallback) + +NS_IMETHODIMP +SpeechDispatcherCallback::OnPause() +{ + // XXX: Speech dispatcher does not pause immediately, but waits for the speech + // to reach an index mark so that it could resume from that offset. + // There is no support for word or sentence boundaries, so index marks would + // only occur in explicit SSML marks, and we don't support that yet. + // What in actuality happens, is that if you call spd_pause(), it will speak + // the utterance in its entirety, dispatch an end event, and then put speechd + // in a 'paused' state. Since it is after the utterance ended, we don't get + // that state change, and our speech api is in an unrecoverable state. + // So, since it is useless anyway, I am not implementing pause. + return NS_OK; +} + +NS_IMETHODIMP +SpeechDispatcherCallback::OnResume() +{ + // XXX: Unsupported, see OnPause(). + return NS_OK; +} + +NS_IMETHODIMP +SpeechDispatcherCallback::OnCancel() +{ + if (spd_cancel(mService->mSpeechdClient) < 0) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +NS_IMETHODIMP +SpeechDispatcherCallback::OnVolumeChanged(float aVolume) +{ + // XXX: This currently does not change the volume mid-utterance, but it + // doesn't do anything bad either. So we could put this here with the hopes + // that speechd supports this in the future. + if (spd_set_volume(mService->mSpeechdClient, static_cast(aVolume * 100)) < 0) { + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +bool +SpeechDispatcherCallback::OnSpeechEvent(SPDNotificationType state) +{ + bool remove = false; + + switch (state) { + case SPD_EVENT_BEGIN: + mStartTime = TimeStamp::Now(); + mTask->DispatchStart(); + break; + + case SPD_EVENT_PAUSE: + mTask->DispatchPause((TimeStamp::Now() - mStartTime).ToSeconds(), 0); + break; + + case SPD_EVENT_RESUME: + mTask->DispatchResume((TimeStamp::Now() - mStartTime).ToSeconds(), 0); + break; + + case SPD_EVENT_CANCEL: + case SPD_EVENT_END: + mTask->DispatchEnd((TimeStamp::Now() - mStartTime).ToSeconds(), 0); + remove = true; + break; + + case SPD_EVENT_INDEX_MARK: + // Not yet supported + break; + + default: + break; + } + + return remove; +} + +static void +speechd_cb(size_t msg_id, size_t client_id, SPDNotificationType state) +{ + SpeechDispatcherService* service = SpeechDispatcherService::GetInstance(false); + + if (service) { + NS_DispatchToMainThread( + NS_NewRunnableMethodWithArgs( + service, &SpeechDispatcherService::EventNotify, + static_cast(msg_id), state)); + } +} + + +NS_INTERFACE_MAP_BEGIN(SpeechDispatcherService) + NS_INTERFACE_MAP_ENTRY(nsISpeechService) + NS_INTERFACE_MAP_ENTRY(nsIObserver) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver) +NS_INTERFACE_MAP_END + +NS_IMPL_ADDREF(SpeechDispatcherService) +NS_IMPL_RELEASE(SpeechDispatcherService) + +SpeechDispatcherService::SpeechDispatcherService() + : mInitialized(false) + , mSpeechdClient(nullptr) +{ +} + +void +SpeechDispatcherService::Init() +{ + if (!Preferences::GetBool("media.webspeech.synth.enabled") || + Preferences::GetBool("media.webspeech.synth.test")) { + return; + } + + // While speech dispatcher has a "threaded" mode, only spd_say() is async. + // Since synchronous socket i/o could impact startup time, we do + // initialization in a separate thread. + DebugOnly rv = NS_NewNamedThread("speechd init", + getter_AddRefs(mInitThread)); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + rv = mInitThread->Dispatch( + NS_NewRunnableMethod(this, &SpeechDispatcherService::Setup), NS_DISPATCH_NORMAL); + MOZ_ASSERT(NS_SUCCEEDED(rv)); +} + +SpeechDispatcherService::~SpeechDispatcherService() +{ + if (mInitThread) { + mInitThread->Shutdown(); + } + + if (mSpeechdClient) { + spd_close(mSpeechdClient); + } +} + +void +SpeechDispatcherService::Setup() +{ +#define FUNC(name, type, params) { #name, (nsSpeechDispatcherFunc *)&_##name }, + static const nsSpeechDispatcherDynamicFunction kSpeechDispatcherSymbols[] = { + SPEECHD_FUNCTIONS + }; +#undef FUNC + + MOZ_ASSERT(!mInitialized); + + speechdLib = PR_LoadLibrary("libspeechd.so.2"); + + if (!speechdLib) { + NS_WARNING("Failed to load speechd library"); + return; + } + + for (uint32_t i = 0; i < ArrayLength(kSpeechDispatcherSymbols); i++) { + *kSpeechDispatcherSymbols[i].function = + PR_FindFunctionSymbol(speechdLib, kSpeechDispatcherSymbols[i].functionName); + + if (!*kSpeechDispatcherSymbols[i].function) { + NS_WARNING(nsPrintfCString("Failed to find speechd symbol for'%s'", + kSpeechDispatcherSymbols[i].functionName).get()); + return; + } + } + + mSpeechdClient = spd_open("firefox", "web speech api", "who", SPD_MODE_THREADED); + if (!mSpeechdClient) { + NS_WARNING("Failed to call spd_open"); + return; + } + + // Get all the voices from sapi and register in the SynthVoiceRegistry + SPDVoice** list = spd_list_synthesis_voices(mSpeechdClient); + + mSpeechdClient->callback_begin = speechd_cb; + mSpeechdClient->callback_end = speechd_cb; + mSpeechdClient->callback_cancel = speechd_cb; + mSpeechdClient->callback_pause = speechd_cb; + mSpeechdClient->callback_resume = speechd_cb; + + spd_set_notification_on(mSpeechdClient, SPD_BEGIN); + spd_set_notification_on(mSpeechdClient, SPD_END); + spd_set_notification_on(mSpeechdClient, SPD_CANCEL); + + if (list != NULL) { + for (int i = 0; list[i]; i++) { + nsAutoString uri; + + uri.AssignLiteral(URI_PREFIX); + nsAutoCString name; + NS_EscapeURL(list[i]->name, -1, esc_OnlyNonASCII | esc_AlwaysCopy, name); + uri.Append(NS_ConvertUTF8toUTF16(name));; + uri.AppendLiteral("?"); + + nsAutoCString lang(list[i]->language); + + if (strcmp(list[i]->variant, "none") != 0) { + // In speech dispatcher, the variant will usually be the locale subtag + // with another, non-standard suptag after it. We keep the first one + // and convert it to uppercase. + const char* v = list[i]->variant; + const char* hyphen = strchr(v, '-'); + nsDependentCSubstring variant(v, hyphen ? hyphen - v : strlen(v)); + ToUpperCase(variant); + + // eSpeak uses UK which is not a valid region subtag in BCP47. + if (variant.Equals("UK")) { + variant.AssignLiteral("GB"); + } + + lang.AppendLiteral("-"); + lang.Append(variant); + } + + uri.Append(NS_ConvertUTF8toUTF16(lang)); + + mVoices.Put(uri, new SpeechDispatcherVoice( + NS_ConvertUTF8toUTF16(list[i]->name), + NS_ConvertUTF8toUTF16(lang))); + } + } + + NS_DispatchToMainThread(NS_NewRunnableMethod(this, &SpeechDispatcherService::RegisterVoices)); + + //mInitialized = true; +} + +// private methods + +void +SpeechDispatcherService::RegisterVoices() +{ + nsSynthVoiceRegistry* registry = nsSynthVoiceRegistry::GetInstance(); + for (auto iter = mVoices.Iter(); !iter.Done(); iter.Next()) { + RefPtr& voice = iter.Data(); + + // This service can only speak one utterance at a time, so we set + // aQueuesUtterances to true in order to track global state and schedule + // access to this service. + DebugOnly rv = + registry->AddVoice(this, iter.Key(), voice->mName, voice->mLanguage, + voice->mName.EqualsLiteral("default"), true); + + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to add voice"); + } + + mInitThread->Shutdown(); + mInitThread = nullptr; + + mInitialized = true; +} + +// nsIObserver + +NS_IMETHODIMP +SpeechDispatcherService::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) +{ + return NS_OK; +} + +// nsISpeechService + +// TODO: Support SSML +NS_IMETHODIMP +SpeechDispatcherService::Speak(const nsAString& aText, const nsAString& aUri, + float aVolume, float aRate, float aPitch, + nsISpeechTask* aTask) +{ + if (NS_WARN_IF(!mInitialized)) { + return NS_ERROR_NOT_AVAILABLE; + } + + RefPtr callback = + new SpeechDispatcherCallback(aTask, this); + + bool found = false; + SpeechDispatcherVoice* voice = mVoices.GetWeak(aUri, &found); + + if(NS_WARN_IF(!(found))) { + return NS_ERROR_NOT_AVAILABLE; + } + + spd_set_synthesis_voice(mSpeechdClient, + NS_ConvertUTF16toUTF8(voice->mName).get()); + + // We provide a volume of 0.0 to 1.0, speech-dispatcher expects 0 - 100. + spd_set_volume(mSpeechdClient, static_cast(aVolume * 100)); + + // We provide a rate of 0.1 to 10 with 1 being default. + // speech-dispatcher expects -100 to 100 with 0 being default. + int rate = 0; + + if (aRate > 1) { + rate = static_cast((aRate - 1) * 10); + } else if (aRate <= 1) { + rate = static_cast((aRate - 1) * (100/0.9)); + } + + spd_set_voice_rate(mSpeechdClient, rate); + + // We provide a pitch of 0 to 2 with 1 being the default. + // speech-dispatcher expects -100 to 100 with 0 being default. + spd_set_voice_pitch(mSpeechdClient, static_cast((aPitch - 1) * 100)); + + // The last three parameters don't matter for an indirect service + nsresult rv = aTask->Setup(callback, 0, 0, 0); + + if (NS_FAILED(rv)) { + return rv; + } + + if (aText.Length()) { + int msg_id = spd_say( + mSpeechdClient, SPD_MESSAGE, NS_ConvertUTF16toUTF8(aText).get()); + + if (msg_id < 0) { + return NS_ERROR_FAILURE; + } + + mCallbacks.Put(msg_id, callback); + } else { + // Speech dispatcher does not work well with empty strings. + // In that case, don't send empty string to speechd, + // and just emulate a speechd start and end event. + NS_DispatchToMainThread(NS_NewRunnableMethodWithArgs( + callback, &SpeechDispatcherCallback::OnSpeechEvent, SPD_EVENT_BEGIN)); + + NS_DispatchToMainThread(NS_NewRunnableMethodWithArgs( + callback, &SpeechDispatcherCallback::OnSpeechEvent, SPD_EVENT_END)); + } + + return NS_OK; +} + +NS_IMETHODIMP +SpeechDispatcherService::GetServiceType(SpeechServiceType* aServiceType) +{ + *aServiceType = nsISpeechService::SERVICETYPE_INDIRECT_AUDIO; + return NS_OK; +} + +SpeechDispatcherService* +SpeechDispatcherService::GetInstance(bool create) +{ + if (XRE_GetProcessType() != GeckoProcessType_Default) { + MOZ_ASSERT(false, + "SpeechDispatcherService can only be started on main gecko process"); + return nullptr; + } + + if (!sSingleton && create) { + sSingleton = new SpeechDispatcherService(); + sSingleton->Init(); + } + + return sSingleton; +} + +already_AddRefed +SpeechDispatcherService::GetInstanceForService() +{ + MOZ_ASSERT(NS_IsMainThread()); + RefPtr sapiService = GetInstance(); + return sapiService.forget(); +} + +void +SpeechDispatcherService::EventNotify(uint32_t aMsgId, uint32_t aState) +{ + SpeechDispatcherCallback* callback = mCallbacks.GetWeak(aMsgId); + + if (callback) { + if (callback->OnSpeechEvent((SPDNotificationType)aState)) { + mCallbacks.Remove(aMsgId); + } + } +} + +void +SpeechDispatcherService::Shutdown() +{ + if (!sSingleton) { + return; + } + + sSingleton = nullptr; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h new file mode 100644 index 0000000000..908f5beaec --- /dev/null +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* 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_dom_SpeechDispatcherService_h +#define mozilla_dom_SpeechDispatcherService_h + +#include "mozilla/StaticPtr.h" +#include "nsAutoPtr.h" +#include "nsIObserver.h" +#include "nsISpeechService.h" +#include "nsIThread.h" +#include "nsRefPtrHashtable.h" +#include "nsTArray.h" + +struct SPDConnection; + +namespace mozilla { +namespace dom { + +class SpeechDispatcherCallback; +class SpeechDispatcherVoice; + +class SpeechDispatcherService final : public nsIObserver, + public nsISpeechService +{ + friend class SpeechDispatcherCallback; +public: + NS_DECL_THREADSAFE_ISUPPORTS + NS_DECL_NSIOBSERVER + NS_DECL_NSISPEECHSERVICE + + SpeechDispatcherService(); + + void Init(); + + void Setup(); + + void EventNotify(uint32_t aMsgId, uint32_t aState); + + static SpeechDispatcherService* GetInstance(bool create = true); + static already_AddRefed GetInstanceForService(); + + static void Shutdown(); + + static StaticRefPtr sSingleton; + +private: + virtual ~SpeechDispatcherService(); + + void RegisterVoices(); + + bool mInitialized; + + SPDConnection* mSpeechdClient; + + nsRefPtrHashtable mCallbacks; + + nsCOMPtr mInitThread; + + nsRefPtrHashtable mVoices; +}; + +} // namespace dom +} // namespace mozilla +#endif diff --git a/dom/media/webspeech/synth/speechd/moz.build b/dom/media/webspeech/synth/speechd/moz.build new file mode 100644 index 0000000000..3d8c8c015c --- /dev/null +++ b/dom/media/webspeech/synth/speechd/moz.build @@ -0,0 +1,13 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +UNIFIED_SOURCES += [ + 'SpeechDispatcherModule.cpp', + 'SpeechDispatcherService.cpp' +] +include('/ipc/chromium/chromium-config.mozbuild') + +FINAL_LIBRARY = 'xul' diff --git a/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp b/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp index d9e0935aa8..0b72a4af5b 100644 --- a/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp +++ b/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp @@ -93,6 +93,11 @@ public: return NS_OK; } + NS_IMETHOD OnVolumeChanged(float aVolume) override + { + return NS_OK; + } + private: virtual ~FakeSynthCallback() { } diff --git a/dom/media/webspeech/synth/windows/SapiService.cpp b/dom/media/webspeech/synth/windows/SapiService.cpp index 1a8e9901e5..c1325f4f92 100644 --- a/dom/media/webspeech/synth/windows/SapiService.cpp +++ b/dom/media/webspeech/synth/windows/SapiService.cpp @@ -8,6 +8,7 @@ #include "SapiService.h" #include "nsServiceManagerUtils.h" #include "nsWin32Locale.h" +#include "GeckoProfiler.h" #include "mozilla/dom/nsSynthVoiceRegistry.h" #include "mozilla/dom/nsSpeechTask.h" @@ -76,6 +77,11 @@ SapiCallback::OnPause() if (FAILED(mSapiClient->Pause())) { return NS_ERROR_FAILURE; } + if (!mTask) { + // When calling pause() on child porcess, it may not receive end event + // from chrome process yet. + return NS_ERROR_FAILURE; + } mTask->DispatchPause(GetTickCount() - mStartingTime, mCurrentIndex); return NS_OK; } @@ -86,6 +92,11 @@ SapiCallback::OnResume() if (FAILED(mSapiClient->Resume())) { return NS_ERROR_FAILURE; } + if (!mTask) { + // When calling resume() on child porcess, it may not receive end event + // from chrome process yet. + return NS_ERROR_FAILURE; + } mTask->DispatchResume(GetTickCount() - mStartingTime, mCurrentIndex); return NS_OK; } @@ -103,6 +114,13 @@ SapiCallback::OnCancel() return NS_OK; } +NS_IMETHODIMP +SapiCallback::OnVolumeChanged(float aVolume) +{ + mSapiClient->SetVolume(static_cast(aVolume * 100)); + return NS_OK; +} + void SapiCallback::OnSpeechEvent(const SPEVENT& speechEvent) { @@ -160,6 +178,7 @@ SapiService::SpeechEventCallback(WPARAM aWParam, LPARAM aLParam) NS_INTERFACE_MAP_BEGIN(SapiService) NS_INTERFACE_MAP_ENTRY(nsISpeechService) + NS_INTERFACE_MAP_ENTRY(nsIObserver) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechService) NS_INTERFACE_MAP_END @@ -178,9 +197,12 @@ SapiService::~SapiService() bool SapiService::Init() { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + MOZ_ASSERT(!mInitialized); - if (Preferences::GetBool("media.webspeech.synth.test")) { + if (Preferences::GetBool("media.webspeech.synth.test") || + !Preferences::GetBool("media.webspeech.synth.enabled")) { // When enabled, we shouldn't add OS backend (Bug 1160844) return false; } @@ -357,6 +379,13 @@ SapiService::GetServiceType(SpeechServiceType* aServiceType) return NS_OK; } +NS_IMETHODIMP +SapiService::Observe(nsISupports* aSubject, const char* aTopic, + const char16_t* aData) +{ + return NS_OK; +} + SapiService* SapiService::GetInstance() { diff --git a/dom/media/webspeech/synth/windows/SapiService.h b/dom/media/webspeech/synth/windows/SapiService.h index cba4dab71d..5216ab5653 100644 --- a/dom/media/webspeech/synth/windows/SapiService.h +++ b/dom/media/webspeech/synth/windows/SapiService.h @@ -9,6 +9,7 @@ #include "nsAutoPtr.h" #include "nsISpeechService.h" +#include "nsIObserver.h" #include "nsRefPtrHashtable.h" #include "nsTArray.h" #include "mozilla/StaticPtr.h" @@ -22,10 +23,12 @@ namespace dom { class SapiCallback; class SapiService final : public nsISpeechService + , public nsIObserver { public: NS_DECL_ISUPPORTS NS_DECL_NSISPEECHSERVICE + NS_DECL_NSIOBSERVER SapiService(); bool Init(); diff --git a/dom/mobilemessage/MobileMessageManager.cpp b/dom/mobilemessage/MobileMessageManager.cpp index 3e73c73361..d13b53bcd8 100644 --- a/dom/mobilemessage/MobileMessageManager.cpp +++ b/dom/mobilemessage/MobileMessageManager.cpp @@ -24,6 +24,7 @@ #include "mozilla/dom/ToJSValue.h" #include "mozilla/Preferences.h" #include "mozilla/Services.h" +#include "mozilla/UniquePtr.h" #include "nsIMmsService.h" #include "nsIMobileMessageCallback.h" #include "nsIMobileMessageDatabaseService.h" @@ -424,7 +425,7 @@ MobileMessageManager::GetMessages(const MobileMessageFilter& aFilter, endDate = aFilter.mEndDate.Value(); } - nsAutoArrayPtr ptrNumbers; + UniquePtr ptrNumbers; uint32_t numbersCount = 0; if (!aFilter.mNumbers.IsNull() && aFilter.mNumbers.Value().Length()) { @@ -432,7 +433,7 @@ MobileMessageManager::GetMessages(const MobileMessageFilter& aFilter, uint32_t index; numbersCount = numbers.Length(); - ptrNumbers = new const char16_t* [numbersCount]; + ptrNumbers = MakeUnique(numbersCount); for (index = 0; index < numbersCount; index++) { ptrNumbers[index] = numbers[index].get(); } @@ -464,7 +465,7 @@ MobileMessageManager::GetMessages(const MobileMessageFilter& aFilter, nsCOMPtr continueCallback; nsresult rv = dbService->CreateMessageCursor(hasStartDate, startDate, hasEndDate, endDate, - ptrNumbers, numbersCount, + ptrNumbers.get(), numbersCount, delivery, hasRead, read, hasThreadId, threadId, diff --git a/dom/mobilemessage/ipc/SmsParent.cpp b/dom/mobilemessage/ipc/SmsParent.cpp index f3512c77dd..da5bc4a524 100644 --- a/dom/mobilemessage/ipc/SmsParent.cpp +++ b/dom/mobilemessage/ipc/SmsParent.cpp @@ -22,6 +22,7 @@ #include "mozilla/dom/File.h" #include "mozilla/dom/ToJSValue.h" #include "mozilla/dom/mobilemessage/Constants.h" // For MessageType +#include "mozilla/UniquePtr.h" #include "nsContentUtils.h" #include "nsTArrayHelpers.h" #include "xpcpublic.h" @@ -830,12 +831,12 @@ MobileMessageCursorParent::DoRequest(const CreateMessageCursorRequest& aRequest) const SmsFilterData& filter = aRequest.filter(); const nsTArray& numbers = filter.numbers(); - nsAutoArrayPtr ptrNumbers; + UniquePtr ptrNumbers; uint32_t numbersCount = numbers.Length(); if (numbersCount) { uint32_t index; - ptrNumbers = new const char16_t* [numbersCount]; + ptrNumbers = MakeUnique(numbersCount); for (index = 0; index < numbersCount; index++) { ptrNumbers[index] = numbers[index].get(); } @@ -845,7 +846,7 @@ MobileMessageCursorParent::DoRequest(const CreateMessageCursorRequest& aRequest) filter.startDate(), filter.hasEndDate(), filter.endDate(), - ptrNumbers, numbersCount, + ptrNumbers.get(), numbersCount, filter.delivery(), filter.hasRead(), filter.read(), diff --git a/dom/plugins/base/nsJSNPRuntime.cpp b/dom/plugins/base/nsJSNPRuntime.cpp index 895fb70c46..92ce8a941f 100644 --- a/dom/plugins/base/nsJSNPRuntime.cpp +++ b/dom/plugins/base/nsJSNPRuntime.cpp @@ -1166,8 +1166,7 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JSContext* cx, JS::Handle obj) // Insert the new wrapper into the hashtable, rooting the JSObject. Its // lifetime is now tied to that of the NPObject. - nsJSObjWrapperKey key(obj, npp); - if (!sJSObjWrappers.putNew(key, wrapper)) { + if (!sJSObjWrappers.putNew(nsJSObjWrapperKey(obj, npp), wrapper)) { // Out of memory, free the wrapper we created. _releaseobject(wrapper); return nullptr; @@ -1651,6 +1650,8 @@ NPObjWrapper_Resolve(JSContext* cx, JS::Handle obj, JS::Handle if (JSID_IS_SYMBOL(id)) return true; + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::JS); + NPObject* npobj = GetNPObject(cx, obj); if (!npobj || !npobj->_class || !npobj->_class->hasProperty || @@ -2118,6 +2119,8 @@ static bool NPObjectMember_GetProperty(JSContext *cx, JS::HandleObject obj, JS::HandleId id, JS::MutableHandleValue vp) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + if (JSID_IS_SYMBOL(id)) { JS::RootedSymbol sym(cx, JSID_TO_SYMBOL(id)); if (JS::GetSymbolCode(sym) == JS::SymbolCode::toPrimitive) { diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp index ac54062295..143719c7c7 100644 --- a/dom/plugins/base/nsNPAPIPlugin.cpp +++ b/dom/plugins/base/nsNPAPIPlugin.cpp @@ -405,6 +405,8 @@ nsNPAPIPlugin::RunPluginOOP(const nsPluginTag *aPluginTag) inline PluginLibrary* GetNewPluginLibrary(nsPluginTag *aPluginTag) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + if (!aPluginTag) { return nullptr; } @@ -423,6 +425,7 @@ GetNewPluginLibrary(nsPluginTag *aPluginTag) nsresult nsNPAPIPlugin::CreatePlugin(nsPluginTag *aPluginTag, nsNPAPIPlugin** aResult) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); *aResult = nullptr; if (!aPluginTag) { diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 2a185e3d53..d24f875eb0 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -280,6 +280,7 @@ nsNPAPIPluginInstance::StopTime() nsresult nsNPAPIPluginInstance::Initialize(nsNPAPIPlugin *aPlugin, nsPluginInstanceOwner* aOwner, const nsACString& aMIMEType) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); PLUGIN_LOG(PLUGIN_LOG_NORMAL, ("nsNPAPIPluginInstance::Initialize this=%p\n",this)); NS_ENSURE_ARG_POINTER(aPlugin); @@ -655,6 +656,8 @@ nsresult nsNPAPIPluginInstance::HandleEvent(void* event, int16_t* result, if (RUNNING != mRunning) return NS_OK; + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + if (!event) return NS_ERROR_FAILURE; diff --git a/dom/plugins/base/nsNPAPIPluginStreamListener.cpp b/dom/plugins/base/nsNPAPIPluginStreamListener.cpp index aa59329d6b..61daa1c907 100644 --- a/dom/plugins/base/nsNPAPIPluginStreamListener.cpp +++ b/dom/plugins/base/nsNPAPIPluginStreamListener.cpp @@ -284,6 +284,7 @@ nsNPAPIPluginStreamListener::CallURLNotify(NPReason reason) nsresult nsNPAPIPluginStreamListener::OnStartBinding(nsPluginStreamListenerPeer* streamPeer) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); if (!mInst || !mInst->CanFireNotifications() || mStreamCleanedUp) return NS_ERROR_FAILURE; diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index 1df792cdd5..5db1290bc4 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -1332,6 +1332,7 @@ nsresult nsPluginHost::EnsurePluginLoaded(nsPluginTag* aPluginTag) nsresult nsPluginHost::GetPluginForContentProcess(uint32_t aPluginId, nsNPAPIPlugin** aPlugin) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); MOZ_ASSERT(XRE_IsParentProcess()); // If plugins haven't been scanned yet, do so now @@ -3436,6 +3437,7 @@ nsPluginHost::AddHeadersToChannel(const char *aHeadersData, nsresult nsPluginHost::StopPluginInstance(nsNPAPIPluginInstance* aInstance) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); if (PluginDestructionGuard::DelayDestroy(aInstance)) { return NS_OK; } diff --git a/dom/plugins/base/nsPluginInstanceOwner.cpp b/dom/plugins/base/nsPluginInstanceOwner.cpp index 8ca9db4f24..4567523f75 100644 --- a/dom/plugins/base/nsPluginInstanceOwner.cpp +++ b/dom/plugins/base/nsPluginInstanceOwner.cpp @@ -3590,6 +3590,8 @@ nsPluginInstanceOwner::UpdateWindowVisibility(bool aVisible) void nsPluginInstanceOwner::UpdateDocumentActiveState(bool aIsActive) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + mPluginDocumentActiveState = aIsActive; #ifndef XP_MACOSX UpdateWindowPositionAndClipRect(true); diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 7f28ef5e11..d0d604e97c 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -109,6 +109,7 @@ mozilla::plugins::SetupBridge(uint32_t aPluginId, nsresult* rv, uint32_t* runID) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); if (NS_WARN_IF(!rv) || NS_WARN_IF(!runID)) { return false; } diff --git a/dom/storage/DOMStorageDBThread.cpp b/dom/storage/DOMStorageDBThread.cpp index 7c98119a49..a98e314990 100644 --- a/dom/storage/DOMStorageDBThread.cpp +++ b/dom/storage/DOMStorageDBThread.cpp @@ -116,6 +116,7 @@ DOMStorageDBThread::Shutdown() void DOMStorageDBThread::SyncPreload(DOMStorageCacheBridge* aCache, bool aForceSync) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::STORAGE); if (!aForceSync && aCache->LoadedCount()) { // Preload already started for this cache, just wait for it to finish. // LoadWait will exit after LoadDone on the cache has been called. diff --git a/dom/svg/SVGFEConvolveMatrixElement.cpp b/dom/svg/SVGFEConvolveMatrixElement.cpp index 45faf68c64..2b0b0b62d0 100644 --- a/dom/svg/SVGFEConvolveMatrixElement.cpp +++ b/dom/svg/SVGFEConvolveMatrixElement.cpp @@ -6,6 +6,8 @@ #include "mozilla/dom/SVGFEConvolveMatrixElement.h" #include "mozilla/dom/SVGFEConvolveMatrixElementBinding.h" +#include "mozilla/UniquePtr.h" +#include "mozilla/UniquePtrExtensions.h" #include "DOMSVGAnimatedNumberList.h" #include "nsSVGUtils.h" #include "nsSVGFilterInstance.h" @@ -203,7 +205,7 @@ SVGFEConvolveMatrixElement::GetPrimitiveDescription(nsSVGFilterInstance* aInstan if (orderX > NS_SVG_OFFSCREEN_MAX_DIMENSION || orderY > NS_SVG_OFFSCREEN_MAX_DIMENSION) return failureDescription; - nsAutoArrayPtr kernel(new (fallible) float[orderX * orderY]); + UniquePtr kernel = MakeUniqueFallible(orderX * orderY); if (!kernel) return failureDescription; for (uint32_t i = 0; i < kmLength; i++) { diff --git a/dom/telephony/ipc/TelephonyChild.cpp b/dom/telephony/ipc/TelephonyChild.cpp index 593387f6e5..2355e036c1 100644 --- a/dom/telephony/ipc/TelephonyChild.cpp +++ b/dom/telephony/ipc/TelephonyChild.cpp @@ -7,6 +7,7 @@ #include "TelephonyChild.h" #include "mozilla/dom/telephony/TelephonyDialCallback.h" +#include "mozilla/UniquePtr.h" #include "TelephonyIPCService.h" USING_TELEPHONY_NAMESPACE @@ -212,12 +213,13 @@ TelephonyRequestChild::DoResponse(const DialResponseMMISuccess& aResponse) uint32_t count = info.get_ArrayOfnsString().Length(); const nsTArray& additionalInformation = info.get_ArrayOfnsString(); - nsAutoArrayPtr additionalInfoPtrs(new const char16_t*[count]); + auto additionalInfoPtrs = MakeUnique(count); for (size_t i = 0; i < count; ++i) { additionalInfoPtrs[i] = additionalInformation[i].get(); } - callback->NotifyDialMMISuccessWithStrings(statusMessage, count, additionalInfoPtrs); + callback->NotifyDialMMISuccessWithStrings(statusMessage, count, + additionalInfoPtrs.get()); break; } case AdditionalInformation::TArrayOfnsMobileCallForwardingOptions: { diff --git a/dom/xbl/nsXBLBinding.cpp b/dom/xbl/nsXBLBinding.cpp index 849214cebb..5d01c89d32 100644 --- a/dom/xbl/nsXBLBinding.cpp +++ b/dom/xbl/nsXBLBinding.cpp @@ -872,7 +872,7 @@ GetOrCreateClassObjectMap(JSContext *cx, JS::Handle scope, const char MOZ_ASSERT(scope == xpc::GetXBLScopeOrGlobal(cx, scope)); // First, see if the map is already defined. - JS::Rooted desc(cx); + JS::Rooted desc(cx); if (!JS_GetOwnPropertyDescriptor(cx, scope, mapName, &desc)) { return nullptr; } @@ -1011,7 +1011,7 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, // holder should be class objects. If we don't find the class object, we need // to create and define it. JS::Rooted proto(cx); - JS::Rooted desc(cx); + JS::Rooted desc(cx); if (!JS_GetOwnUCPropertyDescriptor(cx, holder, aClassName.get(), &desc)) { return NS_ERROR_OUT_OF_MEMORY; } @@ -1093,7 +1093,7 @@ nsXBLBinding::ResolveAllFields(JSContext *cx, JS::Handle obj) const bool nsXBLBinding::LookupMember(JSContext* aCx, JS::Handle aId, - JS::MutableHandle aDesc) + JS::MutableHandle aDesc) { // We should never enter this function with a pre-filled property descriptor. MOZ_ASSERT(!aDesc.object()); @@ -1148,7 +1148,7 @@ nsXBLBinding::LookupMember(JSContext* aCx, JS::Handle aId, bool nsXBLBinding::LookupMemberInternal(JSContext* aCx, nsString& aName, JS::Handle aNameAsId, - JS::MutableHandle aDesc, + JS::MutableHandle aDesc, JS::Handle aXBLScope) { // First, see if we have an implementation. If we don't, it means that this diff --git a/dom/xbl/nsXBLBinding.h b/dom/xbl/nsXBLBinding.h index 97a9f50e64..03c23bc597 100644 --- a/dom/xbl/nsXBLBinding.h +++ b/dom/xbl/nsXBLBinding.h @@ -76,7 +76,7 @@ public: * otherwise we don't have untainted data with which to do a proper lookup. */ bool LookupMember(JSContext* aCx, JS::Handle aId, - JS::MutableHandle aDesc); + JS::MutableHandle aDesc); /* * Determines whether the binding has a field with the given name. @@ -92,7 +92,7 @@ protected: */ bool LookupMemberInternal(JSContext* aCx, nsString& aName, JS::Handle aNameAsId, - JS::MutableHandle aDesc, + JS::MutableHandle aDesc, JS::Handle aXBLScope); public: diff --git a/dom/xbl/nsXBLProtoImpl.cpp b/dom/xbl/nsXBLProtoImpl.cpp index 48a30b39ff..3d787f6fa2 100644 --- a/dom/xbl/nsXBLProtoImpl.cpp +++ b/dom/xbl/nsXBLProtoImpl.cpp @@ -102,7 +102,7 @@ nsXBLProtoImpl::InstallImplementation(nsXBLPrototypeBinding* aPrototypeBinding, // weird property holder duplication. const char16_t* className = aPrototypeBinding->ClassName().get(); JS::Rooted propertyHolder(cx); - JS::Rooted existingHolder(cx); + JS::Rooted existingHolder(cx); if (scopeObject != globalObject && !JS_GetOwnUCPropertyDescriptor(cx, scopeObject, className, &existingHolder)) { return NS_ERROR_FAILURE; @@ -271,7 +271,7 @@ nsXBLProtoImpl::CompilePrototypeMembers(nsXBLPrototypeBinding* aBinding) bool nsXBLProtoImpl::LookupMember(JSContext* aCx, nsString& aName, JS::Handle aNameAsId, - JS::MutableHandle aDesc, + JS::MutableHandle aDesc, JS::Handle aClassObject) { for (nsXBLProtoImplMember* m = mMembers; m; m = m->GetNext()) { diff --git a/dom/xbl/nsXBLProtoImpl.h b/dom/xbl/nsXBLProtoImpl.h index e46d6ad690..8b63d156b8 100644 --- a/dom/xbl/nsXBLProtoImpl.h +++ b/dom/xbl/nsXBLProtoImpl.h @@ -50,7 +50,7 @@ public: nsresult CompilePrototypeMembers(nsXBLPrototypeBinding* aBinding); bool LookupMember(JSContext* aCx, nsString& aName, JS::Handle aNameAsId, - JS::MutableHandle aDesc, + JS::MutableHandle aDesc, JS::Handle aClassObject); void SetMemberList(nsXBLProtoImplMember* aMemberList) diff --git a/dom/xslt/base/txList.cpp b/dom/xslt/base/txList.cpp index 0e8201c77d..fa4952ad96 100644 --- a/dom/xslt/base/txList.cpp +++ b/dom/xslt/base/txList.cpp @@ -65,8 +65,6 @@ nsresult txList::insertAfter(void* objPtr, ListItem* refItem) nsresult txList::insertBefore(void* objPtr, ListItem* refItem) { ListItem* item = new ListItem; - NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY); - item->objPtr = objPtr; item->nextItem = 0; item->prevItem = 0; diff --git a/dom/xslt/nsIXSLTProcessorPrivate.idl b/dom/xslt/nsIXSLTProcessorPrivate.idl index d88320cef2..9212f70fd3 100644 --- a/dom/xslt/nsIXSLTProcessorPrivate.idl +++ b/dom/xslt/nsIXSLTProcessorPrivate.idl @@ -5,9 +5,16 @@ #include "nsISupports.idl" -[scriptable, uuid(b8d727f7-67f4-4dc1-a318-ec0c87280816)] +[scriptable, uuid(75d14f5d-293d-4872-8a26-e79268de592f)] interface nsIXSLTProcessorPrivate : nsISupports { + /** + * This needs to be called if the XSLTProcessor is instantiated + * through the XPCOM registry (i.e. using do_createInstance) and the + * stylesheet uses xsl:import/xsl:include or the document() xpath function. + */ + void init(in nsISupports global); + /** * Disables all loading of external documents, such as from * and document() diff --git a/dom/xslt/xpath/txExprLexer.cpp b/dom/xslt/xpath/txExprLexer.cpp index 4927afa0f0..dc1616af07 100644 --- a/dom/xslt/xpath/txExprLexer.cpp +++ b/dom/xslt/xpath/txExprLexer.cpp @@ -361,9 +361,6 @@ txExprLexer::parse(const nsASingleFragmentString& aPattern) // add a endToken to the list newToken = new Token(end, end, Token::END); - if (!newToken) { - return NS_ERROR_OUT_OF_MEMORY; - } addToken(newToken); return NS_OK; diff --git a/dom/xslt/xpath/txExprParser.cpp b/dom/xslt/xpath/txExprParser.cpp index d431802738..f35a0dc474 100644 --- a/dom/xslt/xpath/txExprParser.cpp +++ b/dom/xslt/xpath/txExprParser.cpp @@ -121,8 +121,6 @@ txExprParser::createAVT(const nsSubstring& aAttrValue, else { if (!concat) { concat = new txCoreFunctionCall(txCoreFunctionCall::CONCAT); - NS_ENSURE_TRUE(concat, NS_ERROR_OUT_OF_MEMORY); - rv = concat->addParam(expr.forget()); expr = concat; NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/xslt/xpath/txNodeSet.cpp b/dom/xslt/xpath/txNodeSet.cpp index 8611fd7fb6..a55317e330 100644 --- a/dom/xslt/xpath/txNodeSet.cpp +++ b/dom/xslt/xpath/txNodeSet.cpp @@ -353,7 +353,6 @@ txNodeSet::mark(int32_t aIndex) if (!mMarks) { int32_t length = size(); mMarks = new bool[length]; - NS_ENSURE_TRUE(mMarks, NS_ERROR_OUT_OF_MEMORY); memset(mMarks, 0, length * sizeof(bool)); } if (mDirection == kForward) { diff --git a/dom/xslt/xpath/txNodeSetAdaptor.cpp b/dom/xslt/xpath/txNodeSetAdaptor.cpp index d2d16d5ef5..2656c8ddec 100644 --- a/dom/xslt/xpath/txNodeSetAdaptor.cpp +++ b/dom/xslt/xpath/txNodeSetAdaptor.cpp @@ -26,8 +26,7 @@ txNodeSetAdaptor::Init() if (!mValue) { mValue = new txNodeSet(nullptr); } - - return mValue ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + return NS_OK; } NS_IMETHODIMP diff --git a/dom/xslt/xpath/txResultRecycler.cpp b/dom/xslt/xpath/txResultRecycler.cpp index 0db095001c..774a0345c4 100644 --- a/dom/xslt/xpath/txResultRecycler.cpp +++ b/dom/xslt/xpath/txResultRecycler.cpp @@ -77,7 +77,6 @@ txResultRecycler::getStringResult(StringResult** aResult) { if (mStringResults.isEmpty()) { *aResult = new StringResult(this); - NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); } else { *aResult = static_cast(mStringResults.pop()); @@ -95,7 +94,6 @@ txResultRecycler::getStringResult(const nsAString& aValue, { if (mStringResults.isEmpty()) { *aResult = new StringResult(aValue, this); - NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); } else { StringResult* strRes = @@ -121,7 +119,6 @@ txResultRecycler::getNodeSet(txNodeSet** aResult) { if (mNodeSetResults.isEmpty()) { *aResult = new txNodeSet(this); - NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); } else { *aResult = static_cast(mNodeSetResults.pop()); @@ -137,7 +134,6 @@ txResultRecycler::getNodeSet(txNodeSet* aNodeSet, txNodeSet** aResult) { if (mNodeSetResults.isEmpty()) { *aResult = new txNodeSet(*aNodeSet, this); - NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); } else { *aResult = static_cast(mNodeSetResults.pop()); @@ -154,7 +150,6 @@ txResultRecycler::getNodeSet(const txXPathNode& aNode, txAExprResult** aResult) { if (mNodeSetResults.isEmpty()) { *aResult = new txNodeSet(aNode, this); - NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); } else { txNodeSet* nodes = static_cast(mNodeSetResults.pop()); @@ -172,7 +167,6 @@ txResultRecycler::getNumberResult(double aValue, txAExprResult** aResult) { if (mNumberResults.isEmpty()) { *aResult = new NumberResult(aValue, this); - NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); } else { NumberResult* numRes = diff --git a/dom/xslt/xpath/txXPCOMExtensionFunction.cpp b/dom/xslt/xpath/txXPCOMExtensionFunction.cpp index d38a6a8740..79826fe667 100644 --- a/dom/xslt/xpath/txXPCOMExtensionFunction.cpp +++ b/dom/xslt/xpath/txXPCOMExtensionFunction.cpp @@ -17,8 +17,11 @@ #include "xptcall.h" #include "txXPathObjectAdaptor.h" #include "mozilla/Attributes.h" +#include "mozilla/UniquePtr.h" +#include "nsContentUtils.h" #include "nsIClassInfo.h" #include "nsIInterfaceInfo.h" +#include "js/RootingAPI.h" NS_IMPL_ISUPPORTS(txXPathObjectAdaptor, txIXPathObject) @@ -256,8 +259,7 @@ TX_ResolveFunctionCallXPCOM(const nsCString &aContractID, int32_t aNamespaceID, aName, #endif aState); - - return *aFunction ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + return NS_OK; } txArgumentType @@ -303,16 +305,30 @@ public: : mCount(0) { } + txParamArrayHolder(txParamArrayHolder&& rhs) + : mArray(mozilla::Move(rhs.mArray)) + , mCount(rhs.mCount) + { + rhs.mCount = 0; + } ~txParamArrayHolder(); bool Init(uint8_t aCount); operator nsXPTCVariant*() const { - return mArray; + return mArray.get(); + } + + void trace(JSTracer* trc) { + for (uint8_t i = 0; i < mCount; ++i) { + if (mArray[i].type == nsXPTType::T_JSVAL) { + JS::UnsafeTraceRoot(trc, &mArray[i].val.j, "txParam value"); + } + } } private: - nsAutoArrayPtr mArray; + mozilla::UniquePtr mArray; uint8_t mCount; }; @@ -339,12 +355,12 @@ bool txParamArrayHolder::Init(uint8_t aCount) { mCount = aCount; - mArray = new nsXPTCVariant[mCount]; + mArray = mozilla::MakeUnique(mCount); if (!mArray) { return false; } - memset(mArray, 0, mCount * sizeof(nsXPTCVariant)); + memset(mArray.get(), 0, mCount * sizeof(nsXPTCVariant)); return true; } @@ -368,8 +384,8 @@ txXPCOMExtensionFunctionCall::evaluate(txIEvalContext* aContext, uint8_t paramCount = methodInfo->GetParamCount(); uint8_t inArgs = paramCount - 1; - txParamArrayHolder invokeParams; - if (!invokeParams.Init(paramCount)) { + JS::Rooted invokeParams(nsContentUtils::RootingCxForThread()); + if (!invokeParams.get().Init(paramCount)) { return NS_ERROR_OUT_OF_MEMORY; } @@ -389,11 +405,8 @@ txXPCOMExtensionFunctionCall::evaluate(txIEvalContext* aContext, // Create context wrapper. context = new txFunctionEvaluationContext(aContext, mState); - if (!context) { - return NS_ERROR_OUT_OF_MEMORY; - } - nsXPTCVariant &invokeParam = invokeParams[0]; + nsXPTCVariant &invokeParam = invokeParams.get()[0]; invokeParam.type = paramInfo.GetType(); invokeParam.SetValNeedsCleanup(); NS_ADDREF((txIFunctionEvaluationContext*&)invokeParam.val.p = context); @@ -420,7 +433,7 @@ txXPCOMExtensionFunctionCall::evaluate(txIEvalContext* aContext, return NS_ERROR_FAILURE; } - nsXPTCVariant &invokeParam = invokeParams[i]; + nsXPTCVariant &invokeParam = invokeParams.get()[i]; if (paramInfo.IsOut()) { // We don't support out values. return NS_ERROR_FAILURE; @@ -508,14 +521,10 @@ txXPCOMExtensionFunctionCall::evaluate(txIEvalContext* aContext, return NS_ERROR_FAILURE; } - nsXPTCVariant &returnParam = invokeParams[inArgs]; + nsXPTCVariant &returnParam = invokeParams.get()[inArgs]; returnParam.type = returnInfo.GetType(); if (returnType == eSTRING) { nsString *value = new nsString(); - if (!value) { - return NS_ERROR_FAILURE; - } - returnParam.SetValNeedsCleanup(); returnParam.val.p = value; } @@ -526,7 +535,7 @@ txXPCOMExtensionFunctionCall::evaluate(txIEvalContext* aContext, } } - rv = NS_InvokeByIndex(mHelper, mMethodIndex, paramCount, invokeParams); + rv = NS_InvokeByIndex(mHelper, mMethodIndex, paramCount, invokeParams.get()); // In case someone is holding on to the txFunctionEvaluationContext which // could thus stay alive longer than this function. diff --git a/dom/xslt/xpath/txXPathOptimizer.cpp b/dom/xslt/xpath/txXPathOptimizer.cpp index efe363d466..756dd253d7 100644 --- a/dom/xslt/xpath/txXPathOptimizer.cpp +++ b/dom/xslt/xpath/txXPathOptimizer.cpp @@ -133,8 +133,6 @@ txXPathOptimizer::optimizeStep(Expr* aInExpr, Expr** aOutExpr) *aOutExpr = new txNamedAttributeStep(nameTest->mNamespace, nameTest->mPrefix, nameTest->mLocalName); - NS_ENSURE_TRUE(*aOutExpr, NS_ERROR_OUT_OF_MEMORY); - return NS_OK; // return since we no longer have a step-object. } } @@ -145,8 +143,6 @@ txXPathOptimizer::optimizeStep(Expr* aInExpr, Expr** aOutExpr) !pred->canReturnType(Expr::NUMBER_RESULT) && !pred->isSensitiveTo(Expr::NODESET_CONTEXT)) { txNodeTest* predTest = new txPredicatedNodeTest(step->getNodeTest(), pred); - NS_ENSURE_TRUE(predTest, NS_ERROR_OUT_OF_MEMORY); - step->dropFirst(); step->setNodeTest(predTest); } @@ -252,8 +248,6 @@ txXPathOptimizer::optimizeUnion(Expr* aInExpr, Expr** aOutExpr) // Create a txUnionNodeTest if needed if (!unionTest) { nsAutoPtr owner(unionTest = new txUnionNodeTest); - NS_ENSURE_TRUE(unionTest, NS_ERROR_OUT_OF_MEMORY); - rv = unionTest->addNodeTest(currentStep->getNodeTest()); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/xslt/xslt/txBufferingHandler.cpp b/dom/xslt/xslt/txBufferingHandler.cpp index 42a88b9caa..e1ad24d56f 100644 --- a/dom/xslt/xslt/txBufferingHandler.cpp +++ b/dom/xslt/xslt/txBufferingHandler.cpp @@ -204,8 +204,6 @@ txBufferingHandler::attribute(nsIAtom* aPrefix, nsIAtom* aLocalName, new txAttributeAtomTransaction(aPrefix, aLocalName, aLowercaseLocalName, aNsID, aValue); - NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); - return mBuffer->addTransaction(transaction); } @@ -222,8 +220,6 @@ txBufferingHandler::attribute(nsIAtom* aPrefix, const nsSubstring& aLocalName, txOutputTransaction* transaction = new txAttributeTransaction(aPrefix, aLocalName, aNsID, aValue); - NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); - return mBuffer->addTransaction(transaction); } @@ -247,8 +243,6 @@ txBufferingHandler::characters(const nsSubstring& aData, bool aDOE) } transaction = new txCharacterTransaction(type, aData.Length()); - NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); - mBuffer->mStringValue.Append(aData); return mBuffer->addTransaction(transaction); } @@ -261,8 +255,6 @@ txBufferingHandler::comment(const nsString& aData) mCanAddAttribute = false; txOutputTransaction* transaction = new txCommentTransaction(aData); - NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); - return mBuffer->addTransaction(transaction); } @@ -273,8 +265,6 @@ txBufferingHandler::endDocument(nsresult aResult) txOutputTransaction* transaction = new txOutputTransaction(txOutputTransaction::eEndDocumentTransaction); - NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); - return mBuffer->addTransaction(transaction); } @@ -287,8 +277,6 @@ txBufferingHandler::endElement() txOutputTransaction* transaction = new txOutputTransaction(txOutputTransaction::eEndElementTransaction); - NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); - return mBuffer->addTransaction(transaction); } @@ -302,8 +290,6 @@ txBufferingHandler::processingInstruction(const nsString& aTarget, txOutputTransaction* transaction = new txPITransaction(aTarget, aData); - NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); - return mBuffer->addTransaction(transaction); } @@ -314,8 +300,6 @@ txBufferingHandler::startDocument() txOutputTransaction* transaction = new txOutputTransaction(txOutputTransaction::eStartDocumentTransaction); - NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); - return mBuffer->addTransaction(transaction); } @@ -331,8 +315,6 @@ txBufferingHandler::startElement(nsIAtom* aPrefix, nsIAtom* aLocalName, txOutputTransaction* transaction = new txStartElementAtomTransaction(aPrefix, aLocalName, aLowercaseLocalName, aNsID); - NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); - return mBuffer->addTransaction(transaction); } @@ -347,8 +329,6 @@ txBufferingHandler::startElement(nsIAtom* aPrefix, txOutputTransaction* transaction = new txStartElementTransaction(aPrefix, aLocalName, aNsID); - NS_ENSURE_TRUE(transaction, NS_ERROR_OUT_OF_MEMORY); - return mBuffer->addTransaction(transaction); } diff --git a/dom/xslt/xslt/txDocumentFunctionCall.cpp b/dom/xslt/xslt/txDocumentFunctionCall.cpp index 3ea7a83b24..2a35f7ff7c 100644 --- a/dom/xslt/xslt/txDocumentFunctionCall.cpp +++ b/dom/xslt/xslt/txDocumentFunctionCall.cpp @@ -13,13 +13,16 @@ #include "txXSLTFunctions.h" #include "txExecutionState.h" #include "txURIUtils.h" +#include "nsIURI.h" /* * Creates a new DocumentFunctionCall. */ -DocumentFunctionCall::DocumentFunctionCall(const nsAString& aBaseURI) - : mBaseURI(aBaseURI) +DocumentFunctionCall::DocumentFunctionCall(nsIURI* aBaseURI) { + nsCString spec; + aBaseURI->GetSpec(spec); + mBaseURI = NS_ConvertUTF8toUTF16(spec); } static void diff --git a/dom/xslt/xslt/txEXSLTFunctions.cpp b/dom/xslt/xslt/txEXSLTFunctions.cpp index c643caf125..fb19f1a1d2 100644 --- a/dom/xslt/xslt/txEXSLTFunctions.cpp +++ b/dom/xslt/xslt/txEXSLTFunctions.cpp @@ -708,8 +708,7 @@ TX_ConstructEXSLTFunction(nsIAtom *aName, if (aName == *desc.mName && aNamespaceID == desc.mNamespaceID) { *aResult = new txEXSLTFunctionCall( static_cast(i)); - - return *aResult ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + return NS_OK; } } diff --git a/dom/xslt/xslt/txExecutionState.cpp b/dom/xslt/xslt/txExecutionState.cpp index f92396090f..44139ef34e 100644 --- a/dom/xslt/xslt/txExecutionState.cpp +++ b/dom/xslt/xslt/txExecutionState.cpp @@ -103,8 +103,6 @@ txExecutionState::init(const txXPathNode& aNode, // Set up initial context mEvalContext = new txSingleNodeContext(aNode, this); - NS_ENSURE_TRUE(mEvalContext, NS_ERROR_OUT_OF_MEMORY); - mInitialEvalContext = mEvalContext; // Set up output and result-handler @@ -129,7 +127,6 @@ txExecutionState::init(const txXPathNode& aNode, // The actual value here doesn't really matter since noone should use this // value. But lets put something errorlike in just in case mGlobalVarPlaceholderValue = new StringResult(NS_LITERAL_STRING("Error"), nullptr); - NS_ENSURE_TRUE(mGlobalVarPlaceholderValue, NS_ERROR_OUT_OF_MEMORY); // Initiate first instruction. This has to be done last since findTemplate // might use us. @@ -516,7 +513,6 @@ txExecutionState::bindVariable(const txExpandedName& aName, { if (!mLocalVariables) { mLocalVariables = new txVariableMap; - NS_ENSURE_TRUE(mLocalVariables, NS_ERROR_OUT_OF_MEMORY); } return mLocalVariables->bindVariable(aName, aValue); } diff --git a/dom/xslt/xslt/txFormatNumberFunctionCall.cpp b/dom/xslt/xslt/txFormatNumberFunctionCall.cpp index e51ac3f259..674fb553ce 100644 --- a/dom/xslt/xslt/txFormatNumberFunctionCall.cpp +++ b/dom/xslt/xslt/txFormatNumberFunctionCall.cpp @@ -281,8 +281,6 @@ txFormatNumberFunctionCall::evaluate(txIEvalContext* aContext, bufsize = 1 + 30; char* buf = new char[bufsize]; - NS_ENSURE_TRUE(buf, NS_ERROR_OUT_OF_MEMORY); - int bufIntDigits, sign; char* endp; PR_dtoa(value, 0, 0, &bufIntDigits, &sign, &endp, buf, bufsize-1); diff --git a/dom/xslt/xslt/txInstructions.cpp b/dom/xslt/xslt/txInstructions.cpp index 7ad789a9c7..56676fc390 100644 --- a/dom/xslt/xslt/txInstructions.cpp +++ b/dom/xslt/xslt/txInstructions.cpp @@ -699,8 +699,6 @@ nsresult txPushRTFHandler::execute(txExecutionState& aEs) { txAXMLEventHandler* handler = new txRtfHandler; - NS_ENSURE_TRUE(handler, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aEs.pushResultHandler(handler); if (NS_FAILED(rv)) { delete handler; @@ -719,8 +717,6 @@ nsresult txPushStringHandler::execute(txExecutionState& aEs) { txAXMLEventHandler* handler = new txTextHandler(mOnlyText); - NS_ENSURE_TRUE(handler, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aEs.pushResultHandler(handler); if (NS_FAILED(rv)) { delete handler; diff --git a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp index dde45ac1d9..2e4768fb3d 100644 --- a/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp +++ b/dom/xslt/xslt/txMozillaStylesheetCompiler.cpp @@ -39,6 +39,7 @@ #include "mozilla/Attributes.h" #include "mozilla/dom/Element.h" #include "mozilla/dom/EncodingUtils.h" +#include "mozilla/UniquePtr.h" using namespace mozilla; using mozilla::dom::EncodingUtils; @@ -256,6 +257,16 @@ txStylesheetSink::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext) nsCOMPtr channel = do_QueryInterface(aRequest); + nsCOMPtr channelPrincipal; + nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal( + channel, getter_AddRefs(channelPrincipal)); + mCompiler->setPrincipal(channelPrincipal); + + nsCOMPtr baseURI; + nsresult rv = NS_GetFinalChannelURI(channel, getter_AddRefs(baseURI)); + NS_ENSURE_SUCCESS(rv, rv); + mCompiler->setBaseURI(baseURI); + // check channel's charset... nsAutoCString charsetVal; nsAutoCString charset; @@ -374,9 +385,8 @@ public: TX_DECL_ACOMPILEOBSERVER NS_INLINE_DECL_REFCOUNTING(txCompileObserver) - nsresult startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler, - nsIPrincipal* aSourcePrincipal, - ReferrerPolicy aReferrerPolicy); + nsresult startLoad(nsIURI* aUri, nsIPrincipal* aSourcePrincipal, + txStylesheetCompiler* aCompiler); private: RefPtr mProcessor; @@ -399,30 +409,15 @@ txCompileObserver::txCompileObserver(txMozillaXSLTProcessor* aProcessor, } nsresult -txCompileObserver::loadURI(const nsAString& aUri, - const nsAString& aReferrerUri, - ReferrerPolicy aReferrerPolicy, +txCompileObserver::loadURI(nsIURI* aUri, + nsIPrincipal* aReferrerPrincipal, txStylesheetCompiler* aCompiler) { - if (mProcessor->IsLoadDisabled()) { + if (mProcessor->IsLoadDisabled() || !mLoaderDocument) { return NS_ERROR_XSLT_LOAD_BLOCKED_ERROR; } - nsCOMPtr uri; - nsresult rv = NS_NewURI(getter_AddRefs(uri), aUri); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr referrerUri; - rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr referrerPrincipal; - rv = nsContentUtils::GetSecurityManager()-> - GetSimpleCodebasePrincipal(referrerUri, - getter_AddRefs(referrerPrincipal)); - NS_ENSURE_SUCCESS(rv, rv); - - return startLoad(uri, aCompiler, referrerPrincipal, aReferrerPolicy); + return startLoad(aUri, aReferrerPrincipal, aCompiler); } void @@ -440,10 +435,11 @@ txCompileObserver::onDoneCompiling(txStylesheetCompiler* aCompiler, } nsresult -txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler, - nsIPrincipal* aReferrerPrincipal, - ReferrerPolicy aReferrerPolicy) +txCompileObserver::startLoad(nsIURI* aUri, nsIPrincipal* aReferrerPrincipal, + txStylesheetCompiler* aCompiler) { + MOZ_ASSERT(aReferrerPrincipal); + nsCOMPtr loadGroup = mLoaderDocument->GetDocumentLoadGroup(); if (!loadGroup) { return NS_ERROR_FAILURE; @@ -472,7 +468,8 @@ txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler, nsCOMPtr referrerURI; aReferrerPrincipal->GetURI(getter_AddRefs(referrerURI)); if (referrerURI) { - httpChannel->SetReferrerWithPolicy(referrerURI, aReferrerPolicy); + httpChannel->SetReferrerWithPolicy(referrerURI, + mLoaderDocument->GetReferrerPolicy()); } } @@ -480,7 +477,6 @@ txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler, NS_ENSURE_SUCCESS(rv, rv); RefPtr sink = new txStylesheetSink(aCompiler, parser); - NS_ENSURE_TRUE(sink, NS_ERROR_OUT_OF_MEMORY); channel->SetNotificationCallbacks(sink); @@ -493,24 +489,26 @@ txCompileObserver::startLoad(nsIURI* aUri, txStylesheetCompiler* aCompiler, nsresult TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor, - nsIDocument* aLoaderDocument, ReferrerPolicy aReferrerPolicy) + nsIDocument* aLoaderDocument) { - nsIPrincipal* principal = aLoaderDocument->NodePrincipal(); - - nsAutoCString spec; - aUri->GetSpec(spec); - MOZ_LOG(txLog::xslt, LogLevel::Info, ("TX_LoadSheet: %s\n", spec.get())); + if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Info)) { + nsAutoCString spec; + aUri->GetSpec(spec); + MOZ_LOG(txLog::xslt, LogLevel::Info, + ("TX_LoadSheet: %s\n", spec.get())); + } RefPtr observer = new txCompileObserver(aProcessor, aLoaderDocument); - NS_ENSURE_TRUE(observer, NS_ERROR_OUT_OF_MEMORY); + + nsAutoCString fragment; + aUri->GetRef(fragment); RefPtr compiler = - new txStylesheetCompiler(NS_ConvertUTF8toUTF16(spec), aReferrerPolicy, - observer); - NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY); + new txStylesheetCompiler(NS_ConvertUTF8toUTF16(fragment), observer); - return observer->startLoad(aUri, compiler, principal, aReferrerPolicy); + return observer->startLoad(aUri, aLoaderDocument->NodePrincipal(), + compiler); } /** @@ -526,11 +524,9 @@ handleNode(nsINode* aNode, txStylesheetCompiler* aCompiler) dom::Element* element = aNode->AsElement(); uint32_t attsCount = element->GetAttrCount(); - nsAutoArrayPtr atts; + UniquePtr atts; if (attsCount > 0) { - atts = new txStylesheetAttr[attsCount]; - NS_ENSURE_TRUE(atts, NS_ERROR_OUT_OF_MEMORY); - + atts = MakeUnique(attsCount); uint32_t counter; for (counter = 0; counter < attsCount; ++counter) { txStylesheetAttr& att = atts[counter]; @@ -546,7 +542,7 @@ handleNode(nsINode* aNode, txStylesheetCompiler* aCompiler) rv = aCompiler->startElement(ni->NamespaceID(), ni->NameAtom(), - ni->GetPrefixAtom(), atts, + ni->GetPrefixAtom(), atts.get(), attsCount); NS_ENSURE_SUCCESS(rv, rv); @@ -586,7 +582,11 @@ handleNode(nsINode* aNode, txStylesheetCompiler* aCompiler) class txSyncCompileObserver final : public txACompileObserver { public: - explicit txSyncCompileObserver(txMozillaXSLTProcessor* aProcessor); + explicit txSyncCompileObserver(txMozillaXSLTProcessor* aProcessor, + nsIDocument* aLoaderDocument) + : mProcessor(aProcessor), + mLoaderDocument(aLoaderDocument) + {} TX_DECL_ACOMPILEOBSERVER NS_INLINE_DECL_REFCOUNTING(txSyncCompileObserver) @@ -598,60 +598,43 @@ private: } RefPtr mProcessor; + nsCOMPtr mLoaderDocument; }; -txSyncCompileObserver::txSyncCompileObserver(txMozillaXSLTProcessor* aProcessor) - : mProcessor(aProcessor) -{ -} - nsresult -txSyncCompileObserver::loadURI(const nsAString& aUri, - const nsAString& aReferrerUri, - ReferrerPolicy aReferrerPolicy, +txSyncCompileObserver::loadURI(nsIURI* aUri, + nsIPrincipal* aReferrerPrincipal, txStylesheetCompiler* aCompiler) { - if (mProcessor->IsLoadDisabled()) { + MOZ_ASSERT(aReferrerPrincipal); + + if (mProcessor->IsLoadDisabled() || !mLoaderDocument) { return NS_ERROR_XSLT_LOAD_BLOCKED_ERROR; } - nsCOMPtr uri; - nsresult rv = NS_NewURI(getter_AddRefs(uri), aUri); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr referrerUri; - rv = NS_NewURI(getter_AddRefs(referrerUri), aReferrerUri); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr referrerPrincipal; - rv = nsContentUtils::GetSecurityManager()-> - GetSimpleCodebasePrincipal(referrerUri, - getter_AddRefs(referrerPrincipal)); - NS_ENSURE_SUCCESS(rv, rv); - - // This is probably called by js, a loadGroup for the channel doesn't - // make sense. - nsCOMPtr source; - if (mProcessor) { - source = - do_QueryInterface(mProcessor->GetSourceContentModel()); - } - nsAutoSyncOperation sync(source ? source->OwnerDoc() : nullptr); + nsAutoSyncOperation sync(mLoaderDocument); nsCOMPtr document; - rv = nsSyncLoadService::LoadDocument(uri, nsIContentPolicy::TYPE_XSLT, - referrerPrincipal, - nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS, - nullptr, false, - aReferrerPolicy, - getter_AddRefs(document)); + nsCOMPtr loadGroup = mLoaderDocument->GetDocumentLoadGroup(); + nsresult rv = + nsSyncLoadService::LoadDocument(aUri, + nsIContentPolicy::TYPE_XSLT, + aReferrerPrincipal, + nsILoadInfo::SEC_REQUIRE_CORS_DATA_INHERITS, + loadGroup, + false, + mLoaderDocument->GetReferrerPolicy(), + getter_AddRefs(document)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr doc = do_QueryInterface(document); + nsCOMPtr baseURI = doc->GetBaseURI(); + aCompiler->setBaseURI(baseURI); + aCompiler->setPrincipal(doc->NodePrincipal()); rv = handleNode(doc, aCompiler); if (NS_FAILED(rv)) { nsAutoCString spec; - uri->GetSpec(spec); + aUri->GetSpec(spec); aCompiler->cancel(rv, nullptr, NS_ConvertUTF8toUTF16(spec).get()); return rv; } @@ -668,46 +651,20 @@ void txSyncCompileObserver::onDoneCompiling(txStylesheetCompiler* aCompiler, } nsresult -TX_CompileStylesheet(nsINode* aNode, txMozillaXSLTProcessor* aProcessor, +TX_CompileStylesheet(nsINode* aNode, + nsIDocument* aLoaderDocument, + txMozillaXSLTProcessor* aProcessor, txStylesheet** aStylesheet) { - // If we move GetBaseURI to nsINode this can be simplified. - nsCOMPtr doc = aNode->OwnerDoc(); - - nsCOMPtr uri; - if (aNode->IsNodeOfType(nsINode::eCONTENT)) { - uri = static_cast(aNode)->GetBaseURI(); - } - else { - NS_ASSERTION(aNode->IsNodeOfType(nsINode::eDOCUMENT), "not a doc"); - uri = static_cast(aNode)->GetBaseURI(); - } - NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); - - nsAutoCString spec; - uri->GetSpec(spec); - NS_ConvertUTF8toUTF16 baseURI(spec); - - nsIURI* docUri = doc->GetDocumentURI(); - NS_ENSURE_TRUE(docUri, NS_ERROR_FAILURE); - - // We need to remove the ref, a URI with a ref would mean that we have an - // embedded stylesheet. - docUri->CloneIgnoringRef(getter_AddRefs(uri)); - NS_ENSURE_TRUE(uri, NS_ERROR_FAILURE); - - uri->GetSpec(spec); - NS_ConvertUTF8toUTF16 stylesheetURI(spec); - RefPtr obs = - new txSyncCompileObserver(aProcessor); - NS_ENSURE_TRUE(obs, NS_ERROR_OUT_OF_MEMORY); + new txSyncCompileObserver(aProcessor, aLoaderDocument); RefPtr compiler = - new txStylesheetCompiler(stylesheetURI, doc->GetReferrerPolicy(), obs); - NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY); + new txStylesheetCompiler(EmptyString(), obs); + nsCOMPtr baseURI = aNode->GetBaseURI(); compiler->setBaseURI(baseURI); + compiler->setPrincipal(aNode->NodePrincipal()); nsresult rv = handleNode(aNode, compiler); if (NS_FAILED(rv)) { diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp index dfc02a8209..d70473a341 100644 --- a/dom/xslt/xslt/txMozillaXSLTProcessor.cpp +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.cpp @@ -357,6 +357,20 @@ txMozillaXSLTProcessor::txMozillaXSLTProcessor(nsISupports* aOwner) { } +NS_IMETHODIMP +txMozillaXSLTProcessor::Init(nsISupports* aOwner) +{ + mOwner = aOwner; + if (nsCOMPtr win = do_QueryInterface(aOwner)) { + if (win->IsOuterWindow()) { + // Must be bound to inner window, innerize if necessary. + mOwner = win->GetCurrentInnerWindow(); + } + } + + return NS_OK; +} + txMozillaXSLTProcessor::~txMozillaXSLTProcessor() { if (mStylesheetDocument) { @@ -512,7 +526,6 @@ txMozillaXSLTProcessor::AddXSLTParam(const nsString& aName, } else { value = new StringResult(aValue, nullptr); - NS_ENSURE_TRUE(value, NS_ERROR_OUT_OF_MEMORY); } nsCOMPtr name = do_GetAtom(aName); @@ -530,8 +543,6 @@ txMozillaXSLTProcessor::AddXSLTParam(const nsString& aName, } var = new txVariable(value); - NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY); - return mVariables.add(varName, var); } @@ -570,12 +581,7 @@ txMozillaXSLTProcessor::DoTransform() NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr event = new nsTransformBlockerEvent(this); - if (!event) { - return NS_ERROR_OUT_OF_MEMORY; - } - document->BlockOnload(); - rv = NS_DispatchToCurrentThread(event); if (NS_FAILED(rv)) { // XXX Maybe we should just display the source document in this case? @@ -606,7 +612,7 @@ txMozillaXSLTProcessor::ImportStylesheet(nsIDOMNode *aStyle) styleNode->IsNodeOfType(nsINode::eDOCUMENT)), NS_ERROR_INVALID_ARG); - nsresult rv = TX_CompileStylesheet(styleNode, this, + nsresult rv = TX_CompileStylesheet(styleNode, getLoaderDoc(), this, getter_AddRefs(mStylesheet)); // XXX set up exception context, bug 204658 NS_ENSURE_SUCCESS(rv, rv); @@ -1044,12 +1050,7 @@ NS_IMETHODIMP txMozillaXSLTProcessor::LoadStyleSheet(nsIURI* aUri, nsIDocument* aLoaderDocument) { - mozilla::net::ReferrerPolicy refpol = mozilla::net::RP_Default; - if (mStylesheetDocument) { - refpol = mStylesheetDocument->GetReferrerPolicy(); - } - - nsresult rv = TX_LoadSheet(aUri, this, aLoaderDocument, refpol); + nsresult rv = TX_LoadSheet(aUri, this, aLoaderDocument); if (NS_FAILED(rv) && mObserver) { // This is most likely a network or security error, just // use the uri as context. @@ -1206,6 +1207,24 @@ txMozillaXSLTProcessor::notifyError() mObserver->OnTransformDone(mTransformResult, document); } +nsIDocument* +txMozillaXSLTProcessor::getLoaderDoc() +{ + if (mOwner) { + nsCOMPtr win = do_QueryInterface(mOwner); + if (win) { + return win->GetExtantDoc(); + } + } + + if (mSource) { + nsCOMPtr node = do_QueryInterface(mSource); + return node->OwnerDoc(); + } + + return nullptr; +} + nsresult txMozillaXSLTProcessor::ensureStylesheet() { @@ -1220,7 +1239,8 @@ txMozillaXSLTProcessor::ensureStylesheet() style = mStylesheetDocument; } - return TX_CompileStylesheet(style, this, getter_AddRefs(mStylesheet)); + return TX_CompileStylesheet(style, getLoaderDoc(), this, + getter_AddRefs(mStylesheet)); } void @@ -1414,8 +1434,6 @@ txVariable::Convert(nsIVariant *aValue, txAExprResult** aResult) NS_ENSURE_SUCCESS(rv, rv); *aResult = new NumberResult(value, nullptr); - NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); - NS_ADDREF(*aResult); return NS_OK; @@ -1429,8 +1447,6 @@ txVariable::Convert(nsIVariant *aValue, txAExprResult** aResult) NS_ENSURE_SUCCESS(rv, rv); *aResult = new BooleanResult(value); - NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); - NS_ADDREF(*aResult); return NS_OK; @@ -1453,8 +1469,6 @@ txVariable::Convert(nsIVariant *aValue, txAExprResult** aResult) NS_ENSURE_SUCCESS(rv, rv); *aResult = new StringResult(value, nullptr); - NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); - NS_ADDREF(*aResult); return NS_OK; @@ -1537,10 +1551,6 @@ txVariable::Convert(nsIVariant *aValue, txAExprResult** aResult) NS_ENSURE_TRUE(value.init(cx, str), NS_ERROR_FAILURE); *aResult = new StringResult(value, nullptr); - if (!*aResult) { - return NS_ERROR_OUT_OF_MEMORY; - } - NS_ADDREF(*aResult); return NS_OK; diff --git a/dom/xslt/xslt/txMozillaXSLTProcessor.h b/dom/xslt/xslt/txMozillaXSLTProcessor.h index 6fa2ab1338..1cf381a873 100644 --- a/dom/xslt/xslt/txMozillaXSLTProcessor.h +++ b/dom/xslt/xslt/txMozillaXSLTProcessor.h @@ -166,6 +166,8 @@ private: void notifyError(); nsresult ensureStylesheet(); + nsIDocument* getLoaderDoc(); + nsCOMPtr mOwner; RefPtr mStylesheet; @@ -185,10 +187,10 @@ private: }; extern nsresult TX_LoadSheet(nsIURI* aUri, txMozillaXSLTProcessor* aProcessor, - nsIDocument* aLoaderDocument, - mozilla::net::ReferrerPolicy aReferrerPolicy); + nsIDocument* aLoaderDocument); extern nsresult TX_CompileStylesheet(nsINode* aNode, + nsIDocument* aLoaderDocument, txMozillaXSLTProcessor* aProcessor, txStylesheet** aStylesheet); diff --git a/dom/xslt/xslt/txNodeSorter.cpp b/dom/xslt/xslt/txNodeSorter.cpp index 68881f6f30..cf1d61f6d3 100644 --- a/dom/xslt/xslt/txNodeSorter.cpp +++ b/dom/xslt/xslt/txNodeSorter.cpp @@ -37,7 +37,6 @@ txNodeSorter::addSortElement(Expr* aSelectExpr, Expr* aLangExpr, Expr* aCaseOrderExpr, txIEvalContext* aContext) { nsAutoPtr key(new SortKey); - NS_ENSURE_TRUE(key, NS_ERROR_OUT_OF_MEMORY); nsresult rv = NS_OK; // Select @@ -98,12 +97,10 @@ txNodeSorter::addSortElement(Expr* aSelectExpr, Expr* aLangExpr, key->mComparator = new txResultStringComparator(ascending, upperFirst, lang); - NS_ENSURE_TRUE(key->mComparator, NS_ERROR_OUT_OF_MEMORY); } else if (TX_StringEqualsAtom(dataType, nsGkAtoms::number)) { // Number comparator key->mComparator = new txResultNumberComparator(ascending); - NS_ENSURE_TRUE(key->mComparator, NS_ERROR_OUT_OF_MEMORY); } else { // XXX ErrorReport: unknown data-type diff --git a/dom/xslt/xslt/txPatternParser.cpp b/dom/xslt/xslt/txPatternParser.cpp index 342b1fc91a..5dd6e0f491 100644 --- a/dom/xslt/xslt/txPatternParser.cpp +++ b/dom/xslt/xslt/txPatternParser.cpp @@ -63,10 +63,6 @@ nsresult txPatternParser::createUnionPattern(txExprLexer& aLexer, } txUnionPattern* unionPattern = new txUnionPattern(); - if (!unionPattern) { - delete locPath; - return NS_ERROR_OUT_OF_MEMORY; - } rv = unionPattern->addPattern(locPath); #if 0 // XXX addPattern can't fail yet, it doesn't check for mem if (NS_FAILED(rv)) { @@ -127,8 +123,7 @@ nsresult txPatternParser::createLocPathPattern(txExprLexer& aLexer, if (aLexer.peek()->mType == Token::END || aLexer.peek()->mType == Token::UNION_OP) { aPattern = new txRootPattern(); - - return aPattern ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + return NS_OK; } break; case Token::FUNCTION_NAME_AND_PAREN: @@ -163,19 +158,8 @@ nsresult txPatternParser::createLocPathPattern(txExprLexer& aLexer, } pathPattern = new txLocPathPattern(); - if (!pathPattern) { - delete stepPattern; - return NS_ERROR_OUT_OF_MEMORY; - } - if (isAbsolute) { txRootPattern* root = new txRootPattern(); - if (!root) { - delete stepPattern; - delete pathPattern; - return NS_ERROR_OUT_OF_MEMORY; - } - #ifdef TX_TO_STRING root->setSerialize(false); #endif @@ -229,7 +213,7 @@ nsresult txPatternParser::createIdPattern(txExprLexer& aLexer, if (aLexer.nextToken()->mType != Token::R_PAREN) return NS_ERROR_XPATH_PARSE_FAILURE; aPattern = new txIdPattern(value); - return aPattern ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + return NS_OK; } nsresult txPatternParser::createKeyPattern(txExprLexer& aLexer, @@ -263,8 +247,7 @@ nsresult txPatternParser::createKeyPattern(txExprLexer& aLexer, return rv; aPattern = new txKeyPattern(prefix, localName, namespaceID, value); - - return aPattern ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + return NS_OK; } nsresult txPatternParser::createStepPattern(txExprLexer& aLexer, @@ -308,9 +291,6 @@ nsresult txPatternParser::createStepPattern(txExprLexer& aLexer, (uint16_t)txXPathNodeType::ATTRIBUTE_NODE : (uint16_t)txXPathNodeType::ELEMENT_NODE; nodeTest = new txNameTest(prefix, lName, nspace, nodeType); - if (!nodeTest) { - return NS_ERROR_OUT_OF_MEMORY; - } } else { rv = createNodeTypeTest(aLexer, &nodeTest); @@ -318,11 +298,6 @@ nsresult txPatternParser::createStepPattern(txExprLexer& aLexer, } nsAutoPtr step(new txStepPattern(nodeTest, isAttr)); - if (!step) { - delete nodeTest; - return NS_ERROR_OUT_OF_MEMORY; - } - rv = parsePredicates(step, aLexer, aContext); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/xslt/xslt/txRtfHandler.cpp b/dom/xslt/xslt/txRtfHandler.cpp index 1b3d12822b..3c73e676ee 100644 --- a/dom/xslt/xslt/txRtfHandler.cpp +++ b/dom/xslt/xslt/txRtfHandler.cpp @@ -62,10 +62,7 @@ nsresult txRtfHandler::getAsRTF(txAExprResult** aResult) { *aResult = new txResultTreeFragment(Move(mBuffer)); - NS_ENSURE_TRUE(*aResult, NS_ERROR_OUT_OF_MEMORY); - NS_ADDREF(*aResult); - return NS_OK; } diff --git a/dom/xslt/xslt/txStylesheet.cpp b/dom/xslt/xslt/txStylesheet.cpp index 1c29ecd15c..b680da01f9 100644 --- a/dom/xslt/xslt/txStylesheet.cpp +++ b/dom/xslt/xslt/txStylesheet.cpp @@ -28,59 +28,40 @@ nsresult txStylesheet::init() { mRootFrame = new ImportFrame; - NS_ENSURE_TRUE(mRootFrame, NS_ERROR_OUT_OF_MEMORY); // Create default templates // element/root template mContainerTemplate = new txPushParams; - NS_ENSURE_TRUE(mContainerTemplate, NS_ERROR_OUT_OF_MEMORY); nsAutoPtr nt(new txNodeTypeTest(txNodeTypeTest::NODE_TYPE)); - NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY); - nsAutoPtr nodeExpr(new LocationStep(nt, LocationStep::CHILD_AXIS)); - NS_ENSURE_TRUE(nodeExpr, NS_ERROR_OUT_OF_MEMORY); - nt.forget(); txPushNewContext* pushContext = new txPushNewContext(Move(nodeExpr)); mContainerTemplate->mNext = pushContext; - NS_ENSURE_TRUE(pushContext, NS_ERROR_OUT_OF_MEMORY); txApplyDefaultElementTemplate* applyTemplates = new txApplyDefaultElementTemplate; pushContext->mNext = applyTemplates; - NS_ENSURE_TRUE(applyTemplates, NS_ERROR_OUT_OF_MEMORY); txLoopNodeSet* loopNodeSet = new txLoopNodeSet(applyTemplates); applyTemplates->mNext = loopNodeSet; - NS_ENSURE_TRUE(loopNodeSet, NS_ERROR_OUT_OF_MEMORY); txPopParams* popParams = new txPopParams; pushContext->mBailTarget = loopNodeSet->mNext = popParams; - NS_ENSURE_TRUE(popParams, NS_ERROR_OUT_OF_MEMORY); popParams->mNext = new txReturn(); - NS_ENSURE_TRUE(popParams->mNext, NS_ERROR_OUT_OF_MEMORY); // attribute/textnode template nt = new txNodeTypeTest(txNodeTypeTest::NODE_TYPE); - NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY); - nodeExpr = new LocationStep(nt, LocationStep::SELF_AXIS); - NS_ENSURE_TRUE(nodeExpr, NS_ERROR_OUT_OF_MEMORY); - nt.forget(); mCharactersTemplate = new txValueOf(Move(nodeExpr), false); - NS_ENSURE_TRUE(mCharactersTemplate, NS_ERROR_OUT_OF_MEMORY); - mCharactersTemplate->mNext = new txReturn(); - NS_ENSURE_TRUE(mCharactersTemplate->mNext, NS_ERROR_OUT_OF_MEMORY); // pi/comment/namespace template mEmptyTemplate = new txReturn(); - NS_ENSURE_TRUE(mEmptyTemplate, NS_ERROR_OUT_OF_MEMORY); return NS_OK; } @@ -351,8 +332,6 @@ txStylesheet::doneCompiling() if (!mDecimalFormats.get(txExpandedName())) { nsAutoPtr format(new txDecimalFormat); - NS_ENSURE_TRUE(format, NS_ERROR_OUT_OF_MEMORY); - rv = mDecimalFormats.add(txExpandedName(), format); NS_ENSURE_SUCCESS(rv, rv); @@ -394,8 +373,6 @@ txStylesheet::addTemplate(txTemplateItem* aTemplate, if (!templates) { nsAutoPtr< nsTArray > newList( new nsTArray); - NS_ENSURE_TRUE(newList, NS_ERROR_OUT_OF_MEMORY); - rv = aImportFrame->mMatchableTemplates.set(aTemplate->mMode, newList); NS_ENSURE_SUCCESS(rv, rv); @@ -546,8 +523,6 @@ txStylesheet::addGlobalVariable(txVariableItem* aVariable) new GlobalVariable(Move(aVariable->mValue), Move(aVariable->mFirstInstruction), aVariable->mIsParam)); - NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = mGlobalVariables.add(aVariable->mName, var); NS_ENSURE_SUCCESS(rv, rv); @@ -566,8 +541,6 @@ txStylesheet::addKey(const txExpandedName& aName, txXSLKey* xslKey = mKeys.get(aName); if (!xslKey) { xslKey = new txXSLKey(aName); - NS_ENSURE_TRUE(xslKey, NS_ERROR_OUT_OF_MEMORY); - rv = mKeys.add(aName, xslKey); if (NS_FAILED(rv)) { delete xslKey; diff --git a/dom/xslt/xslt/txStylesheetCompileHandlers.cpp b/dom/xslt/xslt/txStylesheetCompileHandlers.cpp index 4765b77794..295604cd11 100644 --- a/dom/xslt/xslt/txStylesheetCompileHandlers.cpp +++ b/dom/xslt/xslt/txStylesheetCompileHandlers.cpp @@ -20,6 +20,7 @@ #include "txNamespaceMap.h" #include "txURIUtils.h" #include "txXSLTFunctions.h" +#include "nsNetUtil.h" using namespace mozilla; @@ -113,8 +114,6 @@ parseUseAttrSets(txStylesheetAttr* aAttributes, NS_ENSURE_SUCCESS(rv, rv); nsAutoPtr instr(new txInsertAttrSet(name)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); } @@ -191,7 +190,6 @@ getExprAttr(txStylesheetAttr* aAttributes, attr->mValue #endif ); - NS_ENSURE_TRUE(aExpr, NS_ERROR_OUT_OF_MEMORY); } else { aExpr = nullptr; @@ -228,7 +226,6 @@ getAVTAttr(txStylesheetAttr* aAttributes, attr->mValue #endif ); - NS_ENSURE_TRUE(aAVT, NS_ERROR_OUT_OF_MEMORY); } else { aAVT = nullptr; @@ -525,12 +522,8 @@ txFnStartLREStylesheet(int32_t aNamespaceID, double prio = UnspecifiedNaN(); nsAutoPtr match(new txRootPattern()); - NS_ENSURE_TRUE(match, NS_ERROR_OUT_OF_MEMORY); - nsAutoPtr templ(new txTemplateItem(Move(match), nullExpr, nullExpr, prio)); - NS_ENSURE_TRUE(templ, NS_ERROR_OUT_OF_MEMORY); - aState.openInstructionContainer(templ); rv = aState.addToplevelItem(templ); NS_ENSURE_SUCCESS(rv, rv); @@ -553,8 +546,6 @@ txFnEndLREStylesheet(txStylesheetCompilerState& aState) aState.popHandlerTable(); nsAutoPtr instr(new txReturn()); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -638,8 +629,6 @@ txFnStartAttributeSet(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); nsAutoPtr attrSet(new txAttributeSetItem(name)); - NS_ENSURE_TRUE(attrSet, NS_ERROR_OUT_OF_MEMORY); - aState.openInstructionContainer(attrSet); rv = aState.addToplevelItem(attrSet); @@ -659,8 +648,6 @@ txFnEndAttributeSet(txStylesheetCompilerState& aState) aState.popHandlerTable(); nsAutoPtr instr(new txReturn()); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -686,8 +673,6 @@ txFnStartDecimalFormat(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); nsAutoPtr format(new txDecimalFormat); - NS_ENSURE_TRUE(format, NS_ERROR_OUT_OF_MEMORY); - rv = getCharAttr(aAttributes, aAttrCount, nsGkAtoms::decimalSeparator, false, aState, format->mDecimalSeparator); NS_ENSURE_SUCCESS(rv, rv); @@ -761,11 +746,7 @@ txFnStartImport(int32_t aNamespaceID, txStylesheetCompilerState& aState) { nsAutoPtr import(new txImportItem); - NS_ENSURE_TRUE(import, NS_ERROR_OUT_OF_MEMORY); - import->mFrame = new txStylesheet::ImportFrame; - NS_ENSURE_TRUE(import->mFrame, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addToplevelItem(import); NS_ENSURE_SUCCESS(rv, rv); @@ -776,10 +757,12 @@ txFnStartImport(int32_t aNamespaceID, nsGkAtoms::href, true, &attr); NS_ENSURE_SUCCESS(rv, rv); - nsAutoString absUri; - URIUtils::resolveHref(attr->mValue, aState.mElementContext->mBaseURI, - absUri); - rv = aState.loadImportedStylesheet(absUri, importPtr->mFrame); + nsCOMPtr uri; + rv = NS_NewURI(getter_AddRefs(uri), attr->mValue, nullptr, + aState.mElementContext->mBaseURI); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aState.loadImportedStylesheet(uri, importPtr->mFrame); NS_ENSURE_SUCCESS(rv, rv); return aState.pushHandlerTable(gTxIgnoreHandler); @@ -807,10 +790,12 @@ txFnStartInclude(int32_t aNamespaceID, nsGkAtoms::href, true, &attr); NS_ENSURE_SUCCESS(rv, rv); - nsAutoString absUri; - URIUtils::resolveHref(attr->mValue, aState.mElementContext->mBaseURI, - absUri); - rv = aState.loadIncludedStylesheet(absUri); + nsCOMPtr uri; + rv = NS_NewURI(getter_AddRefs(uri), attr->mValue, nullptr, + aState.mElementContext->mBaseURI); + NS_ENSURE_SUCCESS(rv, rv); + + rv = aState.loadIncludedStylesheet(uri); NS_ENSURE_SUCCESS(rv, rv); return aState.pushHandlerTable(gTxIgnoreHandler); @@ -910,7 +895,6 @@ txFnStartOutput(int32_t aNamespaceID, nsresult rv = NS_OK; nsAutoPtr item(new txOutputItem); - NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY); txExpandedName methodExpName; rv = getQNameAttr(aAttributes, aAttrCount, nsGkAtoms::method, false, @@ -977,8 +961,6 @@ txFnStartOutput(int32_t aNamespaceID, nsWhitespaceTokenizer tokens(attr->mValue); while (tokens.hasMoreTokens()) { nsAutoPtr qname(new txExpandedName()); - NS_ENSURE_TRUE(qname, NS_ERROR_OUT_OF_MEMORY); - rv = qname->init(tokens.nextToken(), aState.mElementContext->mMappings, false); NS_ENSURE_SUCCESS(rv, rv); @@ -1033,8 +1015,6 @@ txFnStartStripSpace(int32_t aNamespaceID, bool strip = aLocalName == nsGkAtoms::stripSpace; nsAutoPtr stripItem(new txStripSpaceItem); - NS_ENSURE_TRUE(stripItem, NS_ERROR_OUT_OF_MEMORY); - nsWhitespaceTokenizer tokenizer(attr->mValue); while (tokenizer.hasMoreTokens()) { const nsASingleFragmentString& name = tokenizer.nextToken(); @@ -1075,8 +1055,6 @@ txFnStartStripSpace(int32_t aNamespaceID, } nsAutoPtr sst(new txStripSpaceTest(prefix, localName, ns, strip)); - NS_ENSURE_TRUE(sst, NS_ERROR_OUT_OF_MEMORY); - rv = stripItem->addStripSpaceTest(sst); NS_ENSURE_SUCCESS(rv, rv); @@ -1131,8 +1109,6 @@ txFnStartTemplate(int32_t aNamespaceID, nsAutoPtr templ(new txTemplateItem(Move(match), name, mode, prio)); - NS_ENSURE_TRUE(templ, NS_ERROR_OUT_OF_MEMORY); - aState.openInstructionContainer(templ); rv = aState.addToplevelItem(templ); NS_ENSURE_SUCCESS(rv, rv); @@ -1148,8 +1124,6 @@ txFnEndTemplate(txStylesheetCompilerState& aState) aState.popHandlerTable(); nsAutoPtr instr(new txReturn()); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1181,8 +1155,6 @@ txFnStartTopVariable(int32_t aNamespaceID, nsAutoPtr var( new txVariableItem(name, Move(select), aLocalName == nsGkAtoms::param)); - NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY); - aState.openInstructionContainer(var); rv = aState.pushPtr(var, aState.eVariableItem); NS_ENSURE_SUCCESS(rv, rv); @@ -1218,13 +1190,10 @@ txFnEndTopVariable(txStylesheetCompilerState& aState) NS_ASSERTION(!var->mValue, "There shouldn't be a select-expression here"); var->mValue = new txLiteralExpr(EmptyString()); - NS_ENSURE_TRUE(var->mValue, NS_ERROR_OUT_OF_MEMORY); } else if (!var->mValue) { // If we don't have a select-expression there mush be children. nsAutoPtr instr(new txReturn()); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); } @@ -1282,8 +1251,6 @@ txFnStartLRE(int32_t aNamespaceID, nsAutoPtr instr(new txStartLREElement(aNamespaceID, aLocalName, aPrefix)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1313,8 +1280,6 @@ txFnStartLRE(int32_t aNamespaceID, instr = new txLREAttribute(attr->mNamespaceID, attr->mLocalName, attr->mPrefix, Move(avt)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); } @@ -1326,8 +1291,6 @@ static nsresult txFnEndLRE(txStylesheetCompilerState& aState) { nsAutoPtr instr(new txEndElement); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1345,8 +1308,6 @@ txFnText(const nsAString& aStr, txStylesheetCompilerState& aState) TX_RETURN_IF_WHITESPACE(aStr, aState); nsAutoPtr instr(new txText(aStr, false)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1370,14 +1331,10 @@ txFnStartApplyImports(int32_t aNamespaceID, nsresult rv = NS_OK; nsAutoPtr instr(new txApplyImportsStart); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); instr = new txApplyImportsEnd; - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1413,8 +1370,6 @@ txFnStartApplyTemplates(int32_t aNamespaceID, nsresult rv = NS_OK; nsAutoPtr instr(new txPushParams); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1424,8 +1379,6 @@ txFnStartApplyTemplates(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); instr = new txApplyTemplates(mode); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.pushObject(instr); NS_ENSURE_SUCCESS(rv, rv); @@ -1439,17 +1392,11 @@ txFnStartApplyTemplates(int32_t aNamespaceID, if (!select) { nsAutoPtr nt( new txNodeTypeTest(txNodeTypeTest::NODE_TYPE)); - NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY); - select = new LocationStep(nt, LocationStep::CHILD_AXIS); - NS_ENSURE_TRUE(select, NS_ERROR_OUT_OF_MEMORY); - nt.forget(); } nsAutoPtr pushcontext( new txPushNewContext(Move(select))); - NS_ENSURE_TRUE(pushcontext, NS_ERROR_OUT_OF_MEMORY); - rv = aState.pushSorter(pushcontext); NS_ENSURE_SUCCESS(rv, rv); @@ -1476,8 +1423,6 @@ txFnEndApplyTemplates(txStylesheetCompilerState& aState) instr = static_cast(aState.popObject()); // txApplyTemplates nsAutoPtr loop(new txLoopNodeSet(instr)); - NS_ENSURE_TRUE(loop, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1486,8 +1431,6 @@ txFnEndApplyTemplates(txStylesheetCompilerState& aState) NS_ENSURE_SUCCESS(rv, rv); instr = new txPopParams; - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - pushcontext->mBailTarget = instr; rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1513,8 +1456,6 @@ txFnStartAttribute(int32_t aNamespaceID, nsresult rv = NS_OK; nsAutoPtr instr(new txPushStringHandler(true)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1530,8 +1471,6 @@ txFnStartAttribute(int32_t aNamespaceID, instr = new txAttribute(Move(name), Move(nspace), aState.mElementContext->mMappings); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.pushObject(instr); NS_ENSURE_SUCCESS(rv, rv); @@ -1573,8 +1512,6 @@ txFnStartCallTemplate(int32_t aNamespaceID, nsresult rv = NS_OK; nsAutoPtr instr(new txPushParams); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1584,8 +1521,6 @@ txFnStartCallTemplate(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); instr = new txCallTemplate(name); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.pushObject(instr); NS_ENSURE_SUCCESS(rv, rv); @@ -1605,8 +1540,6 @@ txFnEndCallTemplate(txStylesheetCompilerState& aState) NS_ENSURE_SUCCESS(rv, rv); instr = new txPopParams; - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1674,8 +1607,6 @@ txFnStartComment(int32_t aNamespaceID, txStylesheetCompilerState& aState) { nsAutoPtr instr(new txPushStringHandler(true)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1686,8 +1617,6 @@ static nsresult txFnEndComment(txStylesheetCompilerState& aState) { nsAutoPtr instr(new txComment); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1712,8 +1641,6 @@ txFnStartCopy(int32_t aNamespaceID, txStylesheetCompilerState& aState) { nsAutoPtr copy(new txCopy); - NS_ENSURE_TRUE(copy, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.pushPtr(copy, aState.eCopy); NS_ENSURE_SUCCESS(rv, rv); @@ -1731,8 +1658,6 @@ static nsresult txFnEndCopy(txStylesheetCompilerState& aState) { nsAutoPtr instr(new txEndElement); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1764,8 +1689,6 @@ txFnStartCopyOf(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); nsAutoPtr instr(new txCopyOf(Move(select))); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1810,8 +1733,6 @@ txFnStartElement(int32_t aNamespaceID, nsAutoPtr instr( new txStartElement(Move(name), Move(nspace), aState.mElementContext->mMappings)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1825,8 +1746,6 @@ static nsresult txFnEndElement(txStylesheetCompilerState& aState) { nsAutoPtr instr(new txEndElement); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -1886,8 +1805,6 @@ txFnStartForEach(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); nsAutoPtr pushcontext(new txPushNewContext(Move(select))); - NS_ENSURE_TRUE(pushcontext, NS_ERROR_OUT_OF_MEMORY); - rv = aState.pushPtr(pushcontext, aState.ePushNewContext); NS_ENSURE_SUCCESS(rv, rv); @@ -1899,8 +1816,6 @@ txFnStartForEach(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); instr = new txPushNullTemplateRule; - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.pushPtr(instr, aState.ePushNullTemplateRule); NS_ENSURE_SUCCESS(rv, rv); @@ -1979,8 +1894,6 @@ txFnStartIf(int32_t aNamespaceID, nsAutoPtr condGoto(new txConditionalGoto(Move(test), nullptr)); - NS_ENSURE_TRUE(condGoto, NS_ERROR_OUT_OF_MEMORY); - rv = aState.pushPtr(condGoto, aState.eConditionalGoto); NS_ENSURE_SUCCESS(rv, rv); @@ -2015,8 +1928,6 @@ txFnStartMessage(int32_t aNamespaceID, txStylesheetCompilerState& aState) { nsAutoPtr instr(new txPushStringHandler(false)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -2026,8 +1937,6 @@ txFnStartMessage(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); instr = new txMessage(term == eTrue); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.pushObject(instr); NS_ENSURE_SUCCESS(rv, rv); @@ -2121,8 +2030,6 @@ txFnStartNumber(int32_t aNamespaceID, Move(value), Move(format), Move(groupingSeparator), Move(groupingSize))); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -2202,8 +2109,6 @@ txFnStartParam(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); nsAutoPtr var(new txSetVariable(name, Move(select))); - NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY); - if (var->mValue) { // XXX should be gTxErrorHandler? rv = aState.pushHandlerTable(gTxIgnoreHandler); @@ -2235,7 +2140,6 @@ txFnEndParam(txStylesheetCompilerState& aState) NS_ASSERTION(!var->mValue, "There shouldn't be a select-expression here"); var->mValue = new txLiteralExpr(EmptyString()); - NS_ENSURE_TRUE(var->mValue, NS_ERROR_OUT_OF_MEMORY); } nsresult rv = aState.addVariable(var->mName); @@ -2268,8 +2172,6 @@ txFnStartPI(int32_t aNamespaceID, txStylesheetCompilerState& aState) { nsAutoPtr instr(new txPushStringHandler(true)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -2279,8 +2181,6 @@ txFnStartPI(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); instr = new txProcessingInstruction(Move(name)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.pushObject(instr); NS_ENSURE_SUCCESS(rv, rv); @@ -2323,10 +2223,8 @@ txFnStartSort(int32_t aNamespaceID, if (!select) { nsAutoPtr nt( new txNodeTypeTest(txNodeTypeTest::NODE_TYPE)); - NS_ENSURE_TRUE(nt, NS_ERROR_OUT_OF_MEMORY); select = new LocationStep(nt, LocationStep::SELF_AXIS); - NS_ENSURE_TRUE(select, NS_ERROR_OUT_OF_MEMORY); nt.forget(); } @@ -2405,8 +2303,6 @@ static nsresult txFnTextText(const nsAString& aStr, txStylesheetCompilerState& aState) { nsAutoPtr instr(new txText(aStr, aState.mDOE)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -2440,8 +2336,6 @@ txFnStartValueOf(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); nsAutoPtr instr(new txValueOf(Move(select), doe == eTrue)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -2483,8 +2377,6 @@ txFnStartVariable(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); nsAutoPtr var(new txSetVariable(name, Move(select))); - NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY); - if (var->mValue) { // XXX should be gTxErrorHandler? rv = aState.pushHandlerTable(gTxIgnoreHandler); @@ -2517,7 +2409,6 @@ txFnEndVariable(txStylesheetCompilerState& aState) NS_ASSERTION(!var->mValue, "There shouldn't be a select-expression here"); var->mValue = new txLiteralExpr(EmptyString()); - NS_ENSURE_TRUE(var->mValue, NS_ERROR_OUT_OF_MEMORY); } nsresult rv = aState.addVariable(var->mName); @@ -2539,8 +2430,6 @@ txFnStartElementStartRTF(int32_t aNamespaceID, txStylesheetCompilerState& aState) { nsAutoPtr instr(new txPushRTFHandler); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -2555,8 +2444,6 @@ txFnTextStartRTF(const nsAString& aStr, txStylesheetCompilerState& aState) TX_RETURN_IF_WHITESPACE(aStr, aState); nsAutoPtr instr(new txPushRTFHandler); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -2587,8 +2474,6 @@ txFnStartWhen(int32_t aNamespaceID, nsAutoPtr condGoto(new txConditionalGoto(Move(test), nullptr)); - NS_ENSURE_TRUE(condGoto, NS_ERROR_OUT_OF_MEMORY); - rv = aState.pushPtr(condGoto, aState.eConditionalGoto); NS_ENSURE_SUCCESS(rv, rv); @@ -2604,8 +2489,6 @@ txFnEndWhen(txStylesheetCompilerState& aState) { aState.popHandlerTable(); nsAutoPtr gotoinstr(new txGoTo(nullptr)); - NS_ENSURE_TRUE(gotoinstr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.mChooseGotoList->add(gotoinstr); NS_ENSURE_SUCCESS(rv, rv); @@ -2649,8 +2532,6 @@ txFnStartWithParam(int32_t aNamespaceID, NS_ENSURE_SUCCESS(rv, rv); nsAutoPtr var(new txSetParam(name, Move(select))); - NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY); - if (var->mValue) { // XXX should be gTxErrorHandler? rv = aState.pushHandlerTable(gTxIgnoreHandler); @@ -2681,7 +2562,6 @@ txFnEndWithParam(txStylesheetCompilerState& aState) NS_ASSERTION(!var->mValue, "There shouldn't be a select-expression here"); var->mValue = new txLiteralExpr(EmptyString()); - NS_ENSURE_TRUE(var->mValue, NS_ERROR_OUT_OF_MEMORY); } nsAutoPtr instr(var.forget()); @@ -2725,8 +2605,6 @@ txFnEndUnknownInstruction(txStylesheetCompilerState& aState) if (aState.mSearchingForFallback) { nsAutoPtr instr(new txErrorInstruction()); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = aState.addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/dom/xslt/xslt/txStylesheetCompiler.cpp b/dom/xslt/xslt/txStylesheetCompiler.cpp index 61b3318a78..bf37a9fb24 100644 --- a/dom/xslt/xslt/txStylesheetCompiler.cpp +++ b/dom/xslt/xslt/txStylesheetCompiler.cpp @@ -5,6 +5,7 @@ #include "mozilla/ArrayUtils.h" #include "mozilla/Move.h" +#include "mozilla/UniquePtr.h" #include "txStylesheetCompiler.h" #include "txStylesheetCompileHandlers.h" @@ -22,31 +23,29 @@ #include "nsICategoryManager.h" #include "nsServiceManagerUtils.h" #include "nsTArray.h" +#include "nsIURI.h" using namespace mozilla; using mozilla::net::ReferrerPolicy; -txStylesheetCompiler::txStylesheetCompiler(const nsAString& aStylesheetURI, - ReferrerPolicy aReferrerPolicy, +txStylesheetCompiler::txStylesheetCompiler(const nsString& aFragment, txACompileObserver* aObserver) : txStylesheetCompilerState(aObserver) { - mStatus = init(aStylesheetURI, aReferrerPolicy, nullptr, nullptr); + mStatus = init(aFragment, nullptr, nullptr); } -txStylesheetCompiler::txStylesheetCompiler(const nsAString& aStylesheetURI, +txStylesheetCompiler::txStylesheetCompiler(const nsString& aFragment, txStylesheet* aStylesheet, txListIterator* aInsertPosition, - ReferrerPolicy aReferrerPolicy, txACompileObserver* aObserver) : txStylesheetCompilerState(aObserver) { - mStatus = init(aStylesheetURI, aReferrerPolicy, aStylesheet, - aInsertPosition); + mStatus = init(aFragment, aStylesheet, aInsertPosition); } void -txStylesheetCompiler::setBaseURI(const nsString& aBaseURI) +txStylesheetCompiler::setBaseURI(nsIURI* aBaseURI) { NS_ASSERTION(mObjectStack.size() == 1 && !mObjectStack.peek(), "Execution already started"); @@ -58,6 +57,16 @@ txStylesheetCompiler::setBaseURI(const nsString& aBaseURI) mElementContext->mBaseURI = aBaseURI; } +void +txStylesheetCompiler::setPrincipal(nsIPrincipal* aPrincipal) +{ + if (NS_FAILED(mStatus)) { + return; + } + + mStylesheetPrincipal = aPrincipal; +} + nsresult txStylesheetCompiler::startElement(int32_t aNamespaceID, nsIAtom* aLocalName, nsIAtom* aPrefix, @@ -85,8 +94,6 @@ txStylesheetCompiler::startElement(int32_t aNamespaceID, nsIAtom* aLocalName, if (!hasOwnNamespaceMap) { mElementContext->mMappings = new txNamespaceMap(*mElementContext->mMappings); - NS_ENSURE_TRUE(mElementContext->mMappings, - NS_ERROR_OUT_OF_MEMORY); hasOwnNamespaceMap = true; } @@ -118,10 +125,9 @@ txStylesheetCompiler::startElement(const char16_t *aName, nsresult rv = flushCharacters(); NS_ENSURE_SUCCESS(rv, rv); - nsAutoArrayPtr atts; + UniquePtr atts; if (aAttrCount > 0) { - atts = new txStylesheetAttr[aAttrCount]; - NS_ENSURE_TRUE(atts, NS_ERROR_OUT_OF_MEMORY); + atts = MakeUnique(aAttrCount); } bool hasOwnNamespaceMap = false; @@ -149,8 +155,6 @@ txStylesheetCompiler::startElement(const char16_t *aName, if (!hasOwnNamespaceMap) { mElementContext->mMappings = new txNamespaceMap(*mElementContext->mMappings); - NS_ENSURE_TRUE(mElementContext->mMappings, - NS_ERROR_OUT_OF_MEMORY); hasOwnNamespaceMap = true; } @@ -166,7 +170,7 @@ txStylesheetCompiler::startElement(const char16_t *aName, getter_AddRefs(localname), &namespaceID); NS_ENSURE_SUCCESS(rv, rv); - return startElementInternal(namespaceID, localname, prefix, atts, + return startElementInternal(namespaceID, localname, prefix, atts.get(), aAttrCount); } @@ -221,9 +225,11 @@ txStylesheetCompiler::startElementInternal(int32_t aNamespaceID, rv = ensureNewElementContext(); NS_ENSURE_SUCCESS(rv, rv); - nsAutoString uri; - URIUtils::resolveHref(attr->mValue, mElementContext->mBaseURI, uri); - mElementContext->mBaseURI = uri; + nsCOMPtr uri; + rv = NS_NewURI(getter_AddRefs(uri), attr->mValue, + nullptr, mElementContext->mBaseURI); + NS_ENSURE_SUCCESS(rv, rv); + mElementContext->mBaseURI = uri.forget(); } // extension-element-prefixes @@ -336,8 +342,6 @@ txStylesheetCompiler::endElement() txInScopeVariable* var = mInScopeVariables[i]; if (!--(var->mLevel)) { nsAutoPtr instr(new txRemoveVariable(var->mName)); - NS_ENSURE_TRUE(instr, NS_ERROR_OUT_OF_MEMORY); - rv = addInstruction(Move(instr)); NS_ENSURE_SUCCESS(rv, rv); @@ -377,9 +381,15 @@ txStylesheetCompiler::characters(const nsAString& aStr) nsresult txStylesheetCompiler::doneLoading() { - MOZ_LOG(txLog::xslt, LogLevel::Info, - ("Compiler::doneLoading: %s\n", - NS_LossyConvertUTF16toASCII(mStylesheetURI).get())); + if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Info)) { + nsCOMPtr uri; + mStylesheetPrincipal->GetURI(getter_AddRefs(uri)); + nsAutoCString spec; + uri->GetSpec(spec); + MOZ_LOG(txLog::xslt, LogLevel::Info, + ("Compiler::doneLoading: %s\n", + spec.get())); + } if (NS_FAILED(mStatus)) { return mStatus; } @@ -393,11 +403,17 @@ void txStylesheetCompiler::cancel(nsresult aError, const char16_t *aErrorText, const char16_t *aParam) { - MOZ_LOG(txLog::xslt, LogLevel::Info, - ("Compiler::cancel: %s, module: %d, code %d\n", - NS_LossyConvertUTF16toASCII(mStylesheetURI).get(), - NS_ERROR_GET_MODULE(aError), - NS_ERROR_GET_CODE(aError))); + if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Info)) { + nsCOMPtr uri; + mStylesheetPrincipal->GetURI(getter_AddRefs(uri)); + nsAutoCString spec; + uri->GetSpec(spec); + MOZ_LOG(txLog::xslt, LogLevel::Info, + ("Compiler::cancel: %s, module: %d, code %d\n", + spec.get(), + NS_ERROR_GET_MODULE(aError), + NS_ERROR_GET_CODE(aError))); + } if (NS_SUCCEEDED(mStatus)) { mStatus = aError; } @@ -417,20 +433,30 @@ txStylesheetCompiler::getStylesheet() } nsresult -txStylesheetCompiler::loadURI(const nsAString& aUri, - const nsAString& aReferrerUri, - ReferrerPolicy aReferrerPolicy, +txStylesheetCompiler::loadURI(nsIURI* aUri, + nsIPrincipal* aReferrerPrincipal, txStylesheetCompiler* aCompiler) { - MOZ_LOG(txLog::xslt, LogLevel::Info, - ("Compiler::loadURI forwards %s thru %s\n", - NS_LossyConvertUTF16toASCII(aUri).get(), - NS_LossyConvertUTF16toASCII(mStylesheetURI).get())); - if (mStylesheetURI.Equals(aUri)) { + nsCOMPtr stylesheetURI; + mStylesheetPrincipal->GetURI(getter_AddRefs(stylesheetURI)); + + if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Info)) { + nsAutoCString stylesheetSpec; + stylesheetURI->GetSpec(stylesheetSpec); + nsAutoCString uriSpec; + aUri->GetSpec(uriSpec); + MOZ_LOG(txLog::xslt, LogLevel::Info, + ("Compiler::loadURI forwards %s thru %s\n", + uriSpec.get(), + stylesheetSpec.get())); + } + + bool equals; + if (NS_FAILED(stylesheetURI->Equals(aUri, &equals)) || equals) { return NS_ERROR_XSLT_LOAD_RECURSION; } return mObserver ? - mObserver->loadURI(aUri, aReferrerUri, aReferrerPolicy, aCompiler) : + mObserver->loadURI(aUri, aReferrerPrincipal, aCompiler) : NS_ERROR_FAILURE; } @@ -482,8 +508,6 @@ txStylesheetCompiler::ensureNewElementContext() nsAutoPtr context(new txElementContext(*mElementContext)); - NS_ENSURE_TRUE(context, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = pushObject(mElementContext); NS_ENSURE_SUCCESS(rv, rv); @@ -542,27 +566,20 @@ txStylesheetCompilerState::txStylesheetCompilerState(txACompileObserver* aObserv } nsresult -txStylesheetCompilerState::init(const nsAString& aStylesheetURI, - ReferrerPolicy aReferrerPolicy, +txStylesheetCompilerState::init(const nsString& aFragment, txStylesheet* aStylesheet, txListIterator* aInsertPosition) { NS_ASSERTION(!aStylesheet || aInsertPosition, "must provide insertposition if loading subsheet"); - mStylesheetURI = aStylesheetURI; - mReferrerPolicy = aReferrerPolicy; + // Check for fragment identifier of an embedded stylesheet. - int32_t fragment = aStylesheetURI.FindChar('#') + 1; - if (fragment > 0) { - int32_t fragmentLength = aStylesheetURI.Length() - fragment; - if (fragmentLength > 0) { - // This is really an embedded stylesheet, not just a - // "url#". We may want to unescape the fragment. - mTarget = Substring(aStylesheetURI, (uint32_t)fragment, - fragmentLength); - mEmbedStatus = eNeedEmbed; - mHandlerTable = gTxEmbedHandler; - } + if (!aFragment.IsEmpty()) { + // This is really an embedded stylesheet, not just a + // "url#". We may want to unescape the fragment. + mTarget = aFragment; + mEmbedStatus = eNeedEmbed; + mHandlerTable = gTxEmbedHandler; } nsresult rv = NS_OK; if (aStylesheet) { @@ -572,8 +589,6 @@ txStylesheetCompilerState::init(const nsAString& aStylesheetURI, } else { mStylesheet = new txStylesheet; - NS_ENSURE_TRUE(mStylesheet, NS_ERROR_OUT_OF_MEMORY); - rv = mStylesheet->init(); NS_ENSURE_SUCCESS(rv, rv); @@ -583,9 +598,7 @@ txStylesheetCompilerState::init(const nsAString& aStylesheetURI, mIsTopCompiler = true; } - mElementContext = new txElementContext(aStylesheetURI); - NS_ENSURE_TRUE(mElementContext && mElementContext->mMappings, - NS_ERROR_OUT_OF_MEMORY); + mElementContext = new txElementContext(); // Push the "old" txElementContext rv = pushObject(0); @@ -649,7 +662,6 @@ txStylesheetCompilerState::pushChooseGotoList() mChooseGotoList.forget(); mChooseGotoList = new txList; - NS_ENSURE_TRUE(mChooseGotoList, NS_ERROR_OUT_OF_MEMORY); return NS_OK; } @@ -749,18 +761,25 @@ txStylesheetCompilerState::addInstruction(nsAutoPtr&& aInstructio } nsresult -txStylesheetCompilerState::loadIncludedStylesheet(const nsAString& aURI) +txStylesheetCompilerState::loadIncludedStylesheet(nsIURI* aURI) { - MOZ_LOG(txLog::xslt, LogLevel::Info, - ("CompilerState::loadIncludedStylesheet: %s\n", - NS_LossyConvertUTF16toASCII(aURI).get())); - if (mStylesheetURI.Equals(aURI)) { + if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Info)) { + nsAutoCString spec; + aURI->GetSpec(spec); + MOZ_LOG(txLog::xslt, LogLevel::Info, + ("CompilerState::loadIncludedStylesheet: %s\n", + spec.get())); + } + + nsCOMPtr stylesheetURI; + mStylesheetPrincipal->GetURI(getter_AddRefs(stylesheetURI)); + bool equals; + if (NS_FAILED(stylesheetURI->Equals(aURI, &equals)) || equals) { return NS_ERROR_XSLT_LOAD_RECURSION; } NS_ENSURE_TRUE(mObserver, NS_ERROR_NOT_IMPLEMENTED); nsAutoPtr item(new txDummyItem); - NS_ENSURE_TRUE(item, NS_ERROR_OUT_OF_MEMORY); nsresult rv = mToplevelIterator.addBefore(item); NS_ENSURE_SUCCESS(rv, rv); @@ -772,19 +791,21 @@ txStylesheetCompilerState::loadIncludedStylesheet(const nsAString& aURI) txACompileObserver* observer = static_cast(this); + nsAutoCString fragment; + aURI->GetRef(fragment); + RefPtr compiler = - new txStylesheetCompiler(aURI, mStylesheet, &mToplevelIterator, - mReferrerPolicy, observer); - NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY); + new txStylesheetCompiler(NS_ConvertUTF8toUTF16(fragment), + mStylesheet, + &mToplevelIterator, + observer); // step forward before calling the observer in case of syncronous loading mToplevelIterator.next(); - if (mChildCompilerList.AppendElement(compiler) == nullptr) { - return NS_ERROR_OUT_OF_MEMORY; - } + mChildCompilerList.AppendElement(compiler); - rv = mObserver->loadURI(aURI, mStylesheetURI, mReferrerPolicy, compiler); + rv = mObserver->loadURI(aURI, mStylesheetPrincipal, compiler); if (NS_FAILED(rv)) { mChildCompilerList.RemoveElement(compiler); } @@ -793,13 +814,21 @@ txStylesheetCompilerState::loadIncludedStylesheet(const nsAString& aURI) } nsresult -txStylesheetCompilerState::loadImportedStylesheet(const nsAString& aURI, +txStylesheetCompilerState::loadImportedStylesheet(nsIURI* aURI, txStylesheet::ImportFrame* aFrame) { - MOZ_LOG(txLog::xslt, LogLevel::Info, - ("CompilerState::loadImportedStylesheet: %s\n", - NS_LossyConvertUTF16toASCII(aURI).get())); - if (mStylesheetURI.Equals(aURI)) { + if (MOZ_LOG_TEST(txLog::xslt, LogLevel::Info)) { + nsAutoCString spec; + aURI->GetSpec(spec); + MOZ_LOG(txLog::xslt, LogLevel::Info, + ("CompilerState::loadImportedStylesheet: %s\n", + spec.get())); + } + + nsCOMPtr stylesheetURI; + mStylesheetPrincipal->GetURI(getter_AddRefs(stylesheetURI)); + bool equals; + if (NS_FAILED(stylesheetURI->Equals(aURI, &equals)) || equals) { return NS_ERROR_XSLT_LOAD_RECURSION; } NS_ENSURE_TRUE(mObserver, NS_ERROR_NOT_IMPLEMENTED); @@ -809,17 +838,18 @@ txStylesheetCompilerState::loadImportedStylesheet(const nsAString& aURI, txACompileObserver* observer = static_cast(this); + nsAutoCString fragment; + aURI->GetRef(fragment); + RefPtr compiler = - new txStylesheetCompiler(aURI, mStylesheet, &iter, mReferrerPolicy, + new txStylesheetCompiler(NS_ConvertUTF8toUTF16(fragment), + mStylesheet, + &iter, observer); - NS_ENSURE_TRUE(compiler, NS_ERROR_OUT_OF_MEMORY); - if (mChildCompilerList.AppendElement(compiler) == nullptr) { - return NS_ERROR_OUT_OF_MEMORY; - } + mChildCompilerList.AppendElement(compiler); - nsresult rv = mObserver->loadURI(aURI, mStylesheetURI, mReferrerPolicy, - compiler); + nsresult rv = mObserver->loadURI(aURI, mStylesheetPrincipal, compiler); if (NS_FAILED(rv)) { mChildCompilerList.RemoveElement(compiler); } @@ -841,8 +871,6 @@ nsresult txStylesheetCompilerState::addVariable(const txExpandedName& aName) { txInScopeVariable* var = new txInScopeVariable(aName); - NS_ENSURE_TRUE(var, NS_ERROR_OUT_OF_MEMORY); - if (!mInScopeVariables.AppendElement(var)) { delete var; return NS_ERROR_OUT_OF_MEMORY; @@ -963,7 +991,8 @@ TX_ConstructXSLTFunction(nsIAtom* aName, int32_t aNamespaceID, return NS_ERROR_XPATH_UNKNOWN_FUNCTION; } - return *aFunction ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + MOZ_ASSERT(*aFunction); + return NS_OK; } typedef nsresult (*txFunctionFactory)(nsIAtom* aName, @@ -1034,9 +1063,6 @@ findFunction(nsIAtom* aName, int32_t aNamespaceID, if (!sXPCOMFunctionMappings) { sXPCOMFunctionMappings = new nsTArray; - if (!sXPCOMFunctionMappings) { - return NS_ERROR_OUT_OF_MEMORY; - } } txXPCOMFunctionMapping *map = nullptr; @@ -1084,9 +1110,7 @@ extern bool TX_XSLTFunctionAvailable(nsIAtom* aName, int32_t aNameSpaceID) { RefPtr compiler = - new txStylesheetCompiler(EmptyString(), - mozilla::net::RP_Default, nullptr); - NS_ENSURE_TRUE(compiler, false); + new txStylesheetCompiler(EmptyString(), nullptr); nsAutoPtr fnCall; @@ -1104,7 +1128,7 @@ txStylesheetCompilerState::resolveFunctionCall(nsIAtom* aName, int32_t aID, if (rv == NS_ERROR_XPATH_UNKNOWN_FUNCTION && (aID != kNameSpaceID_None || fcp())) { *aFunction = new txErrorFunctionCall(aName); - rv = *aFunction ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + rv = NS_OK; } return rv; @@ -1130,10 +1154,9 @@ txStylesheetCompilerState::shutdown() sXPCOMFunctionMappings = nullptr; } -txElementContext::txElementContext(const nsAString& aBaseURI) +txElementContext::txElementContext() : mPreserveWhitespace(false), mForwardsCompatibleParsing(true), - mBaseURI(aBaseURI), mMappings(new txNamespaceMap), mDepth(0) { diff --git a/dom/xslt/xslt/txStylesheetCompiler.h b/dom/xslt/xslt/txStylesheetCompiler.h index 7fb0f05d60..b15272160c 100644 --- a/dom/xslt/xslt/txStylesheetCompiler.h +++ b/dom/xslt/xslt/txStylesheetCompiler.h @@ -32,12 +32,12 @@ class txInScopeVariable; class txElementContext : public txObject { public: - explicit txElementContext(const nsAString& aBaseURI); + explicit txElementContext(); txElementContext(const txElementContext& aOther); bool mPreserveWhitespace; bool mForwardsCompatibleParsing; - nsString mBaseURI; + nsCOMPtr mBaseURI; RefPtr mMappings; nsTArray mInstructionNamespaces; int32_t mDepth; @@ -49,9 +49,8 @@ public: NS_IMETHOD_(MozExternalRefCountType) AddRef() = 0; NS_IMETHOD_(MozExternalRefCountType) Release() = 0; - virtual nsresult loadURI(const nsAString& aUri, - const nsAString& aReferrerUri, - mozilla::net::ReferrerPolicy aReferrerPolicy, + virtual nsresult loadURI(nsIURI* aUri, + nsIPrincipal* aReferrerPrincipal, txStylesheetCompiler* aCompiler) = 0; virtual void onDoneCompiling(txStylesheetCompiler* aCompiler, nsresult aResult, @@ -60,8 +59,8 @@ public: }; #define TX_DECL_ACOMPILEOBSERVER \ - nsresult loadURI(const nsAString& aUri, const nsAString& aReferrerUri, \ - mozilla::net::ReferrerPolicy aReferrerPolicy, \ + nsresult loadURI(nsIURI* aUri, \ + nsIPrincipal* aReferrerPrincipal, \ txStylesheetCompiler* aCompiler); \ void onDoneCompiling(txStylesheetCompiler* aCompiler, nsresult aResult, \ const char16_t *aErrorText = nullptr, \ @@ -73,9 +72,8 @@ public: explicit txStylesheetCompilerState(txACompileObserver* aObserver); ~txStylesheetCompilerState(); - nsresult init(const nsAString& aStylesheetURI, - mozilla::net::ReferrerPolicy aReferrerPolicy, - txStylesheet* aStylesheet, txListIterator* aInsertPosition); + nsresult init(const nsString& aFragment, txStylesheet* aStylesheet, + txListIterator* aInsertPosition); // Embedded stylesheets state bool handleEmbeddedSheet() @@ -116,8 +114,8 @@ public: nsresult openInstructionContainer(txInstructionContainer* aContainer); void closeInstructionContainer(); nsresult addInstruction(nsAutoPtr&& aInstruction); - nsresult loadIncludedStylesheet(const nsAString& aURI); - nsresult loadImportedStylesheet(const nsAString& aURI, + nsresult loadIncludedStylesheet(nsIURI* aURI); + nsresult loadImportedStylesheet(nsIURI* aURI, txStylesheet::ImportFrame* aFrame); // misc @@ -166,6 +164,7 @@ public: uint16_t mDisAllowed; protected: + nsCOMPtr mStylesheetPrincipal; RefPtr mObserver; nsTArray mInScopeVariables; nsTArray mChildCompilerList; @@ -178,7 +177,6 @@ protected: eInEmbed, eHasEmbed } mEmbedStatus; - nsString mStylesheetURI; bool mIsTopCompiler; bool mDoneWithThisStylesheet; txStack mObjectStack; @@ -189,7 +187,6 @@ private: txInstruction** mNextInstrPtr; txListIterator mToplevelIterator; nsTArray mGotoTargetPointers; - mozilla::net::ReferrerPolicy mReferrerPolicy; }; struct txStylesheetAttr @@ -207,16 +204,15 @@ public: friend class txStylesheetCompilerState; friend bool TX_XSLTFunctionAvailable(nsIAtom* aName, int32_t aNameSpaceID); - txStylesheetCompiler(const nsAString& aStylesheetURI, - mozilla::net::ReferrerPolicy aReferrerPolicy, + txStylesheetCompiler(const nsString& aFragment, txACompileObserver* aObserver); - txStylesheetCompiler(const nsAString& aStylesheetURI, + txStylesheetCompiler(const nsString& aFragment, txStylesheet* aStylesheet, txListIterator* aInsertPosition, - mozilla::net::ReferrerPolicy aReferrerPolicy, txACompileObserver* aObserver); - void setBaseURI(const nsString& aBaseURI); + void setBaseURI(nsIURI* aBaseURI); + void setPrincipal(nsIPrincipal* aPrincipal); nsresult startElement(int32_t aNamespaceID, nsIAtom* aLocalName, nsIAtom* aPrefix, txStylesheetAttr* aAttributes, diff --git a/dom/xslt/xslt/txXPathResultComparator.cpp b/dom/xslt/xslt/txXPathResultComparator.cpp index e21a9af696..5403089206 100644 --- a/dom/xslt/xslt/txXPathResultComparator.cpp +++ b/dom/xslt/xslt/txXPathResultComparator.cpp @@ -73,10 +73,6 @@ txResultStringComparator::createSortableValue(Expr *aExpr, return NS_ERROR_FAILURE; val->mCaseKey = new nsString; - if (!val->mCaseKey) { - return NS_ERROR_OUT_OF_MEMORY; - } - nsString& nsCaseKey = *(nsString *)val->mCaseKey; nsresult rv = aExpr->evaluateToString(aContext, nsCaseKey); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/xslt/xslt/txXSLTFunctions.h b/dom/xslt/xslt/txXSLTFunctions.h index 1bc0f9961e..ca1921cbd5 100644 --- a/dom/xslt/xslt/txXSLTFunctions.h +++ b/dom/xslt/xslt/txXSLTFunctions.h @@ -23,7 +23,7 @@ public: /** * Creates a new document() function call **/ - explicit DocumentFunctionCall(const nsAString& aBaseURI); + explicit DocumentFunctionCall(nsIURI* aBaseURI); TX_DECL_FUNCTION diff --git a/dom/xslt/xslt/txXSLTNumber.cpp b/dom/xslt/xslt/txXSLTNumber.cpp index f9ca733d8f..237a46ec53 100644 --- a/dom/xslt/xslt/txXSLTNumber.cpp +++ b/dom/xslt/xslt/txXSLTNumber.cpp @@ -137,11 +137,9 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern, { txNodeTypeTest* typeTest; typeTest = new txNodeTypeTest(txNodeTypeTest::PI_TYPE); - if (typeTest) { - nsAutoString nodeName; - txXPathNodeUtils::getNodeName(currNode, nodeName); - typeTest->setNodeName(nodeName); - } + nsAutoString nodeName; + txXPathNodeUtils::getNodeName(currNode, nodeName); + typeTest->setNodeName(nodeName); nodeTest = typeTest; break; } @@ -161,14 +159,8 @@ txXSLTNumber::getValueList(Expr* aValueExpr, txPattern* aCountPattern, break; } } - NS_ENSURE_TRUE(nodeTest, NS_ERROR_OUT_OF_MEMORY); - + MOZ_ASSERT(nodeTest); countPattern = new txStepPattern(nodeTest, false); - if (!countPattern) { - // XXX error reporting - delete nodeTest; - return NS_ERROR_OUT_OF_MEMORY; - } } diff --git a/dom/xslt/xslt/txXSLTNumberCounters.cpp b/dom/xslt/xslt/txXSLTNumberCounters.cpp index 9759744230..66abe438d6 100644 --- a/dom/xslt/xslt/txXSLTNumberCounters.cpp +++ b/dom/xslt/xslt/txXSLTNumberCounters.cpp @@ -80,7 +80,8 @@ txFormattedCounter::getCounterFor(const nsAFlatString& aToken, aGroupSeparator); break; } - return aCounter ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + MOZ_ASSERT(aCounter); + return NS_OK; } // for now, the only multi-char token we support are decimals @@ -96,8 +97,8 @@ txFormattedCounter::getCounterFor(const nsAFlatString& aToken, // if we don't recognize the token then use '1' aCounter = new txDecimalCounter(1, aGroupSize, aGroupSeparator); } - - return aCounter ? NS_OK : NS_ERROR_OUT_OF_MEMORY; + MOZ_ASSERT(aCounter); + return NS_OK; } diff --git a/gfx/layers/Compositor.cpp b/gfx/layers/Compositor.cpp index 2c9152bb8c..43c3ebf665 100644 --- a/gfx/layers/Compositor.cpp +++ b/gfx/layers/Compositor.cpp @@ -354,6 +354,29 @@ DecomposeIntoNoRepeatRects(const gfx::Rect& aRect, return 4; } +gfx::IntRect +Compositor::ComputeBackdropCopyRect(const gfx::Rect& aRect, + const gfx::Rect& aClipRect, + const gfx::Matrix4x4& aTransform) +{ + gfx::Rect renderBounds = mRenderBounds; + + // Compute the clip. + gfx::IntPoint offset = GetCurrentRenderTarget()->GetOrigin(); + renderBounds.IntersectRect(renderBounds, aClipRect); + renderBounds.MoveBy(offset); + + // Apply the layer transform. + gfx::Rect dest = aTransform.TransformAndClipBounds(aRect, renderBounds); + dest -= offset; + + // Round out to integer. + gfx::IntRect result; + dest.RoundOut(); + dest.ToIntRect(&result); + return result; +} + #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 void Compositor::SetDispAcquireFence(Layer* aLayer, nsIWidget* aWidget) diff --git a/gfx/layers/Compositor.h b/gfx/layers/Compositor.h index e924e761f9..5415f949d0 100644 --- a/gfx/layers/Compositor.h +++ b/gfx/layers/Compositor.h @@ -514,6 +514,16 @@ protected: bool ShouldDrawDiagnostics(DiagnosticFlags); + /** + * Given a layer rect, clip, and transform, compute the area of the backdrop that + * needs to be copied for mix-blending. The output transform translates from 0..1 + * space into the backdrop rect space. + */ + gfx::IntRect ComputeBackdropCopyRect( + const gfx::Rect& aRect, + const gfx::Rect& aClipRect, + const gfx::Matrix4x4& aTransform); + /** * Render time for the current composition. */ @@ -542,6 +552,8 @@ protected: RefPtr mTarget; gfx::IntRect mTargetBounds; + gfx::Rect mRenderBounds; + #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 FenceHandle mReleaseFenceHandle; #endif diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index d4ca10aa13..577c618d54 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -206,6 +206,7 @@ static void DestroyTextureData(TextureData* aTextureData, ISurfaceAllocator* aAl void TextureChild::ActorDestroy(ActorDestroyReason why) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS); mWaitForRecycle = nullptr; if (mTextureData) { diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index 27ba02bcb3..f18dd86e43 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -454,7 +454,7 @@ CompositorOGL::PrepareViewport(CompositingRenderTargetOGL* aRenderTarget) // Set the viewport correctly. mGLContext->fViewport(0, 0, size.width, size.height); - mRenderBound = Rect(0, 0, size.width, size.height); + mRenderBounds = Rect(0, 0, size.width, size.height); mViewportSize = size; @@ -990,7 +990,7 @@ CompositorOGL::DrawQuad(const Rect& aRect, } IntPoint offset = mCurrentRenderTarget->GetOrigin(); - Rect renderBound = mRenderBound; + Rect renderBound = mRenderBounds; renderBound.IntersectRect(renderBound, aClipRect); renderBound.MoveBy(offset); @@ -1004,7 +1004,7 @@ CompositorOGL::DrawQuad(const Rect& aRect, // Inflate a small size to avoid some numerical imprecision issue. destRect.Inflate(1, 1); destRect.MoveBy(-offset); - if (!mRenderBound.Intersects(destRect)) { + if (!mRenderBounds.Intersects(destRect)) { return; } @@ -1082,11 +1082,6 @@ CompositorOGL::DrawQuad(const Rect& aRect, EffectBlendMode *blendEffect = static_cast(aEffectChain.mSecondaryEffects[EffectTypes::BLEND_MODE].get()); blendMode = blendEffect->mBlendMode; - if (BlendOpIsMixBlendMode(blendMode)) { - gfx::IntRect rect(gfx::IntPoint(0, 0), mCurrentRenderTarget->GetSize()); - - mixBlendBackdrop = CreateTexture(rect, true, mCurrentRenderTarget->GetFBO()); - } } // Only apply DEAA to quads that have been transformed such that aliasing @@ -1110,6 +1105,20 @@ CompositorOGL::DrawQuad(const Rect& aRect, program->SetColorMatrix(effectColorMatrix->mColorMatrix); } + if (BlendOpIsMixBlendMode(blendMode)) { + gfx::IntRect rect = ComputeBackdropCopyRect(aRect, aClipRect, aTransform); + mixBlendBackdrop = CreateTexture(rect, true, mCurrentRenderTarget->GetFBO()); + + // Create a transform from adjusted clip space to render target space, + // translate it for the backdrop rect, then transform it into the backdrop's + // uv-space. + gfx::Matrix4x4 transform; + transform.PostScale(mRenderBounds.width, mRenderBounds.height, 1.0); + transform.PostTranslate(-rect.x, -rect.y, 0.0); + transform.PostScale(1 / float(rect.width), 1 / float(rect.height), 1.0); + program->SetBackdropTransform(transform); + } + program->SetRenderOffset(offset.x, offset.y); LayerScope::SetRenderOffset(offset.x, offset.y); diff --git a/gfx/layers/opengl/CompositorOGL.h b/gfx/layers/opengl/CompositorOGL.h index cea8e31b6f..bde7a43109 100644 --- a/gfx/layers/opengl/CompositorOGL.h +++ b/gfx/layers/opengl/CompositorOGL.h @@ -488,8 +488,6 @@ private: ShaderProgramOGL *mCurrentProgram; - gfx::Rect mRenderBound; - CompositorOGLVRObjects mVR; #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21 diff --git a/gfx/layers/opengl/OGLShaderProgram.cpp b/gfx/layers/opengl/OGLShaderProgram.cpp index f945f07506..fa6966d08a 100644 --- a/gfx/layers/opengl/OGLShaderProgram.cpp +++ b/gfx/layers/opengl/OGLShaderProgram.cpp @@ -30,6 +30,7 @@ AddUniforms(ProgramProfileOGL& aProfile) "uLayerTransform", "uLayerTransformInverse", "uMaskTransform", + "uBackdropTransform", "uLayerRects", "uMatrixProj", "uTextureTransform", @@ -200,6 +201,7 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig) } if (BlendOpIsMixBlendMode(blendOp)) { + vs << "uniform mat4 uBackdropTransform;" << endl; vs << "varying vec2 vBackdropCoord;" << endl; } @@ -287,8 +289,12 @@ ProgramProfileOGL::GetProfileFor(ShaderConfigOGL aConfig) vs << " finalPosition.xy -= uRenderTargetOffset * finalPosition.w;" << endl; vs << " finalPosition = uMatrixProj * finalPosition;" << endl; if (BlendOpIsMixBlendMode(blendOp)) { - // Move from clip space coordinates into texture/uv-coordinates. - vs << " vBackdropCoord = (finalPosition.xy + vec2(1.0, 1.0)) / 2.0;" << endl; + // Translate from clip space (-1, 1) to (0..1), apply the backdrop + // transform, then invert the y-axis. + vs << " vBackdropCoord.x = (finalPosition.x + 1.0) / 2.0;" << endl; + vs << " vBackdropCoord.y = 1.0 - (finalPosition.y + 1.0) / 2.0;" << endl; + vs << " vBackdropCoord = (uBackdropTransform * vec4(vBackdropCoord.xy, 0.0, 1.0)).xy;" << endl; + vs << " vBackdropCoord.y = 1.0 - vBackdropCoord.y;" << endl; } vs << " gl_Position = finalPosition;" << endl; vs << "}" << endl; diff --git a/gfx/layers/opengl/OGLShaderProgram.h b/gfx/layers/opengl/OGLShaderProgram.h index b33a9af383..d10749f50f 100644 --- a/gfx/layers/opengl/OGLShaderProgram.h +++ b/gfx/layers/opengl/OGLShaderProgram.h @@ -52,6 +52,7 @@ public: LayerTransform = 0, LayerTransformInverse, MaskTransform, + BackdropTransform, LayerRects, MatrixProj, TextureTransform, @@ -352,6 +353,10 @@ public: SetMatrixUniform(KnownUniform::MaskTransform, aMatrix); } + void SetBackdropTransform(const gfx::Matrix4x4& aMatrix) { + SetMatrixUniform(KnownUniform::BackdropTransform, aMatrix); + } + void SetDEAAEdges(const gfx::Point3D* aEdges) { SetArrayUniform(KnownUniform::SSEdges, 4, aEdges); } diff --git a/gfx/tests/browser/browser.ini b/gfx/tests/browser/browser.ini new file mode 100644 index 0000000000..0a1902f0ea --- /dev/null +++ b/gfx/tests/browser/browser.ini @@ -0,0 +1,4 @@ +[DEFAULT] +support-files = + +[browser_windowless_troubleshoot_crash.js] diff --git a/gfx/tests/browser/browser_windowless_troubleshoot_crash.js b/gfx/tests/browser/browser_windowless_troubleshoot_crash.js new file mode 100644 index 0000000000..f78a91c725 --- /dev/null +++ b/gfx/tests/browser/browser_windowless_troubleshoot_crash.js @@ -0,0 +1,45 @@ +let { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); + +add_task(function* test_windowlessBrowserTroubleshootCrash() { + let webNav = Services.appShell.createWindowlessBrowser(false); + + let onLoaded = new Promise((resolve, reject) => { + let docShell = webNav.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDocShell); + let listener = { + observe(contentWindow, topic, data) { + let observedDocShell = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShellTreeItem) + .sameTypeRootTreeItem + .QueryInterface(Ci.nsIDocShell); + if (docShell === observedDocShell) { + Services.obs.removeObserver(listener, "content-document-global-created", false); + resolve(); + } + } + } + Services.obs.addObserver(listener, "content-document-global-created", false); + }); + webNav.loadURI("about:blank", 0, null, null, null); + + yield onLoaded; + + let winUtils = webNav.document.defaultView. + QueryInterface(Ci.nsIInterfaceRequestor). + getInterface(Ci.nsIDOMWindowUtils); + is(winUtils.layerManagerType, "None", "windowless browser's layerManagerType should be 'None'"); + + ok(true, "not crashed"); + + var Troubleshoot = Cu.import("resource://gre/modules/Troubleshoot.jsm", {}).Troubleshoot; + var data = yield new Promise((resolve, reject) => { + Troubleshoot.snapshot((data) => { + resolve(data); + }); + }); + + ok(data.graphics.windowLayerManagerType !== "None", "windowless browser window should not set windowLayerManagerType to 'None'"); + + webNav.close(); +}); diff --git a/gfx/tests/moz.build b/gfx/tests/moz.build index b985130de0..696ca9a9b0 100644 --- a/gfx/tests/moz.build +++ b/gfx/tests/moz.build @@ -6,3 +6,4 @@ XPCSHELL_TESTS_MANIFESTS += ['unit/xpcshell.ini'] MOCHITEST_MANIFESTS += ['mochitest/mochitest.ini'] +BROWSER_CHROME_MANIFESTS += ['browser/browser.ini'] diff --git a/gfx/thebes/gfxDWriteFontList.cpp b/gfx/thebes/gfxDWriteFontList.cpp index 4f5a5a015f..d61037e219 100644 --- a/gfx/thebes/gfxDWriteFontList.cpp +++ b/gfx/thebes/gfxDWriteFontList.cpp @@ -524,6 +524,8 @@ gfxDWriteFontEntry::GetFontTable(uint32_t aTag) nsresult gfxDWriteFontEntry::ReadCMAP(FontInfoData *aFontInfoData) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS); + // attempt this once, if errors occur leave a blank cmap if (mCharacterMap) { return NS_OK; diff --git a/gfx/thebes/gfxGDIFontList.cpp b/gfx/thebes/gfxGDIFontList.cpp index e9d6f682ee..3dc20d1292 100644 --- a/gfx/thebes/gfxGDIFontList.cpp +++ b/gfx/thebes/gfxGDIFontList.cpp @@ -24,6 +24,7 @@ #include "nsISimpleEnumerator.h" #include "nsIWindowsRegKey.h" #include "gfxFontConstants.h" +#include "GeckoProfiler.h" #include "mozilla/MemoryReporting.h" #include "mozilla/Telemetry.h" @@ -143,6 +144,8 @@ GDIFontEntry::GDIFontEntry(const nsAString& aFaceName, nsresult GDIFontEntry::ReadCMAP(FontInfoData *aFontInfoData) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + // attempt this once, if errors occur leave a blank cmap if (mCharacterMap) { return NS_OK; diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 451c683f17..d78e550f0a 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -21,6 +21,7 @@ #include "nsServiceManagerUtils.h" #include "nsTArray.h" #include "mozilla/Telemetry.h" +#include "GeckoProfiler.h" #include "nsIWindowsRegKey.h" #include "nsIFile.h" @@ -1199,6 +1200,8 @@ InvalidateWindowForDeviceReset(HWND aWnd, LPARAM aMsg) bool gfxWindowsPlatform::UpdateForDeviceReset() { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS); + if (!DidRenderingDeviceReset()) { return false; } diff --git a/image/FrameAnimator.cpp b/image/FrameAnimator.cpp index f87ce242e0..f1d8faea74 100644 --- a/image/FrameAnimator.cpp +++ b/image/FrameAnimator.cpp @@ -79,6 +79,7 @@ FrameAnimator::AdvanceFrame(TimeStamp aTime) { NS_ASSERTION(aTime <= TimeStamp::Now(), "Given time appears to be in the future"); + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::GRAPHICS); uint32_t currentFrameIndex = mCurrentAnimationFrameIndex; uint32_t nextFrameIndex = currentFrameIndex + 1; diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp index 201aac1ecc..5f321d8fc9 100644 --- a/ipc/glue/GeckoChildProcessHost.cpp +++ b/ipc/glue/GeckoChildProcessHost.cpp @@ -380,6 +380,8 @@ GeckoChildProcessHost::AsyncLaunch(std::vector aExtraOpts, bool GeckoChildProcessHost::WaitUntilConnected(int32_t aTimeoutMs) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + // NB: this uses a different mechanism than the chromium parent // class. PRIntervalTime timeoutTicks = (aTimeoutMs > 0) ? diff --git a/js/ipc/JavaScriptShared.cpp b/js/ipc/JavaScriptShared.cpp index df3383145b..aa19bc2bfd 100644 --- a/js/ipc/JavaScriptShared.cpp +++ b/js/ipc/JavaScriptShared.cpp @@ -522,7 +522,7 @@ JavaScriptShared::findObjectById(JSContext* cx, const ObjectId& objId) static const uint64_t UnknownPropertyOp = 1; bool -JavaScriptShared::fromDescriptor(JSContext* cx, Handle desc, +JavaScriptShared::fromDescriptor(JSContext* cx, Handle desc, PPropertyDescriptor* out) { out->attrs() = desc.attributes(); @@ -578,7 +578,7 @@ UnknownStrictPropertyStub(JSContext* cx, HandleObject obj, HandleId id, MutableH bool JavaScriptShared::toDescriptor(JSContext* cx, const PPropertyDescriptor& in, - MutableHandle out) + MutableHandle out) { out.setAttributes(in.attrs()); if (!fromVariant(cx, in.value(), out.value())) diff --git a/js/ipc/JavaScriptShared.h b/js/ipc/JavaScriptShared.h index 6b6d0bde86..01803bd530 100644 --- a/js/ipc/JavaScriptShared.h +++ b/js/ipc/JavaScriptShared.h @@ -155,10 +155,10 @@ class JavaScriptShared : public CPOWManager bool toSymbolVariant(JSContext* cx, JS::Symbol* sym, SymbolVariant* symVarp); JS::Symbol* fromSymbolVariant(JSContext* cx, SymbolVariant symVar); - bool fromDescriptor(JSContext* cx, JS::Handle desc, + bool fromDescriptor(JSContext* cx, JS::Handle desc, PPropertyDescriptor* out); bool toDescriptor(JSContext* cx, const PPropertyDescriptor& in, - JS::MutableHandle out); + JS::MutableHandle out); bool toObjectOrNullVariant(JSContext* cx, JSObject* obj, ObjectOrNullVariant* objVarp); JSObject* fromObjectOrNullVariant(JSContext* cx, ObjectOrNullVariant objVar); diff --git a/js/ipc/WrapperAnswer.cpp b/js/ipc/WrapperAnswer.cpp index f9e2c8c5ac..06aac55d64 100644 --- a/js/ipc/WrapperAnswer.cpp +++ b/js/ipc/WrapperAnswer.cpp @@ -124,7 +124,7 @@ WrapperAnswer::RecvGetPropertyDescriptor(const ObjectId& objId, const JSIDVarian if (!fromJSIDVariant(cx, idVar, &id)) return fail(jsapi, rs); - Rooted desc(cx); + Rooted desc(cx); if (!JS_GetPropertyDescriptorById(cx, obj, id, &desc)) return fail(jsapi, rs); @@ -155,7 +155,7 @@ WrapperAnswer::RecvGetOwnPropertyDescriptor(const ObjectId& objId, const JSIDVar if (!fromJSIDVariant(cx, idVar, &id)) return fail(jsapi, rs); - Rooted desc(cx); + Rooted desc(cx); if (!JS_GetOwnPropertyDescriptorById(cx, obj, id, &desc)) return fail(jsapi, rs); @@ -185,7 +185,7 @@ WrapperAnswer::RecvDefineProperty(const ObjectId& objId, const JSIDVariant& idVa if (!fromJSIDVariant(cx, idVar, &id)) return fail(jsapi, rs); - Rooted desc(cx); + Rooted desc(cx); if (!toDescriptor(cx, descriptor, &desc)) return fail(jsapi, rs); diff --git a/js/ipc/WrapperOwner.cpp b/js/ipc/WrapperOwner.cpp index 6009307035..c22c451823 100644 --- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -98,9 +98,9 @@ class CPOWProxyHandler : public BaseProxyHandler } virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const override; @@ -119,7 +119,7 @@ class CPOWProxyHandler : public BaseProxyHandler virtual bool construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const override; virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const override; @@ -145,6 +145,7 @@ const char CPOWProxyHandler::family = 0; const CPOWProxyHandler CPOWProxyHandler::singleton; #define FORWARD(call, args) \ + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::JS); \ WrapperOwner* owner = OwnerOf(proxy); \ if (!owner->active()) { \ JS_ReportError(cx, "cannot use a CPOW whose process is gone"); \ @@ -160,14 +161,14 @@ const CPOWProxyHandler CPOWProxyHandler::singleton; bool CPOWProxyHandler::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const + MutableHandle desc) const { FORWARD(getPropertyDescriptor, (cx, proxy, id, desc)); } bool WrapperOwner::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) + MutableHandle desc) { ObjectId objId = idOf(proxy); @@ -190,14 +191,14 @@ WrapperOwner::getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId bool CPOWProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const + MutableHandle desc) const { FORWARD(getOwnPropertyDescriptor, (cx, proxy, id, desc)); } bool WrapperOwner::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) + MutableHandle desc) { ObjectId objId = idOf(proxy); @@ -220,7 +221,7 @@ WrapperOwner::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, Handle bool CPOWProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const { FORWARD(defineProperty, (cx, proxy, id, desc, result)); @@ -228,7 +229,7 @@ CPOWProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id, bool WrapperOwner::defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) { ObjectId objId = idOf(proxy); @@ -451,7 +452,7 @@ WrapperOwner::DOMQI(JSContext* cx, JS::HandleObject proxy, JS::CallArgs& args) // We could stash the actual QI function on our own function object to avoid // if we're called multiple times, but since we're transient, there's no // point right now. - JS::Rooted propDesc(cx); + JS::Rooted propDesc(cx); if (!JS_GetPropertyDescriptor(cx, proxy, "QueryInterface", &propDesc)) return false; diff --git a/js/ipc/WrapperOwner.h b/js/ipc/WrapperOwner.h index 2e05d1d2c5..ab5de8f2c1 100644 --- a/js/ipc/WrapperOwner.h +++ b/js/ipc/WrapperOwner.h @@ -30,9 +30,9 @@ class WrapperOwner : public virtual JavaScriptShared // Standard internal methods. // (The traps should be in the same order like js/Proxy.h) bool getOwnPropertyDescriptor(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); bool defineProperty(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); bool ownPropertyKeys(JSContext* cx, JS::HandleObject proxy, JS::AutoIdVector& props); bool delete_(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, @@ -49,7 +49,7 @@ class WrapperOwner : public virtual JavaScriptShared // SpiderMonkey extensions. bool getPropertyDescriptor(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); bool hasOwn(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, bool* bp); bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::HandleObject proxy, JS::AutoIdVector& props); diff --git a/js/public/Class.h b/js/public/Class.h index 8745564de7..83b200faf6 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -412,7 +412,7 @@ typedef bool JS::MutableHandleObject objp, JS::MutableHandle propp); typedef bool (* DefinePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); typedef bool (* HasPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); @@ -424,7 +424,7 @@ typedef bool JS::HandleValue receiver, JS::ObjectOpResult& result); typedef bool (* GetOwnPropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); typedef bool (* DeletePropertyOp)(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result); diff --git a/js/public/GCHashTable.h b/js/public/GCHashTable.h index cbc59d8534..a8be05b65c 100644 --- a/js/public/GCHashTable.h +++ b/js/public/GCHashTable.h @@ -49,8 +49,7 @@ template , typename AllocPolicy = TempAllocPolicy, typename MapSweepPolicy = DefaultMapSweepPolicy> -class GCHashMap : public HashMap, - public JS::Traceable +class GCHashMap : public HashMap { using Base = HashMap; @@ -226,8 +225,7 @@ class HandleBase> template , typename AllocPolicy = TempAllocPolicy> -class GCHashSet : public HashSet, - public JS::Traceable +class GCHashSet : public HashSet { using Base = HashSet; diff --git a/js/public/GCVector.h b/js/public/GCVector.h index 37db34e988..53c05976e4 100644 --- a/js/public/GCVector.h +++ b/js/public/GCVector.h @@ -33,7 +33,7 @@ namespace js { template -class GCVector : public JS::Traceable +class GCVector { mozilla::Vector vector; diff --git a/js/public/Proxy.h b/js/public/Proxy.h index b318d68694..2ec8ce7378 100644 --- a/js/public/Proxy.h +++ b/js/public/Proxy.h @@ -29,6 +29,7 @@ using JS::MutableHandleValue; using JS::NativeImpl; using JS::ObjectOpResult; using JS::PrivateValue; +using JS::PropertyDescriptor; using JS::Value; class RegExpGuard; @@ -251,9 +252,9 @@ class JS_FRIEND_API(BaseProxyHandler) /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const = 0; + MutableHandle desc) const = 0; virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const = 0; virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const = 0; @@ -315,7 +316,7 @@ class JS_FRIEND_API(BaseProxyHandler) /* SpiderMonkey extensions. */ virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const; + MutableHandle desc) const; virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const; @@ -374,9 +375,9 @@ class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const override; @@ -404,7 +405,7 @@ class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler /* SpiderMonkey extensions. */ virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index 6d6afe60ec..4d04d95d72 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -581,28 +581,15 @@ struct JS_EXPORT_API(MovableCellHasher>) } /* namespace js */ -namespace JS { - -// Non pointer types -- structs or classes that contain GC pointers, either as -// a member or in a more complex container layout -- can also be stored in a -// [Persistent]Rooted if it derives from JS::Traceable. A JS::Traceable stored -// in a [Persistent]Rooted must implement the method: -// |static void trace(T*, JSTracer*)| -class Traceable -{ -}; - -} /* namespace JS */ - namespace js { template class DispatchWrapper { - static_assert(mozilla::IsBaseOf::value, + static_assert(JS::MapTypeToRootKind::kind == JS::RootKind::Traceable, "DispatchWrapper is intended only for usage with a Traceable"); - using TraceFn = void (*)(T*, JSTracer*); + using TraceFn = void (*)(JSTracer*, T*, const char*); TraceFn tracer; #if JS_BITS_PER_WORD == 32 uint32_t padding; // Ensure the storage fields have CellSize alignment. @@ -612,7 +599,7 @@ class DispatchWrapper public: template MOZ_IMPLICIT DispatchWrapper(U&& initial) - : tracer(&T::trace), + : tracer(&GCPolicy::trace), storage(mozilla::Forward(initial)) { } @@ -624,10 +611,10 @@ class DispatchWrapper // Trace the contained storage (of unknown type) using the trace function // we set aside when we did know the type. - static void TraceWrapped(JSTracer* trc, JS::Traceable* thingp, const char* name) { + static void TraceWrapped(JSTracer* trc, T* thingp, const char* name) { auto wrapper = reinterpret_cast( uintptr_t(thingp) - offsetof(DispatchWrapper, storage)); - wrapper->tracer(&wrapper->storage, trc); + wrapper->tracer(trc, &wrapper->storage, name); } }; @@ -670,9 +657,6 @@ namespace JS { template class MOZ_RAII Rooted : public js::RootedBase { - static_assert(!mozilla::IsConvertible::value, - "Rooted takes pointer or Traceable types but not Traceable* type"); - /* Note: CX is a subclass of either ContextFriendFields or PerThreadDataFriendFields. */ void registerWithRootLists(js::RootLists& roots) { this->stack = &roots.stackRoots_[JS::MapTypeToRootKind::kind]; @@ -727,14 +711,14 @@ class MOZ_RAII Rooted : public js::RootedBase /* * For pointer types, the TraceKind for tracing is based on the list it is - * in (selected via rootKind), so no additional storage is required here. - * All Traceable, however, share the same list, so the function to - * call for tracing is stored adjacent to the struct. Since C++ cannot - * templatize on storage class, this is implemented via the wrapper class - * DispatchWrapper. + * in (selected via MapTypeToRootKind), so no additional storage is + * required here. Non-pointer types, however, share the same list, so the + * function to call for tracing is stored adjacent to the struct. Since C++ + * cannot templatize on storage class, this is implemented via the wrapper + * class DispatchWrapper. */ using MaybeWrapped = typename mozilla::Conditional< - mozilla::IsBaseOf::value, + MapTypeToRootKind::kind == JS::RootKind::Traceable, js::DispatchWrapper, T>::Type; MaybeWrapped ptr; @@ -1071,7 +1055,7 @@ class PersistentRooted : public js::PersistentRootedBase, // See the comment above Rooted::ptr. using MaybeWrapped = typename mozilla::Conditional< - mozilla::IsBaseOf::value, + MapTypeToRootKind::kind == JS::RootKind::Traceable, js::DispatchWrapper, T>::Type; diff --git a/js/public/UbiNode.h b/js/public/UbiNode.h index 653fb0a89b..7abc88a838 100644 --- a/js/public/UbiNode.h +++ b/js/public/UbiNode.h @@ -308,7 +308,7 @@ template class ConcreteStackFrame; // valid within the scope of an AutoCheckCannotGC; if the graph being analyzed // is an offline heap snapshot, the JS::ubi::StackFrame is valid as long as the // offline heap snapshot is alive. -class JS_FRIEND_API(StackFrame) : public JS::Traceable { +class JS_FRIEND_API(StackFrame) { // Storage in which we allocate BaseStackFrame subclasses. mozilla::AlignedStorage2 storage; @@ -398,12 +398,6 @@ class JS_FRIEND_API(StackFrame) : public JS::Traceable { size_t sourceLength(); size_t functionDisplayNameLength(); - // JS::Traceable implementation just forwards to our virtual trace method. - static void trace(StackFrame* frame, JSTracer* trc) { - if (frame) - frame->trace(trc); - } - // Methods that forward to virtual calls through BaseStackFrame. void trace(JSTracer* trc) { base()->trace(trc); } diff --git a/js/public/Utility.h b/js/public/Utility.h index 470c4bec09..8c2a7d1b92 100644 --- a/js/public/Utility.h +++ b/js/public/Utility.h @@ -235,6 +235,11 @@ static inline void* js_calloc(size_t nmemb, size_t size) static inline void* js_realloc(void* p, size_t bytes) { + // realloc() with zero size is not portable, as some implementations may + // return nullptr on success and free |p| for this. We assume nullptr + // indicates failure and that |p| is still valid. + MOZ_ASSERT(bytes != 0); + JS_OOM_POSSIBLY_FAIL(); return realloc(p, bytes); } diff --git a/js/src/NamespaceImports.h b/js/src/NamespaceImports.h index 3db0bb42f4..81df88516e 100644 --- a/js/src/NamespaceImports.h +++ b/js/src/NamespaceImports.h @@ -49,6 +49,8 @@ class MOZ_STACK_CLASS SourceBufferHolder; class HandleValueArray; class ObjectOpResult; + +struct PropertyDescriptor; } // namespace JS // Do the importing. @@ -148,6 +150,8 @@ using JS::HandleValueArray; using JS::ObjectOpResult; +using JS::PropertyDescriptor; + using JS::Zone; } /* namespace js */ diff --git a/js/src/asmjs/WasmStubs.cpp b/js/src/asmjs/WasmStubs.cpp index 27df2eb4aa..806b838ec1 100644 --- a/js/src/asmjs/WasmStubs.cpp +++ b/js/src/asmjs/WasmStubs.cpp @@ -407,7 +407,12 @@ GenerateInterpExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffse case ExprType::I64: MOZ_CRASH("no int64 in asm.js"); case ExprType::F32: - MOZ_CRASH("Float32 shouldn't be returned from a FFI"); + MOZ_ASSERT(!mg.isAsmJS(), "import can't return float32 in asm.js"); + masm.call(SymbolicAddress::InvokeImport_F64); + masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw); + masm.loadDouble(argv, ReturnDoubleReg); + masm.convertDoubleToFloat32(ReturnDoubleReg, ReturnFloat32Reg); + break; case ExprType::F64: masm.call(SymbolicAddress::InvokeImport_F64); masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw); @@ -657,7 +662,9 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffsets* case ExprType::I64: MOZ_CRASH("no int64 in asm.js"); case ExprType::F32: - MOZ_CRASH("Float shouldn't be returned from an import"); + MOZ_ASSERT(!mg.isAsmJS(), "import can't return float32 in asm.js"); + masm.convertValueToFloat(JSReturnOperand, ReturnFloat32Reg, &oolConvert); + break; case ExprType::F64: masm.convertValueToDouble(JSReturnOperand, ReturnDoubleReg, &oolConvert); break; @@ -719,6 +726,13 @@ GenerateJitExitStub(ModuleGenerator& mg, unsigned importIndex, ProfilingOffsets* masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw); masm.loadDouble(Address(masm.getStackPointer(), offsetToCoerceArgv), ReturnDoubleReg); break; + case ExprType::F32: + MOZ_ASSERT(!mg.isAsmJS(), "import can't return float32 in asm.js"); + masm.call(SymbolicAddress::CoerceInPlace_ToNumber); + masm.branchTest32(Assembler::Zero, ReturnReg, ReturnReg, JumpTarget::Throw); + masm.loadDouble(Address(masm.getStackPointer(), offsetToCoerceArgv), ReturnDoubleReg); + masm.convertDoubleToFloat32(ReturnDoubleReg, ReturnFloat32Reg); + break; default: MOZ_CRASH("Unsupported convert type"); } diff --git a/js/src/builtin/MapObject.h b/js/src/builtin/MapObject.h index 1118675f87..a3d57f7dd3 100644 --- a/js/src/builtin/MapObject.h +++ b/js/src/builtin/MapObject.h @@ -22,7 +22,7 @@ namespace js { * * All values except ropes are hashable as-is. */ -class HashableValue : public JS::Traceable +class HashableValue { PreBarrieredValue value; @@ -43,8 +43,8 @@ class HashableValue : public JS::Traceable HashableValue mark(JSTracer* trc) const; Value get() const { return value.get(); } - static void trace(HashableValue* value, JSTracer* trc) { - TraceEdge(trc, &value->value, "HashableValue"); + void trace(JSTracer* trc) { + TraceEdge(trc, &value, "HashableValue"); } }; diff --git a/js/src/builtin/ModuleObject.cpp b/js/src/builtin/ModuleObject.cpp index 4520a3045f..8f48ca66e9 100644 --- a/js/src/builtin/ModuleObject.cpp +++ b/js/src/builtin/ModuleObject.cpp @@ -377,7 +377,7 @@ ModuleNamespaceObject::ProxyHandler::preventExtensions(JSContext* cx, HandleObje bool ModuleNamespaceObject::ProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const + MutableHandle desc) const { Rooted ns(cx, &proxy->as()); if (JSID_IS_SYMBOL(id)) { @@ -417,7 +417,7 @@ ModuleNamespaceObject::ProxyHandler::getOwnPropertyDescriptor(JSContext* cx, Han bool ModuleNamespaceObject::ProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const { return result.failReadOnly(); diff --git a/js/src/builtin/ModuleObject.h b/js/src/builtin/ModuleObject.h index 024d8291b8..1bf80aa9ba 100644 --- a/js/src/builtin/ModuleObject.h +++ b/js/src/builtin/ModuleObject.h @@ -152,9 +152,9 @@ class ModuleNamespaceObject : public ProxyObject JS::Value getEnumerateFunction(HandleObject proxy) const; bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; bool ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const override; diff --git a/js/src/builtin/Reflect.cpp b/js/src/builtin/Reflect.cpp index 61eaa583d0..2f75a53459 100644 --- a/js/src/builtin/Reflect.cpp +++ b/js/src/builtin/Reflect.cpp @@ -140,7 +140,7 @@ Reflect_defineProperty(JSContext* cx, unsigned argc, Value* vp) return false; // Steps 4-5. - Rooted desc(cx); + Rooted desc(cx); if (!ToPropertyDescriptor(cx, args.get(2), true, &desc)) return false; diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index eba0214656..eb910da2e8 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -475,8 +475,8 @@ regexp_global_impl(JSContext* cx, const CallArgs& args) return true; } -static bool -regexp_global(JSContext* cx, unsigned argc, JS::Value* vp) +bool +js::regexp_global(JSContext* cx, unsigned argc, JS::Value* vp) { /* Steps 1-3. */ CallArgs args = CallArgsFromVp(argc, vp); @@ -495,8 +495,8 @@ regexp_ignoreCase_impl(JSContext* cx, const CallArgs& args) return true; } -static bool -regexp_ignoreCase(JSContext* cx, unsigned argc, JS::Value* vp) +bool +js::regexp_ignoreCase(JSContext* cx, unsigned argc, JS::Value* vp) { /* Steps 1-3. */ CallArgs args = CallArgsFromVp(argc, vp); @@ -515,8 +515,8 @@ regexp_multiline_impl(JSContext* cx, const CallArgs& args) return true; } -static bool -regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp) +bool +js::regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp) { /* Steps 1-3. */ CallArgs args = CallArgsFromVp(argc, vp); @@ -564,8 +564,8 @@ regexp_sticky_impl(JSContext* cx, const CallArgs& args) return true; } -static bool -regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp) +bool +js::regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp) { /* Steps 1-3. */ CallArgs args = CallArgsFromVp(argc, vp); @@ -582,8 +582,8 @@ regexp_unicode_impl(JSContext* cx, const CallArgs& args) return true; } -static bool -regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp) +bool +js::regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp) { /* Steps 1-3. */ CallArgs args = CallArgsFromVp(argc, vp); diff --git a/js/src/builtin/RegExp.h b/js/src/builtin/RegExp.h index ee3a2555b2..2216651c22 100644 --- a/js/src/builtin/RegExp.h +++ b/js/src/builtin/RegExp.h @@ -98,6 +98,18 @@ extern const JSPropertySpec regexp_static_props[]; extern const JSPropertySpec regexp_properties[]; extern const JSFunctionSpec regexp_methods[]; +// Used in RegExpObject::isOriginalFlagGetter. +extern bool +regexp_global(JSContext* cx, unsigned argc, JS::Value* vp); +extern bool +regexp_ignoreCase(JSContext* cx, unsigned argc, JS::Value* vp); +extern bool +regexp_multiline(JSContext* cx, unsigned argc, JS::Value* vp); +extern bool +regexp_sticky(JSContext* cx, unsigned argc, JS::Value* vp); +extern bool +regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp); + } /* namespace js */ #endif /* builtin_RegExp_h */ diff --git a/js/src/builtin/SIMD.cpp b/js/src/builtin/SIMD.cpp index 1702ddab59..133b4fd87f 100644 --- a/js/src/builtin/SIMD.cpp +++ b/js/src/builtin/SIMD.cpp @@ -39,21 +39,6 @@ using mozilla::NumberIsInt32; static_assert(unsigned(SimdType::Count) == 12, "sync with TypedObjectConstants.h"); -bool -js::IsSignedIntSimdType(SimdType type) -{ - switch (type) { - case SimdType::Int32x4: - return true; - case SimdType::Float32x4: - case SimdType::Bool32x4: - return false; - default: - break; - } - MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Unknown SIMD type"); -} - PropertyName* js::SimdTypeToName(JSContext* cx, SimdType type) { @@ -140,7 +125,7 @@ static SimdTypeDescr* GetTypeDescr(JSContext* cx) { RootedGlobalObject global(cx, cx->global()); - return GlobalObject::getOrCreateSimdTypeDescr(cx, global); + return GlobalObject::getOrCreateSimdTypeDescr(cx, global, T::type); } template @@ -221,10 +206,15 @@ static const JSFunctionSpec SimdTypedObjectMethods[] = { // // The JS_INLINABLE_FN macro refers to js::JitInfo_##native which we provide as // Simd##Type##_##Operation +// +// /!\ Don't forget to keep this list in sync with the SIMD instrinics used in +// SelfHosting.cpp. namespace js { namespace jit { +static_assert(uint64_t(SimdOperation::Last) <= UINT16_MAX, "SimdOperation must fit in uint16_t"); + // See also JitInfo_* in MCallOptimize.cpp. We provide a JSJitInfo for all the // named functions here. The default JitInfo_SimdInt32x4 etc structs represent the // SimdOperation::Constructor. @@ -249,6 +239,10 @@ FLOAT32X4_FUNCTION_LIST(TDEFN) INT32X4_FUNCTION_LIST(TDEFN) #undef TDEFN +#define TDEFN(Name, Func, Operands) DEFN(Uint32x4, Name) +UINT32X4_FUNCTION_LIST(TDEFN) +#undef TDEFN + #define TDEFN(Name, Func, Operands) DEFN(Bool32x4, Name) BOOL32X4_FUNCTION_LIST(TDEFN) #undef TDEFN @@ -314,7 +308,7 @@ const JSFunctionSpec Uint16x8Defn::Methods[] = { const JSFunctionSpec Uint32x4Defn::Methods[] = { #define SIMD_UINT32X4_FUNCTION_ITEM(Name, Func, Operands) \ - JS_FN(#Name, js::simd_uint32x4_##Name, Operands, 0), + JS_INLINABLE_FN(#Name, js::simd_uint32x4_##Name, Operands, 0, SimdUint32x4_##Name), UINT32X4_FUNCTION_LIST(SIMD_UINT32X4_FUNCTION_ITEM) #undef SIMD_UINT32X4_FUNCTION_ITEM JS_FS_END @@ -438,9 +432,9 @@ GlobalObject::initSimdObject(JSContext* cx, Handle global) return true; } -template static bool -CreateSimdType(JSContext* cx, Handle global, HandlePropertyName stringRepr) +CreateSimdType(JSContext* cx, Handle global, HandlePropertyName stringRepr, + SimdType simdType, const JSFunctionSpec* methods) { RootedObject funcProto(cx, global->getOrCreateFunctionPrototype(cx)); if (!funcProto) @@ -452,7 +446,6 @@ CreateSimdType(JSContext* cx, Handle global, HandlePropertyName s if (!typeDescr) return false; - const SimdType simdType = T::type; typeDescr->initReservedSlot(JS_DESCR_SLOT_KIND, Int32Value(type::Simd)); typeDescr->initReservedSlot(JS_DESCR_SLOT_STRING_REPR, StringValue(stringRepr)); typeDescr->initReservedSlot(JS_DESCR_SLOT_ALIGNMENT, Int32Value(SimdTypeDescr::alignment(simdType))); @@ -488,7 +481,7 @@ CreateSimdType(JSContext* cx, Handle global, HandlePropertyName s MOZ_ASSERT(globalSimdObject); RootedValue typeValue(cx, ObjectValue(*typeDescr)); - if (!JS_DefineFunctions(cx, typeDescr, T::Methods) || + if (!JS_DefineFunctions(cx, typeDescr, methods) || !DefineProperty(cx, globalSimdObject, stringRepr, typeValue, nullptr, nullptr, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_RESOLVING)) { @@ -502,12 +495,13 @@ CreateSimdType(JSContext* cx, Handle global, HandlePropertyName s } bool -GlobalObject::initSimdType(JSContext* cx, Handle global, uint32_t simdTypeDescrType) +GlobalObject::initSimdType(JSContext* cx, Handle global, SimdType simdType) { #define CREATE_(Type) \ - case SimdType::Type: return CreateSimdType(cx, global, cx->names().Type); + case SimdType::Type: \ + return CreateSimdType(cx, global, cx->names().Type, simdType, Type##Defn::Methods); - switch (SimdType(simdTypeDescrType)) { + switch (simdType) { FOR_EACH_SIMD(CREATE_) case SimdType::Count: break; } @@ -516,6 +510,28 @@ GlobalObject::initSimdType(JSContext* cx, Handle global, uint32_t #undef CREATE_ } +SimdTypeDescr* +GlobalObject::getOrCreateSimdTypeDescr(JSContext* cx, Handle global, + SimdType simdType) +{ + MOZ_ASSERT(unsigned(simdType) < unsigned(SimdType::Count), "Invalid SIMD type"); + + RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx)); + if (!globalSimdObject) + return nullptr; + + uint32_t typeSlotIndex = uint32_t(simdType); + if (globalSimdObject->as().getReservedSlot(typeSlotIndex).isUndefined() && + !GlobalObject::initSimdType(cx, global, simdType)) + { + return nullptr; + } + + const Value& slot = globalSimdObject->as().getReservedSlot(typeSlotIndex); + MOZ_ASSERT(slot.isObject()); + return &slot.toObject().as(); +} + bool SimdObject::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* resolved) { @@ -526,7 +542,8 @@ SimdObject::resolve(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* Rooted global(cx, cx->global()); #define TRY_RESOLVE_(Type) \ if (str == cx->names().Type) { \ - *resolved = CreateSimdType(cx, global, cx->names().Type); \ + *resolved = CreateSimdType(cx, global, cx->names().Type, \ + SimdType::Type, Type##Defn::Methods); \ return *resolved; \ } FOR_EACH_SIMD(TRY_RESOLVE_) diff --git a/js/src/builtin/SIMD.h b/js/src/builtin/SIMD.h index 3d0e0d38f7..85ce1bf84d 100644 --- a/js/src/builtin/SIMD.h +++ b/js/src/builtin/SIMD.h @@ -799,13 +799,90 @@ enum class SimdType : uint8_t { Count }; +// The integer SIMD types have a lot of operations that do the exact same thing +// for signed and unsigned integer types. Sometimes it is simpler to treat +// signed and unsigned integer SIMD types as the same type, using a SimdSign to +// distinguish the few cases where there is a difference. +enum class SimdSign { + // Signedness is not applicable to this type. (i.e., Float or Bool). + NotApplicable, + // Treat as an unsigned integer with a range 0 .. 2^N-1. + Unsigned, + // Treat as a signed integer in two's complement encoding. + Signed, +}; + +// Get the signedness of a SIMD type. +inline SimdSign +GetSimdSign(SimdType t) +{ + switch(t) { + case SimdType::Int8x16: + case SimdType::Int16x8: + case SimdType::Int32x4: + return SimdSign::Signed; + + case SimdType::Uint8x16: + case SimdType::Uint16x8: + case SimdType::Uint32x4: + return SimdSign::Unsigned; + + default: + return SimdSign::NotApplicable; + } +} + +inline bool +IsSignedIntSimdType(SimdType type) +{ + return GetSimdSign(type) == SimdSign::Signed; +} + +// Get the boolean SIMD type with the same shape as t. +// +// This is the result type of a comparison operation, and it can also be used to +// identify the geometry of a SIMD type. +inline SimdType +GetBooleanSimdType(SimdType t) +{ + switch(t) { + case SimdType::Int8x16: + case SimdType::Uint8x16: + case SimdType::Bool8x16: + return SimdType::Bool8x16; + + case SimdType::Int16x8: + case SimdType::Uint16x8: + case SimdType::Bool16x8: + return SimdType::Bool16x8; + + case SimdType::Int32x4: + case SimdType::Uint32x4: + case SimdType::Float32x4: + case SimdType::Bool32x4: + return SimdType::Bool32x4; + + case SimdType::Float64x2: + case SimdType::Bool64x2: + return SimdType::Bool64x2; + + case SimdType::Count: + break; + } + MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("Bad SIMD type"); +} + // Complete set of SIMD operations. // // No SIMD types implement all of these operations. // // C++ defines keywords and/or/xor/not, so prepend Fn_ to all named functions to // avoid clashes. -enum class SimdOperation : uint8_t { +// +// Note: because of a gcc < v4.8's compiler bug, uint8_t can't be used as the +// storage class here. See bug 1243810. See also +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64037 . +enum class SimdOperation { // The constructor call. No Fn_ prefix here. Constructor, @@ -828,6 +905,8 @@ enum class SimdOperation : uint8_t { Fn_fromUint32x4Bits, Fn_fromFloat32x4Bits, Fn_fromFloat64x2Bits, + + Last = Fn_fromFloat64x2Bits }; class SimdObject : public JSObject @@ -1007,8 +1086,6 @@ struct Bool64x2 { } }; -bool IsSignedIntSimdType(SimdType type); - PropertyName* SimdTypeToName(JSContext* cx, SimdType type); template @@ -1020,6 +1097,16 @@ bool IsVectorObject(HandleValue v); template bool ToSimdConstant(JSContext* cx, HandleValue v, jit::SimdConstant* out); +JSObject* +InitSimdClass(JSContext* cx, HandleObject obj); + +namespace jit { + +extern const JSJitInfo JitInfo_SimdInt32x4_extractLane; +extern const JSJitInfo JitInfo_SimdFloat32x4_extractLane; + +} // namespace jit + #define DECLARE_SIMD_FLOAT32X4_FUNCTION(Name, Func, Operands) \ extern bool \ simd_float32x4_##Name(JSContext* cx, unsigned argc, Value* vp); @@ -1092,9 +1179,6 @@ simd_bool64x2_##Name(JSContext* cx, unsigned argc, Value* vp); BOOL64X2_FUNCTION_LIST(DECLARE_SIMD_BOOL64x2_FUNCTION) #undef DECLARE_SIMD_BOOL64x2_FUNCTION -JSObject* -InitSimdClass(JSContext* cx, HandleObject obj); - } /* namespace js */ #endif /* builtin_SIMD_h */ diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 03cad49d28..a513464fac 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -1743,7 +1743,7 @@ ReportPropertyError(JSContext* cx, bool TypedObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) { Rooted typedObj(cx, &obj->as()); @@ -1963,7 +1963,7 @@ TypedObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id, Handl bool TypedObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc) + MutableHandle desc) { Rooted typedObj(cx, &obj->as()); if (!typedObj->isAttached()) { @@ -2599,122 +2599,18 @@ js::GetTypedObjectModule(JSContext* cx, unsigned argc, Value* vp) } bool -js::GetFloat32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp) +js::GetSimdTypeDescr(JSContext* cx, unsigned argc, Value* vp) { CallArgs args = CallArgsFromVp(argc, vp); + MOZ_ASSERT(args.length() == 1); + MOZ_ASSERT(args[0].isInt32()); + // One of the JS_SIMDTYPEREPR_* constants / a SimdType enum value. + // getOrCreateSimdTypeDescr() will do the range check. + int32_t simdTypeRepr = args[0].toInt32(); Rooted global(cx, cx->global()); MOZ_ASSERT(global); - args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - return true; -} - -bool -js::GetFloat64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - Rooted global(cx, cx->global()); - MOZ_ASSERT(global); - args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - return true; -} - -bool -js::GetInt8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - Rooted global(cx, cx->global()); - MOZ_ASSERT(global); - args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - return true; -} - -bool -js::GetInt16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - Rooted global(cx, cx->global()); - MOZ_ASSERT(global); - args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - return true; -} - -bool -js::GetInt32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - Rooted global(cx, cx->global()); - MOZ_ASSERT(global); - args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - return true; -} - -bool -js::GetUint8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - Rooted global(cx, cx->global()); - MOZ_ASSERT(global); - args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - return true; -} - -bool -js::GetUint16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - Rooted global(cx, cx->global()); - MOZ_ASSERT(global); - args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - return true; -} - -bool -js::GetUint32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - Rooted global(cx, cx->global()); - MOZ_ASSERT(global); - args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - return true; -} - -bool -js::GetBool8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - Rooted global(cx, cx->global()); - MOZ_ASSERT(global); - args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - return true; -} - -bool -js::GetBool16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - Rooted global(cx, cx->global()); - MOZ_ASSERT(global); - args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - return true; -} - -bool -js::GetBool32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - Rooted global(cx, cx->global()); - MOZ_ASSERT(global); - args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - return true; -} - -bool -js::GetBool64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp) -{ - CallArgs args = CallArgsFromVp(argc, vp); - Rooted global(cx, cx->global()); - MOZ_ASSERT(global); - args.rval().setObject(*GlobalObject::getOrCreateSimdTypeDescr(cx, global)); + auto* obj = GlobalObject::getOrCreateSimdTypeDescr(cx, global, SimdType(simdTypeRepr)); + args.rval().setObject(*obj); return true; } diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index 8d4a33d932..66d2ddaa0a 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -506,7 +506,7 @@ class TypedObject : public JSObject MutableHandleShape propp); static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result); static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp); @@ -521,7 +521,7 @@ class TypedObject : public JSObject HandleValue receiver, ObjectOpResult& result); static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc); + MutableHandle desc); static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result); @@ -817,100 +817,14 @@ bool ClampToUint8(JSContext* cx, unsigned argc, Value* vp); bool GetTypedObjectModule(JSContext* cx, unsigned argc, Value* vp); /* - * Usage: GetFloat32x4TypeDescr() + * Usage: GetSimdTypeDescr(simdTypeRepr) * - * Returns the Float32x4 type object. SIMD pseudo-module must have - * been initialized for this to be safe. - */ -bool GetFloat32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp); - -/* - * Usage: GetFloat64x2TypeDescr() + * Returns one of the SIMD type objects, identified by `simdTypeRepr` which must + * be one of the JS_SIMDTYPEREPR_* constants. * - * Returns the Float64x2 type object. SIMD pseudo-module must have - * been initialized for this to be safe. + * The SIMD pseudo-module must have been initialized for this to be safe. */ -bool GetFloat64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp); - -/* - * Usage: GetBool8x16TypeDescr() - * - * Returns the Bool8x16 type object. SIMD pseudo-module must have - * been initialized for this to be safe. - */ -bool GetBool8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp); - -/* - * Usage: GetBool16x8TypeDescr() - * - * Returns the Bool16x8 type object. SIMD pseudo-module must have - * been initialized for this to be safe. - */ -bool GetBool16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp); - -/* - * Usage: GetBool32x4TypeDescr() - * - * Returns the Bool32x4 type object. SIMD pseudo-module must have - * been initialized for this to be safe. - */ -bool GetBool32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp); - -/* - * Usage: GetBool64x2TypeDescr() - * - * Returns the Bool64x2 type object. SIMD pseudo-module must have - * been initialized for this to be safe. - */ -bool GetBool64x2TypeDescr(JSContext* cx, unsigned argc, Value* vp); - -/* - * Usage: GetInt8x16TypeDescr() - * - * Returns the Int8x16 type object. SIMD pseudo-module must have - * been initialized for this to be safe. - */ -bool GetInt8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp); - -/* - * Usage: GetInt16x8TypeDescr() - * - * Returns the Int16x8 type object. SIMD pseudo-module must have - * been initialized for this to be safe. - */ -bool GetInt16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp); - -/* - * Usage: GetInt32x4TypeDescr() - * - * Returns the Int32x4 type object. SIMD pseudo-module must have - * been initialized for this to be safe. - */ -bool GetInt32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp); - -/* - * Usage: GetUint8x16TypeDescr() - * - * Returns the Uint8x16 type object. SIMD pseudo-module must have - * been initialized for this to be safe. - */ -bool GetUint8x16TypeDescr(JSContext* cx, unsigned argc, Value* vp); - -/* - * Usage: GetUint16x8TypeDescr() - * - * Returns the Uint16x8 type object. SIMD pseudo-module must have - * been initialized for this to be safe. - */ -bool GetUint16x8TypeDescr(JSContext* cx, unsigned argc, Value* vp); - -/* - * Usage: GetUint32x4TypeDescr() - * - * Returns the Uint32x4 type object. SIMD pseudo-module must have - * been initialized for this to be safe. - */ -bool GetUint32x4TypeDescr(JSContext* cx, unsigned argc, Value* vp); +bool GetSimdTypeDescr(JSContext* cx, unsigned argc, Value* vp); /* * Usage: Store_int8(targetDatum, targetOffset, value) diff --git a/js/src/builtin/TypedObject.js b/js/src/builtin/TypedObject.js index e26d8bb531..21b5bf8d71 100644 --- a/js/src/builtin/TypedObject.js +++ b/js/src/builtin/TypedObject.js @@ -144,18 +144,19 @@ function TypedObjectGetReference(descr, typedObj, offset) { function TypedObjectGetSimd(descr, typedObj, offset) { var type = DESCR_TYPE(descr); + var simdTypeDescr = GetSimdTypeDescr(type); switch (type) { case JS_SIMDTYPEREPR_FLOAT32X4: var x = Load_float32(typedObj, offset + 0); var y = Load_float32(typedObj, offset + 4); var z = Load_float32(typedObj, offset + 8); var w = Load_float32(typedObj, offset + 12); - return GetFloat32x4TypeDescr()(x, y, z, w); + return simdTypeDescr(x, y, z, w); case JS_SIMDTYPEREPR_FLOAT64X2: var x = Load_float64(typedObj, offset + 0); var y = Load_float64(typedObj, offset + 8); - return GetFloat64x2TypeDescr()(x, y); + return simdTypeDescr(x, y); case JS_SIMDTYPEREPR_INT8X16: var s0 = Load_int8(typedObj, offset + 0); @@ -174,8 +175,7 @@ function TypedObjectGetSimd(descr, typedObj, offset) { var s13 = Load_int8(typedObj, offset + 13); var s14 = Load_int8(typedObj, offset + 14); var s15 = Load_int8(typedObj, offset + 15); - return GetInt8x16TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7, - s8, s9, s10, s11, s12, s13, s14, s15); + return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15); case JS_SIMDTYPEREPR_INT16X8: var s0 = Load_int16(typedObj, offset + 0); @@ -186,14 +186,14 @@ function TypedObjectGetSimd(descr, typedObj, offset) { var s5 = Load_int16(typedObj, offset + 10); var s6 = Load_int16(typedObj, offset + 12); var s7 = Load_int16(typedObj, offset + 14); - return GetInt16x8TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7); + return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7); case JS_SIMDTYPEREPR_INT32X4: var x = Load_int32(typedObj, offset + 0); var y = Load_int32(typedObj, offset + 4); var z = Load_int32(typedObj, offset + 8); var w = Load_int32(typedObj, offset + 12); - return GetInt32x4TypeDescr()(x, y, z, w); + return simdTypeDescr(x, y, z, w); case JS_SIMDTYPEREPR_UINT8X16: var s0 = Load_uint8(typedObj, offset + 0); @@ -212,8 +212,7 @@ function TypedObjectGetSimd(descr, typedObj, offset) { var s13 = Load_uint8(typedObj, offset + 13); var s14 = Load_uint8(typedObj, offset + 14); var s15 = Load_uint8(typedObj, offset + 15); - return GetUint8x16TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7, - s8, s9, s10, s11, s12, s13, s14, s15); + return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15); case JS_SIMDTYPEREPR_UINT16X8: var s0 = Load_uint16(typedObj, offset + 0); @@ -224,14 +223,14 @@ function TypedObjectGetSimd(descr, typedObj, offset) { var s5 = Load_uint16(typedObj, offset + 10); var s6 = Load_uint16(typedObj, offset + 12); var s7 = Load_uint16(typedObj, offset + 14); - return GetUint16x8TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7); + return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7); case JS_SIMDTYPEREPR_UINT32X4: var x = Load_uint32(typedObj, offset + 0); var y = Load_uint32(typedObj, offset + 4); var z = Load_uint32(typedObj, offset + 8); var w = Load_uint32(typedObj, offset + 12); - return GetUint32x4TypeDescr()(x, y, z, w); + return simdTypeDescr(x, y, z, w); case JS_SIMDTYPEREPR_BOOL8X16: var s0 = Load_int8(typedObj, offset + 0); @@ -250,8 +249,7 @@ function TypedObjectGetSimd(descr, typedObj, offset) { var s13 = Load_int8(typedObj, offset + 13); var s14 = Load_int8(typedObj, offset + 14); var s15 = Load_int8(typedObj, offset + 15); - return GetBool8x16TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7, - s8, s9, s10, s11, s12, s13, s14, s15); + return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14, s15); case JS_SIMDTYPEREPR_BOOL16X8: var s0 = Load_int16(typedObj, offset + 0); @@ -262,19 +260,19 @@ function TypedObjectGetSimd(descr, typedObj, offset) { var s5 = Load_int16(typedObj, offset + 10); var s6 = Load_int16(typedObj, offset + 12); var s7 = Load_int16(typedObj, offset + 14); - return GetBool16x8TypeDescr()(s0, s1, s2, s3, s4, s5, s6, s7); + return simdTypeDescr(s0, s1, s2, s3, s4, s5, s6, s7); case JS_SIMDTYPEREPR_BOOL32X4: var x = Load_int32(typedObj, offset + 0); var y = Load_int32(typedObj, offset + 4); var z = Load_int32(typedObj, offset + 8); var w = Load_int32(typedObj, offset + 12); - return GetBool32x4TypeDescr()(x, y, z, w); + return simdTypeDescr(x, y, z, w); case JS_SIMDTYPEREPR_BOOL64X2: var x = Load_int32(typedObj, offset + 0); var y = Load_int32(typedObj, offset + 8); - return GetBool64x2TypeDescr()(x, y); + return simdTypeDescr(x, y); } diff --git a/js/src/ds/OrderedHashTable.h b/js/src/ds/OrderedHashTable.h index c992721297..a7c8d34523 100644 --- a/js/src/ds/OrderedHashTable.h +++ b/js/src/ds/OrderedHashTable.h @@ -702,16 +702,19 @@ class OrderedHashMap typedef typename Impl::Range Range; explicit OrderedHashMap(AllocPolicy ap = AllocPolicy()) : impl(ap) {} - bool init() { return impl.init(); } + MOZ_WARN_UNUSED_RESULT bool init() { return impl.init(); } uint32_t count() const { return impl.count(); } bool has(const Key& key) const { return impl.has(key); } Range all() { return impl.all(); } const Entry* get(const Key& key) const { return impl.get(key); } Entry* get(const Key& key) { return impl.get(key); } - template - bool put(const Key& key, V&& value) { return impl.put(Entry(key, Forward(value))); } bool remove(const Key& key, bool* foundp) { return impl.remove(key, foundp); } - bool clear() { return impl.clear(); } + MOZ_WARN_UNUSED_RESULT bool clear() { return impl.clear(); } + + template + MOZ_WARN_UNUSED_RESULT bool put(const Key& key, V&& value) { + return impl.put(Entry(key, Forward(value))); + } void rekeyOneEntry(const Key& current, const Key& newKey) { const Entry* e = get(current); @@ -739,13 +742,13 @@ class OrderedHashSet typedef typename Impl::Range Range; explicit OrderedHashSet(AllocPolicy ap = AllocPolicy()) : impl(ap) {} - bool init() { return impl.init(); } + MOZ_WARN_UNUSED_RESULT bool init() { return impl.init(); } uint32_t count() const { return impl.count(); } bool has(const T& value) const { return impl.has(value); } Range all() { return impl.all(); } - bool put(const T& value) { return impl.put(value); } + MOZ_WARN_UNUSED_RESULT bool put(const T& value) { return impl.put(value); } bool remove(const T& value, bool* foundp) { return impl.remove(value, foundp); } - bool clear() { return impl.clear(); } + MOZ_WARN_UNUSED_RESULT bool clear() { return impl.clear(); } void rekeyOneEntry(const T& current, const T& newKey) { return impl.rekeyOneEntry(current, newKey, newKey); diff --git a/js/src/ds/TraceableFifo.h b/js/src/ds/TraceableFifo.h index e6b20a593a..3176e3e3ea 100644 --- a/js/src/ds/TraceableFifo.h +++ b/js/src/ds/TraceableFifo.h @@ -31,9 +31,7 @@ namespace js { template -class TraceableFifo - : public js::Fifo, - public JS::Traceable +class TraceableFifo : public js::Fifo { using Base = js::Fifo; @@ -46,11 +44,11 @@ class TraceableFifo TraceableFifo(const TraceableFifo&) = delete; TraceableFifo& operator=(const TraceableFifo&) = delete; - static void trace(TraceableFifo* tf, JSTracer* trc) { - for (size_t i = 0; i < tf->front_.length(); ++i) - GCPolicy::trace(trc, &tf->front_[i], "fifo element"); - for (size_t i = 0; i < tf->rear_.length(); ++i) - GCPolicy::trace(trc, &tf->rear_[i], "fifo element"); + void trace(JSTracer* trc) { + for (size_t i = 0; i < this->front_.length(); ++i) + GCPolicy::trace(trc, &this->front_[i], "fifo element"); + for (size_t i = 0; i < this->rear_.length(); ++i) + GCPolicy::trace(trc, &this->rear_[i], "fifo element"); } }; diff --git a/js/src/gc/Marking.cpp b/js/src/gc/Marking.cpp index 794994d216..86bbdc0e05 100644 --- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -1702,6 +1702,7 @@ MarkStack::setBaseCapacity(JSGCMode mode) void MarkStack::setMaxCapacity(size_t maxCapacity) { + MOZ_ASSERT(maxCapacity != 0); MOZ_ASSERT(isEmpty()); maxCapacity_ = maxCapacity; if (baseCapacity_ > maxCapacity_) @@ -1719,6 +1720,7 @@ MarkStack::reset() return; } + MOZ_ASSERT(baseCapacity_ != 0); uintptr_t* newStack = (uintptr_t*)js_realloc(stack_, sizeof(uintptr_t) * baseCapacity_); if (!newStack) { // If the realloc fails, just keep using the existing stack; it's @@ -1738,6 +1740,7 @@ MarkStack::enlarge(unsigned count) size_t tosIndex = position(); + MOZ_ASSERT(newCapacity != 0); uintptr_t* newStack = (uintptr_t*)js_realloc(stack_, sizeof(uintptr_t) * newCapacity); if (!newStack) return false; @@ -1811,8 +1814,11 @@ GCMarker::stop() /* Free non-ballast stack memory. */ stack.reset(); - for (GCZonesIter zone(runtime()); !zone.done(); zone.next()) - zone->gcWeakKeys.clear(); + AutoEnterOOMUnsafeRegion oomUnsafe; + for (GCZonesIter zone(runtime()); !zone.done(); zone.next()) { + if (!zone->gcWeakKeys.clear()) + oomUnsafe.crash("clearing weak keys in GCMarker::stop()"); + } } void @@ -1867,8 +1873,11 @@ GCMarker::leaveWeakMarkingMode() // Table is expensive to maintain when not in weak marking mode, so we'll // rebuild it upon entry rather than allow it to contain stale data. - for (GCZonesIter zone(runtime()); !zone.done(); zone.next()) - zone->gcWeakKeys.clear(); + AutoEnterOOMUnsafeRegion oomUnsafe; + for (GCZonesIter zone(runtime()); !zone.done(); zone.next()) { + if (!zone->gcWeakKeys.clear()) + oomUnsafe.crash("clearing weak keys in GCMarker::leaveWeakMarkingMode()"); + } } void diff --git a/js/src/gc/RootMarking.cpp b/js/src/gc/RootMarking.cpp index be0a5ce810..2bacce9ffa 100644 --- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -42,6 +42,18 @@ typedef RootedValueMap::Enum RootEnum; template using TraceFunction = void (*)(JSTracer* trc, T* ref, const char* name); +// For more detail see JS::Rooted::ptr and js::DispatchWrapper. +// +// The JS::RootKind::Traceable list contains a bunch of totally disparate +// types, but the instantiations of DispatchWrapper below need /something/ in +// the type field. We use the following type as a compatible stand-in. No +// actual methods from ConcreteTraceable type are actually used at runtime -- +// the real trace function has been stored inline in the DispatchWrapper. +struct ConcreteTraceable { + ConcreteTraceable() { MOZ_CRASH("instantiation of ConcreteTraceable"); } + void trace(JSTracer*) {} +}; + template TraceFn = TraceNullableRoot> static inline void MarkExactStackRootList(JSTracer* trc, JS::Rooted* rooter, const char* name) @@ -62,7 +74,8 @@ JS_FOR_EACH_TRACEKIND(MARK_ROOTS) #undef MARK_ROOTS MarkExactStackRootList(trc, stackRoots_[JS::RootKind::Id], "exact-id"); MarkExactStackRootList(trc, stackRoots_[JS::RootKind::Value], "exact-value"); - MarkExactStackRootList::TraceWrapped>( + MarkExactStackRootList::TraceWrapped>( trc, stackRoots_[JS::RootKind::Traceable], "Traceable"); } @@ -92,7 +105,8 @@ JS_FOR_EACH_TRACEKIND(MARK_ROOTS) #undef MARK_ROOTS MarkPersistentRootedList(trc, heapRoots_[JS::RootKind::Id], "persistent-id"); MarkPersistentRootedList(trc, heapRoots_[JS::RootKind::Value], "persistent-value"); - MarkPersistentRootedList::TraceWrapped>(trc, + MarkPersistentRootedList::TraceWrapped>(trc, heapRoots_[JS::RootKind::Traceable], "persistent-traceable"); } @@ -108,8 +122,9 @@ template static void FinishPersistentRootedChain(mozilla::LinkedList>& listArg) { - while (!listArg.isEmpty()) - listArg.getFirst()->reset(); + auto& list = reinterpret_cast>&>(listArg); + while (!list.isEmpty()) + list.getFirst()->reset(); } void @@ -121,7 +136,7 @@ JS_FOR_EACH_TRACEKIND(FINISH_ROOT_LIST) #undef FINISH_ROOT_LIST FinishPersistentRootedChain(heapRoots_[JS::RootKind::Id]); FinishPersistentRootedChain(heapRoots_[JS::RootKind::Value]); - FinishPersistentRootedChain(heapRoots_[JS::RootKind::Traceable]); + FinishPersistentRootedChain(heapRoots_[JS::RootKind::Traceable]); } inline void @@ -232,7 +247,7 @@ StackShape::trace(JSTracer* trc) } void -JSPropertyDescriptor::trace(JSTracer* trc) +PropertyDescriptor::trace(JSTracer* trc) { if (obj) TraceRoot(trc, &obj, "Descriptor::obj"); diff --git a/js/src/jit-test/tests/SIMD/bug1241872.js b/js/src/jit-test/tests/SIMD/bug1241872.js new file mode 100644 index 0000000000..3184770163 --- /dev/null +++ b/js/src/jit-test/tests/SIMD/bug1241872.js @@ -0,0 +1,10 @@ +if (typeof SIMD !== 'object') + exit(0); + +function test() { + return SIMD.Float32x4().toSource(); +} + +var r = ''; +for (var i = 0; i < 10000; i++) + r = test(); diff --git a/js/src/jit-test/tests/gc/bug-1236473.js b/js/src/jit-test/tests/gc/bug-1236473.js new file mode 100644 index 0000000000..e48edd3934 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1236473.js @@ -0,0 +1,7 @@ +if (!('oomTest' in this)) + quit(); + +oomTest(() => { + offThreadCompileScript(`try {} catch (NaN) {}`); + runOffThreadScript(); +}); diff --git a/js/src/jit-test/tests/gc/bug-1240416.js b/js/src/jit-test/tests/gc/bug-1240416.js new file mode 100644 index 0000000000..e3a1bab829 --- /dev/null +++ b/js/src/jit-test/tests/gc/bug-1240416.js @@ -0,0 +1,2 @@ +// |jit-test| error: Error +gcparam('markStackLimit', 0); diff --git a/js/src/jit-test/tests/wasm/basic.js b/js/src/jit-test/tests/wasm/basic.js index dce4ca2ef0..0aa8d8e23e 100644 --- a/js/src/jit-test/tests/wasm/basic.js +++ b/js/src/jit-test/tests/wasm/basic.js @@ -118,6 +118,10 @@ var code = '(module (import "a" "") (import "b" "c") (import "c" ""))'; assertErrorMessage(() => wasmEvalText(code, {a:()=>{}, b:{c:()=>{}}, c:{}}), TypeError, notFunction); wasmEvalText(code, {a:()=>{}, b:{c:()=>{}}, c:()=>{}}); +wasmEvalText('(module (import "a" "" (result i32)))', {a: ()=> {}}); +wasmEvalText('(module (import "a" "" (result f32)))', {a: ()=> {}}); +wasmEvalText('(module (import "a" "" (result f64)))', {a: ()=> {}}); + // ---------------------------------------------------------------------------- // memory @@ -254,6 +258,15 @@ assertErrorMessage(() => wasmEvalText('(module (import "a" "") (func (call_impor wasmEvalText('(module (import "a" "") (func (call_import 0)))', {a:()=>{}}); wasmEvalText('(module (import "a" "" (param i32)) (func (call_import 0 (i32.const 0))))', {a:()=>{}}); +function checkF32CallImport(v) { + assertEq(wasmEvalText('(module (import "a" "" (result f32)) (func (result f32) (call_import 0)) (export "" 0))', {a:()=>{ return v; }})(), Math.fround(v)); +} +checkF32CallImport(13.37); +checkF32CallImport(NaN); +checkF32CallImport(-Infinity); +checkF32CallImport(-0); +checkF32CallImport(Math.pow(2, 32) - 1); + var f = wasmEvalText('(module (import "inc" "") (func (call_import 0)) (export "" 0))', {inc:()=>counter++}); var g = wasmEvalText('(module (import "f" "") (func (block (call_import 0) (call_import 0))) (export "" 0))', {f}); var counter = 0; diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 473484572c..0cd284b6f6 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -18,6 +18,7 @@ #include "gc/Policy.h" #include "jit/BaselineDebugModeOSR.h" #include "jit/BaselineJIT.h" +#include "jit/InlinableNatives.h" #include "jit/JitSpewer.h" #include "jit/Linker.h" #include "jit/Lowering.h" @@ -5626,10 +5627,68 @@ TryAttachFunCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, return true; } +// Check if target is a native SIMD operation which returns a SIMD type. +// If so, set res to a template object matching the SIMD type produced and return true. static bool -GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args, +GetTemplateObjectForSimd(JSContext* cx, JSFunction* target, MutableHandleObject res) +{ + const JSJitInfo* jitInfo = target->jitInfo(); + if (!jitInfo || jitInfo->type() != JSJitInfo::InlinableNative) + return false; + + // Check if this is a native inlinable SIMD operation. + SimdType ctrlType; + switch (jitInfo->inlinableNative) { + case InlinableNative::SimdInt32x4: ctrlType = SimdType::Int32x4; break; + case InlinableNative::SimdUint32x4: ctrlType = SimdType::Uint32x4; break; + case InlinableNative::SimdFloat32x4: ctrlType = SimdType::Float32x4; break; + case InlinableNative::SimdBool32x4: ctrlType = SimdType::Bool32x4; break; + // This is not an inlinable SIMD operation. + default: return false; + } + + // The controlling type is not necessarily the return type. + // Check the actual operation. + SimdOperation simdOp = SimdOperation(jitInfo->nativeOp); + SimdType retType; + + switch(simdOp) { + case SimdOperation::Fn_allTrue: + case SimdOperation::Fn_anyTrue: + case SimdOperation::Fn_extractLane: + // These operations return a scalar. No template object needed. + return false; + + case SimdOperation::Fn_lessThan: + case SimdOperation::Fn_lessThanOrEqual: + case SimdOperation::Fn_equal: + case SimdOperation::Fn_notEqual: + case SimdOperation::Fn_greaterThan: + case SimdOperation::Fn_greaterThanOrEqual: + // These operations return a boolean vector with the same shape as the + // controlling type. + retType = GetBooleanSimdType(ctrlType); + break; + + default: + // All other operations return the controlling type. + retType = ctrlType; + break; + } + + // Create a template object based on retType. + RootedGlobalObject global(cx, cx->global()); + Rooted descr(cx, GlobalObject::getOrCreateSimdTypeDescr(cx, global, retType)); + res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr)); + return true; +} + +static bool +GetTemplateObjectForNative(JSContext* cx, JSFunction* target, const CallArgs& args, MutableHandleObject res, bool* skipAttach) { + Native native = target->native(); + // Check for natives to which template objects can be attached. This is // done to provide templates to Ion for inlining these natives later on. @@ -5703,51 +5762,8 @@ GetTemplateObjectForNative(JSContext* cx, Native native, const CallArgs& args, return !!res; } - if (JitSupportsSimd()) { - RootedGlobalObject global(cx, cx->global()); -#define ADD_INT32X4_SIMD_OP_NAME_(OP) || native == js::simd_int32x4_##OP -#define ADD_BOOL32X4_SIMD_OP_NAME_(OP) || native == js::simd_bool32x4_##OP -#define ADD_FLOAT32X4_SIMD_OP_NAME_(OP) || native == js::simd_float32x4_##OP - // Operations producing an int32x4. - if (false - ION_COMMONX4_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_) - FOREACH_BITWISE_SIMD_UNOP(ADD_INT32X4_SIMD_OP_NAME_) - FOREACH_BITWISE_SIMD_BINOP(ADD_INT32X4_SIMD_OP_NAME_) - FOREACH_SHIFT_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_) - ADD_INT32X4_SIMD_OP_NAME_(fromFloat32x4) - ADD_INT32X4_SIMD_OP_NAME_(fromFloat32x4Bits)) - { - Rooted descr(cx, GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr)); - return !!res; - } - // Operations producing a bool32x4. - if (false - FOREACH_BITWISE_SIMD_UNOP(ADD_BOOL32X4_SIMD_OP_NAME_) - FOREACH_BITWISE_SIMD_BINOP(ADD_BOOL32X4_SIMD_OP_NAME_) - FOREACH_COMP_SIMD_OP(ADD_INT32X4_SIMD_OP_NAME_) - FOREACH_COMP_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_)) - { - Rooted descr(cx, GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr)); - return !!res; - } - // Operations producing a float32x4. - if (false - FOREACH_FLOAT_SIMD_UNOP(ADD_FLOAT32X4_SIMD_OP_NAME_) - FOREACH_FLOAT_SIMD_BINOP(ADD_FLOAT32X4_SIMD_OP_NAME_) - ADD_FLOAT32X4_SIMD_OP_NAME_(fromInt32x4) - ADD_FLOAT32X4_SIMD_OP_NAME_(fromInt32x4Bits) - ION_COMMONX4_SIMD_OP(ADD_FLOAT32X4_SIMD_OP_NAME_)) - { - Rooted descr(cx, GlobalObject::getOrCreateSimdTypeDescr(cx, global)); - res.set(cx->compartment()->jitCompartment()->getSimdTemplateObjectFor(cx, descr)); - return !!res; - } -#undef ADD_BOOL32X4_SIMD_OP_NAME_ -#undef ADD_INT32X4_SIMD_OP_NAME_ -#undef ADD_FLOAT32X4_SIMD_OP_NAME_ - } + if (JitSupportsSimd() && GetTemplateObjectForSimd(cx, target, res)) + return !!res; return true; } @@ -6011,7 +6027,7 @@ TryAttachCallStub(JSContext* cx, ICCall_Fallback* stub, HandleScript script, jsb if (MOZ_LIKELY(!isSpread && !isSuper)) { bool skipAttach = false; CallArgs args = CallArgsFromVp(argc, vp); - if (!GetTemplateObjectForNative(cx, fun->native(), args, &templateObject, &skipAttach)) + if (!GetTemplateObjectForNative(cx, fun, args, &templateObject, &skipAttach)) return false; if (skipAttach) { *handled = true; diff --git a/js/src/jit/InlinableNatives.h b/js/src/jit/InlinableNatives.h index 76b8e51d4d..2d7c46df2b 100644 --- a/js/src/jit/InlinableNatives.h +++ b/js/src/jit/InlinableNatives.h @@ -80,6 +80,7 @@ _(ObjectCreate) \ \ _(SimdInt32x4) \ + _(SimdUint32x4) \ _(SimdFloat32x4) \ _(SimdBool32x4) \ \ diff --git a/js/src/jit/IonBuilder.h b/js/src/jit/IonBuilder.h index 3a788da93d..cba3f237da 100644 --- a/js/src/jit/IonBuilder.h +++ b/js/src/jit/IonBuilder.h @@ -863,23 +863,27 @@ class IonBuilder InlineTypedObject* templateObj); MDefinition* convertToBooleanSimdLane(MDefinition* scalar); - InliningStatus inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType); + InliningStatus inlineSimd(CallInfo& callInfo, JSFunction* target, + MIRType simdType, SimdSign sign = SimdSign::NotApplicable); template InliningStatus inlineSimdBinary(CallInfo& callInfo, JSNative native, typename T::Operation op, MIRType mirType); InliningStatus inlineSimdComp(CallInfo& callInfo, JSNative native, - MSimdBinaryComp::Operation op, MIRType compType); + MSimdBinaryComp::Operation op, + MIRType compType, SimdSign sign); InliningStatus inlineSimdUnary(CallInfo& callInfo, JSNative native, MSimdUnaryArith::Operation op, MIRType mirType); - InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native, MIRType vecType); + InliningStatus inlineSimdExtractLane(CallInfo& callInfo, JSNative native, + MIRType vecType, SimdSign sign); InliningStatus inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, MIRType mirType); InliningStatus inlineSimdSplat(CallInfo& callInfo, JSNative native, MIRType mirType); InliningStatus inlineSimdShuffle(CallInfo& callInfo, JSNative native, MIRType type, unsigned numVectors, unsigned numLanes); InliningStatus inlineSimdCheck(CallInfo& callInfo, JSNative native, MIRType type); InliningStatus inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast, - MIRType from, MIRType to); + MIRType from, MIRType to, + SimdSign sign = SimdSign::NotApplicable); InliningStatus inlineSimdSelect(CallInfo& callInfo, JSNative native, MIRType type); bool prepareForSimdLoadStore(CallInfo& callInfo, Scalar::Type simdType, MInstruction** elements, diff --git a/js/src/jit/IonTypes.h b/js/src/jit/IonTypes.h index 848fe67755..7ca007dd66 100644 --- a/js/src/jit/IonTypes.h +++ b/js/src/jit/IonTypes.h @@ -420,6 +420,7 @@ enum MIRType MIRType_ObjectGroup, // An ObjectGroup pointer. MIRType_Last = MIRType_ObjectGroup, MIRType_Float32x4 = MIRType_Float32 | (2 << VECTOR_SCALE_SHIFT), + // Representing both SIMD.Int32x4 and SIMD.Uint32x4. MIRType_Int32x4 = MIRType_Int32 | (2 << VECTOR_SCALE_SHIFT), MIRType_Bool32x4 = MIRType_Boolean | (2 << VECTOR_SCALE_SHIFT), MIRType_Doublex2 = MIRType_Double | (1 << VECTOR_SCALE_SHIFT) diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index ec61d21f3d..2de305d556 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -203,7 +203,9 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target) // SIMD natives. case InlinableNative::SimdInt32x4: - return inlineSimd(callInfo, target, MIRType_Int32x4); + return inlineSimd(callInfo, target, MIRType_Int32x4, SimdSign::Signed); + case InlinableNative::SimdUint32x4: + return inlineSimd(callInfo, target, MIRType_Int32x4, SimdSign::Unsigned); case InlinableNative::SimdFloat32x4: return inlineSimd(callInfo, target, MIRType_Float32x4); case InlinableNative::SimdBool32x4: @@ -307,21 +309,36 @@ IonBuilder::inlineNativeGetter(CallInfo& callInfo, JSFunction* target) if (!optimizationInfo().inlineNative()) return InliningStatus_NotInlined; - TemporaryTypeSet* thisTypes = callInfo.thisArg()->resultTypeSet(); + MDefinition* thisArg = callInfo.thisArg(); + TemporaryTypeSet* thisTypes = thisArg->resultTypeSet(); MOZ_ASSERT(callInfo.argc() == 0); - // Try to optimize typed array lengths. - if (thisTypes) { - Scalar::Type type; + if (!thisTypes) + return InliningStatus_NotInlined; - type = thisTypes->getTypedArrayType(constraints()); - if (type != Scalar::MaxTypedArrayViewType && - TypedArrayObject::isOriginalLengthGetter(native)) - { - MInstruction* length = addTypedArrayLength(callInfo.thisArg()); - current->push(length); - return InliningStatus_Inlined; - } + // Try to optimize typed array lengths. + if (TypedArrayObject::isOriginalLengthGetter(native)) { + Scalar::Type type = thisTypes->getTypedArrayType(constraints()); + if (type == Scalar::MaxTypedArrayViewType) + return InliningStatus_NotInlined; + + MInstruction* length = addTypedArrayLength(thisArg); + current->push(length); + return InliningStatus_Inlined; + } + + // Try to optimize RegExp getters. + unsigned slot = 0; + if (RegExpObject::isOriginalFlagGetter(native, &slot)) { + const Class* clasp = thisTypes->getKnownClass(constraints()); + if (clasp != &RegExpObject::class_) + return InliningStatus_NotInlined; + + MLoadFixedSlot* load = MLoadFixedSlot::New(alloc(), thisArg, slot); + current->add(load); + current->push(load); + load->setResultType(MIRType_Boolean); + return InliningStatus_Inlined; } return InliningStatus_NotInlined; @@ -3047,14 +3064,24 @@ IonBuilder::inlineConstructTypedObject(CallInfo& callInfo, TypeDescr* descr) } // Main entry point for SIMD inlining. +// When the controlling simdType is an integer type, sign indicates whether the lanes should +// be treated as signed or unsigned integers. IonBuilder::InliningStatus -IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType) +IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType, SimdSign sign) { + if (!JitSupportsSimd()) { + trackOptimizationOutcome(TrackedOutcome::NoSimdJitSupport); + return InliningStatus_NotInlined; + } + JSNative native = target->native(); const JSJitInfo* jitInfo = target->jitInfo(); MOZ_ASSERT(jitInfo && jitInfo->type() == JSJitInfo::InlinableNative); SimdOperation simdOp = SimdOperation(jitInfo->nativeOp); + MOZ_ASSERT(IsSimdType(simdType)); + MOZ_ASSERT((sign != SimdSign::NotApplicable) == IsIntegerSimdType(simdType), + "Signedness must be specified for ints, and only for ints"); switch(simdOp) { case SimdOperation::Constructor: @@ -3067,7 +3094,7 @@ IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType) case SimdOperation::Fn_splat: return inlineSimdSplat(callInfo, native, simdType); case SimdOperation::Fn_extractLane: - return inlineSimdExtractLane(callInfo, native, simdType); + return inlineSimdExtractLane(callInfo, native, simdType, sign); case SimdOperation::Fn_replaceLane: return inlineSimdReplaceLane(callInfo, native, simdType); case SimdOperation::Fn_select: @@ -3134,9 +3161,8 @@ IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType) case SimdOperation::Fn_shiftLeftByScalar: return inlineSimdBinary(callInfo, native, MSimdShift::lsh, simdType); case SimdOperation::Fn_shiftRightByScalar: - // TODO: select opcode from simdType signedness. - MOZ_ASSERT(simdType == MIRType_Int32x4); - return inlineSimdBinary(callInfo, native, MSimdShift::rsh, simdType); + return inlineSimdBinary(callInfo, native, MSimdShift::rshForSign(sign), + simdType); case SimdOperation::Fn_shiftRightArithmeticByScalar: return inlineSimdBinary(callInfo, native, MSimdShift::rsh, simdType); case SimdOperation::Fn_shiftRightLogicalByScalar: @@ -3150,25 +3176,33 @@ IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType) // Comparisons. case SimdOperation::Fn_lessThan: - return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThan, simdType); + return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThan, + simdType, sign); case SimdOperation::Fn_lessThanOrEqual: - return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThanOrEqual, simdType); + return inlineSimdComp(callInfo, native, MSimdBinaryComp::lessThanOrEqual, + simdType, sign); case SimdOperation::Fn_equal: - return inlineSimdComp(callInfo, native, MSimdBinaryComp::equal, simdType); + return inlineSimdComp(callInfo, native, MSimdBinaryComp::equal, + simdType, sign); case SimdOperation::Fn_notEqual: - return inlineSimdComp(callInfo, native, MSimdBinaryComp::notEqual, simdType); + return inlineSimdComp(callInfo, native, MSimdBinaryComp::notEqual, + simdType, sign); case SimdOperation::Fn_greaterThan: - return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThan, simdType); + return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThan, + simdType, sign); case SimdOperation::Fn_greaterThanOrEqual: - return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThanOrEqual, simdType); + return inlineSimdComp(callInfo, native, MSimdBinaryComp::greaterThanOrEqual, + simdType, sign); // Int <-> Float conversions. case SimdOperation::Fn_fromInt32x4: - return inlineSimdConvert(callInfo, native, false, MIRType_Int32x4, simdType); + return inlineSimdConvert(callInfo, native, false, MIRType_Int32x4, + simdType, SimdSign::Signed); case SimdOperation::Fn_fromUint32x4: - return InliningStatus_NotInlined; + return inlineSimdConvert(callInfo, native, false, MIRType_Int32x4, + simdType, SimdSign::Unsigned); case SimdOperation::Fn_fromFloat32x4: - return inlineSimdConvert(callInfo, native, false, MIRType_Float32x4, simdType); + return inlineSimdConvert(callInfo, native, false, MIRType_Float32x4, simdType, sign); // Load/store. case SimdOperation::Fn_load: @@ -3193,10 +3227,10 @@ IonBuilder::inlineSimd(CallInfo& callInfo, JSFunction* target, MIRType simdType) case SimdOperation::Fn_fromInt16x8Bits: return InliningStatus_NotInlined; case SimdOperation::Fn_fromInt32x4Bits: + case SimdOperation::Fn_fromUint32x4Bits: return inlineSimdConvert(callInfo, native, true, MIRType_Int32x4, simdType); case SimdOperation::Fn_fromUint8x16Bits: case SimdOperation::Fn_fromUint16x8Bits: - case SimdOperation::Fn_fromUint32x4Bits: return InliningStatus_NotInlined; case SimdOperation::Fn_fromFloat32x4Bits: return inlineSimdConvert(callInfo, native, true, MIRType_Float32x4, simdType); @@ -3252,6 +3286,11 @@ bool SimdTypeToMIRType(SimdType type, MIRType* mirType) IonBuilder::InliningStatus IonBuilder::inlineConstructSimdObject(CallInfo& callInfo, SimdTypeDescr* descr) { + if (!JitSupportsSimd()) { + trackOptimizationOutcome(TrackedOutcome::NoSimdJitSupport); + return InliningStatus_NotInlined; + } + // Generic constructor of SIMD valuesX4. MIRType simdType; if (!SimdTypeToMIRType(descr->type(), &simdType)) @@ -3371,12 +3410,16 @@ IonBuilder::inlineSimdBinary(CallInfo& callInfo, JSNative native, typename T::Op IonBuilder::InliningStatus IonBuilder::inlineSimdComp(CallInfo& callInfo, JSNative native, MSimdBinaryComp::Operation op, - MIRType mirType) + MIRType mirType, SimdSign sign) { InlineTypedObject* templateObj = nullptr; if (!canInlineSimd(callInfo, native, 2, &templateObj)) return InliningStatus_NotInlined; + // TODO JSO: Implement unsigned integer comparisons. + if (sign == SimdSign::Unsigned) + return InliningStatus_NotInlined; + // If the type of any of the arguments is neither a SIMD type, an Object // type, or a Value, then the applyTypes phase will add a fallible box & // unbox sequence. This does not matter much as all binary SIMD @@ -3420,10 +3463,18 @@ IonBuilder::inlineSimdSplat(CallInfo& callInfo, JSNative native, MIRType mirType } IonBuilder::InliningStatus -IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, MIRType vecType) +IonBuilder::inlineSimdExtractLane(CallInfo& callInfo, JSNative native, + MIRType vecType, SimdSign sign) { - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 2, &templateObj)) + // extractLane() returns a scalar, so don't use canInlineSimd() which looks + // for a template object. + if (callInfo.argc() != 2 || callInfo.constructing()) { + trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); + return InliningStatus_NotInlined; + } + + // TODO JSO: Implement unsigned integer lane values. + if (sign == SimdSign::Unsigned) return InliningStatus_NotInlined; MDefinition* arg = callInfo.getArg(1); @@ -3468,14 +3519,21 @@ IonBuilder::inlineSimdReplaceLane(CallInfo& callInfo, JSNative native, MIRType m return boxSimd(callInfo, ins, templateObj); } +// Inline a SIMD conversion or bitcast. When isCast==false, one of the types +// must be floating point and the other integer. In this case, sign indicates if +// the integer lanes should be treated as signed or unsigned integers. IonBuilder::InliningStatus IonBuilder::inlineSimdConvert(CallInfo& callInfo, JSNative native, bool isCast, - MIRType fromType, MIRType toType) + MIRType fromType, MIRType toType, SimdSign sign) { InlineTypedObject* templateObj = nullptr; if (!canInlineSimd(callInfo, native, 1, &templateObj)) return InliningStatus_NotInlined; + // TODO JSO: Implement unsigned integer conversions. + if (sign == SimdSign::Unsigned) + return InliningStatus_NotInlined; + // See comment in inlineSimdBinary MInstruction* ins; if (isCast) @@ -3523,9 +3581,12 @@ IonBuilder::inlineSimdShuffle(CallInfo& callInfo, JSNative native, MIRType mirTy IonBuilder::InliningStatus IonBuilder::inlineSimdAnyAllTrue(CallInfo& callInfo, bool IsAllTrue, JSNative native) { - InlineTypedObject* templateObj = nullptr; - if (!canInlineSimd(callInfo, native, 1, &templateObj)) + // anyTrue() / allTrue() return a scalar, so don't use canInlineSimd() which looks + // for a template object. + if (callInfo.argc() != 1 || callInfo.constructing()) { + trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm); return InliningStatus_NotInlined; + } MUnaryInstruction* ins; if (IsAllTrue) diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index a4db5b11eb..fa7408638a 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -2352,6 +2352,11 @@ class MSimdShift return new(alloc) MSimdShift(left, right, op); } + // Get the relevant right shift operation given the signedness of a type. + static Operation rshForSign(SimdSign sign) { + return sign == SimdSign::Unsigned ? ursh : rsh; + } + AliasSet getAliasSet() const override { return AliasSet::None(); } diff --git a/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp index 2c82725fc9..be1495bc96 100644 --- a/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp +++ b/js/src/jsapi-tests/testDefineGetterSetterNonEnumerable.cpp @@ -45,7 +45,7 @@ BEGIN_TEST(testDefineGetterSetterNonEnumerable) JS_DATA_TO_FUNC_PTR(JSNative, (JSObject*) funGetObj), JS_DATA_TO_FUNC_PTR(JSNative, (JSObject*) funSetObj))); - JS::Rooted desc(cx); + JS::Rooted desc(cx); CHECK(JS_GetOwnPropertyDescriptor(cx, vObject, PROPERTY_NAME, &desc)); CHECK(desc.object()); CHECK(desc.hasGetterObject()); diff --git a/js/src/jsapi-tests/testDefinePropertyIgnoredAttributes.cpp b/js/src/jsapi-tests/testDefinePropertyIgnoredAttributes.cpp index fc9df64999..83de2918eb 100644 --- a/js/src/jsapi-tests/testDefinePropertyIgnoredAttributes.cpp +++ b/js/src/jsapi-tests/testDefinePropertyIgnoredAttributes.cpp @@ -20,7 +20,7 @@ enum PropertyDescriptorKind { }; static bool -CheckDescriptor(JS::Handle desc, PropertyDescriptorKind kind, +CheckDescriptor(JS::Handle desc, PropertyDescriptorKind kind, bool enumerable, bool writable, bool configurable) { if (!desc.object()) @@ -39,7 +39,7 @@ CheckDescriptor(JS::Handle desc, PropertyDescriptorKind ki BEGIN_TEST(testDefinePropertyIgnoredAttributes) { JS::RootedObject obj(cx, JS_NewPlainObject(cx)); - JS::Rooted desc(cx); + JS::Rooted desc(cx); JS::RootedValue defineValue(cx); // Try a getter. Allow it to fill in the defaults. Because we're passing a diff --git a/js/src/jsapi-tests/testGCExactRooting.cpp b/js/src/jsapi-tests/testGCExactRooting.cpp index c256913477..01bb1fdf08 100644 --- a/js/src/jsapi-tests/testGCExactRooting.cpp +++ b/js/src/jsapi-tests/testGCExactRooting.cpp @@ -44,17 +44,17 @@ BEGIN_TEST(testGCSuppressions) } END_TEST(testGCSuppressions) -struct MyContainer : public JS::Traceable +struct MyContainer { RelocatablePtrObject obj; RelocatablePtrString str; MyContainer() : obj(nullptr), str(nullptr) {} - static void trace(MyContainer* self, JSTracer* trc) { - if (self->obj) - js::TraceEdge(trc, &self->obj, "test container"); - if (self->str) - js::TraceEdge(trc, &self->str, "test container"); + void trace(JSTracer* trc) { + if (obj) + js::TraceEdge(trc, &obj, "test container"); + if (str) + js::TraceEdge(trc, &str, "test container"); } }; diff --git a/js/src/jsapi-tests/testGCWeakRef.cpp b/js/src/jsapi-tests/testGCWeakRef.cpp index fc7bc76c8a..a072081c01 100644 --- a/js/src/jsapi-tests/testGCWeakRef.cpp +++ b/js/src/jsapi-tests/testGCWeakRef.cpp @@ -10,13 +10,13 @@ #include "jsapi-tests/tests.h" -struct MyHeap : JS::Traceable +struct MyHeap { explicit MyHeap(JSObject* obj) : weak(obj) {} js::WeakRef weak; - static void trace(MyHeap* self, JSTracer* trc) { - js::TraceWeakEdge(trc, &self->weak, "weak"); + void trace(JSTracer* trc) { + js::TraceWeakEdge(trc, &weak, "weak"); } }; diff --git a/js/src/jsapi-tests/testGetPropertyDescriptor.cpp b/js/src/jsapi-tests/testGetPropertyDescriptor.cpp index 3cc4def91a..ace3e6333a 100644 --- a/js/src/jsapi-tests/testGetPropertyDescriptor.cpp +++ b/js/src/jsapi-tests/testGetPropertyDescriptor.cpp @@ -11,7 +11,7 @@ BEGIN_TEST(test_GetPropertyDescriptor) CHECK(v.isObject()); JS::RootedObject obj(cx, &v.toObject()); - JS::Rooted desc(cx); + JS::Rooted desc(cx); CHECK(JS_GetPropertyDescriptor(cx, obj, "somename", &desc)); CHECK_EQUAL(desc.object(), obj); diff --git a/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp b/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp index c4df2ff598..3814ae6a85 100644 --- a/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp +++ b/js/src/jsapi-tests/testSetPropertyIgnoringNamedGetter.cpp @@ -16,21 +16,21 @@ class CustomProxyHandler : public DirectProxyHandler { CustomProxyHandler() : DirectProxyHandler(nullptr) {} bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override + MutableHandle desc) const override { return impl(cx, proxy, id, desc, false); } bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override + MutableHandle desc) const override { return impl(cx, proxy, id, desc, true); } - bool set(JSContext *cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver, - ObjectOpResult &result) const override + bool set(JSContext* cx, HandleObject proxy, HandleId id, HandleValue v, HandleValue receiver, + ObjectOpResult& result) const override { - Rooted desc(cx); + Rooted desc(cx); if (!DirectProxyHandler::getPropertyDescriptor(cx, proxy, id, &desc)) return false; return SetPropertyIgnoringNamedGetter(cx, proxy, id, v, receiver, desc, result); @@ -38,7 +38,7 @@ class CustomProxyHandler : public DirectProxyHandler { private: bool impl(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc, bool ownOnly) const + MutableHandle desc, bool ownOnly) const { if (JSID_IS_STRING(id)) { bool match; diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 3295ef48a1..ad88ed49ae 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -2033,7 +2033,7 @@ JS_SetImmutablePrototype(JSContext *cx, JS::HandleObject obj, bool *succeeded) JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptorById(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc) + MutableHandle desc) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); @@ -2043,7 +2043,7 @@ JS_GetOwnPropertyDescriptorById(JSContext* cx, HandleObject obj, HandleId id, JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name, - MutableHandle desc) + MutableHandle desc) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) @@ -2054,7 +2054,7 @@ JS_GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name, JS_PUBLIC_API(bool) JS_GetOwnUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* name, - MutableHandle desc) + MutableHandle desc) { JSAtom* atom = AtomizeChars(cx, name, js_strlen(name)); if (!atom) @@ -2065,14 +2065,14 @@ JS_GetOwnUCPropertyDescriptor(JSContext* cx, HandleObject obj, const char16_t* n JS_PUBLIC_API(bool) JS_GetPropertyDescriptorById(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc) + MutableHandle desc) { return GetPropertyDescriptor(cx, obj, id, desc); } JS_PUBLIC_API(bool) JS_GetPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name, - MutableHandle desc) + MutableHandle desc) { JSAtom* atom = Atomize(cx, name, strlen(name)); if (!atom) @@ -2083,7 +2083,7 @@ JS_GetPropertyDescriptor(JSContext* cx, HandleObject obj, const char* name, static bool DefinePropertyByDescriptor(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, ObjectOpResult& result) + Handle desc, ObjectOpResult& result) { AssertHeapIsIdle(cx); CHECK_REQUEST(cx); @@ -2094,14 +2094,14 @@ DefinePropertyByDescriptor(JSContext* cx, HandleObject obj, HandleId id, JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, ObjectOpResult& result) + Handle desc, ObjectOpResult& result) { return DefinePropertyByDescriptor(cx, obj, id, desc, result); } JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, HandleObject obj, HandleId id, - Handle desc) + Handle desc) { ObjectOpResult result; return DefinePropertyByDescriptor(cx, obj, id, desc, result) && @@ -2354,7 +2354,7 @@ JS_DefineProperty(JSContext* cx, HandleObject obj, const char* name, double valu JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - Handle desc, + Handle desc, ObjectOpResult& result) { JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); @@ -2366,7 +2366,7 @@ JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_ JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, HandleObject obj, const char16_t* name, size_t namelen, - Handle desc) + Handle desc) { JSAtom* atom = AtomizeChars(cx, name, AUTO_NAMELEN(name, namelen)); if (!atom) @@ -3217,7 +3217,7 @@ JS_PUBLIC_API(bool) JS::ObjectToCompletePropertyDescriptor(JSContext* cx, HandleObject obj, HandleValue descObj, - MutableHandle desc) + MutableHandle desc) { if (!ToPropertyDescriptor(cx, descObj, true, desc)) return false; diff --git a/js/src/jsapi.h b/js/src/jsapi.h index b95fe78ba9..7ab0958cc6 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -2516,27 +2516,27 @@ JS_FreezeObject(JSContext* cx, JS::Handle obj); /*** Property descriptors ************************************************************************/ -struct JS_PUBLIC_API(JSPropertyDescriptor) : public JS::Traceable { +namespace JS { + +struct JS_PUBLIC_API(PropertyDescriptor) { JSObject* obj; unsigned attrs; JSGetterOp getter; JSSetterOp setter; JS::Value value; - JSPropertyDescriptor() + PropertyDescriptor() : obj(nullptr), attrs(0), getter(nullptr), setter(nullptr), value(JS::UndefinedValue()) {} - static void trace(JSPropertyDescriptor* self, JSTracer* trc) { self->trace(trc); } + static void trace(PropertyDescriptor* self, JSTracer* trc) { self->trace(trc); } void trace(JSTracer* trc); }; -namespace JS { - template class PropertyDescriptorOperations { - const JSPropertyDescriptor& desc() const { return static_cast(this)->get(); } + const PropertyDescriptor& desc() const { return static_cast(this)->get(); } bool has(unsigned bit) const { MOZ_ASSERT(bit != 0); @@ -2668,7 +2668,7 @@ class PropertyDescriptorOperations template class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations { - JSPropertyDescriptor& desc() { return static_cast(this)->get(); } + PropertyDescriptor& desc() { return static_cast(this)->get(); } public: void clear() { @@ -2691,7 +2691,7 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations< setSetter(setterOp); } - void assign(JSPropertyDescriptor& other) { + void assign(PropertyDescriptor& other) { object().set(other.obj); setAttributes(other.attrs); setGetter(other.getter); @@ -2779,18 +2779,18 @@ class MutablePropertyDescriptorOperations : public PropertyDescriptorOperations< namespace js { template <> -class RootedBase - : public JS::MutablePropertyDescriptorOperations> +class RootedBase + : public JS::MutablePropertyDescriptorOperations> {}; template <> -class HandleBase - : public JS::PropertyDescriptorOperations> +class HandleBase + : public JS::PropertyDescriptorOperations> {}; template <> -class MutableHandleBase - : public JS::MutablePropertyDescriptorOperations> +class MutableHandleBase + : public JS::MutablePropertyDescriptorOperations> {}; } /* namespace js */ @@ -2801,7 +2801,7 @@ extern JS_PUBLIC_API(bool) ObjectToCompletePropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleValue descriptor, - JS::MutableHandle desc); + JS::MutableHandle desc); } // namespace JS @@ -2888,15 +2888,15 @@ JS_SetImmutablePrototype(JSContext* cx, JS::HandleObject obj, bool* succeeded); */ extern JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); extern JS_PUBLIC_API(bool) JS_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, - JS::MutableHandle desc); + JS::MutableHandle desc); extern JS_PUBLIC_API(bool) JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_t* name, - JS::MutableHandle desc); + JS::MutableHandle desc); /** * Like JS_GetOwnPropertyDescriptorById, but also searches the prototype chain @@ -2906,11 +2906,11 @@ JS_GetOwnUCPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char16_ */ extern JS_PUBLIC_API(bool) JS_GetPropertyDescriptorById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); extern JS_PUBLIC_API(bool) JS_GetPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, - JS::MutableHandle desc); + JS::MutableHandle desc); /** * Define a property on obj. @@ -2925,7 +2925,7 @@ JS_GetPropertyDescriptor(JSContext* cx, JS::HandleObject obj, const char* name, */ extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); /** @@ -2934,7 +2934,7 @@ JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, */ extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc); + JS::Handle desc); extern JS_PUBLIC_API(bool) JS_DefinePropertyById(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue value, @@ -2986,12 +2986,12 @@ JS_DefineProperty(JSContext* cx, JS::HandleObject obj, const char* name, double extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, - JS::Handle desc); + JS::Handle desc); extern JS_PUBLIC_API(bool) JS_DefineUCProperty(JSContext* cx, JS::HandleObject obj, const char16_t* name, size_t namelen, diff --git a/js/src/jscntxtinlines.h b/js/src/jscntxtinlines.h index da458330be..2254a4ffc9 100644 --- a/js/src/jscntxtinlines.h +++ b/js/src/jscntxtinlines.h @@ -133,7 +133,7 @@ class CompartmentChecker void check(AbstractFramePtr frame); void check(SavedStacks* stacks); - void check(Handle desc) { + void check(Handle desc) { check(desc.object()); if (desc.hasGetterObject()) check(desc.getterObject()); diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index ce44a40083..b97a0b9ebe 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -242,7 +242,7 @@ JS_CopyPropertyFrom(JSContext* cx, JS::HandleId id, JS::HandleObject target, PropertyCopyBehavior copyBehavior = CopyNonConfigurableAsIs); extern JS_FRIEND_API(bool) -JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle desc); +JS_WrapPropertyDescriptor(JSContext* cx, JS::MutableHandle desc); struct JSFunctionSpecWithHelp { const char* name; @@ -334,7 +334,7 @@ proxy_LookupProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::M JS::MutableHandle propp); extern JS_FRIEND_API(bool) proxy_DefineProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result); extern JS_FRIEND_API(bool) proxy_HasProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, bool* foundp); @@ -346,7 +346,7 @@ proxy_SetProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::Hand JS::HandleValue receiver, JS::ObjectOpResult& result); extern JS_FRIEND_API(bool) proxy_GetOwnPropertyDescriptor(JSContext* cx, JS::HandleObject obj, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); extern JS_FRIEND_API(bool) proxy_DeleteProperty(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::ObjectOpResult& result); @@ -2680,7 +2680,7 @@ ForwardToNative(JSContext* cx, JSNative native, const JS::CallArgs& args); JS_FRIEND_API(bool) SetPropertyIgnoringNamedGetter(JSContext* cx, JS::HandleObject obj, JS::HandleId id, JS::HandleValue v, JS::HandleValue receiver, - JS::Handle ownDesc, + JS::Handle ownDesc, JS::ObjectOpResult& result); JS_FRIEND_API(void) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 7f454b6695..db3e06d2ba 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -1415,6 +1415,8 @@ GCRuntime::setParameter(JSGCParamKey key, uint32_t value, AutoLockGC& lock) defaultTimeBudget_ = value ? value : SliceBudget::UnlimitedTimeBudget; break; case JSGC_MARK_STACK_LIMIT: + if (value == 0) + return false; setMarkStackLimit(value, lock); break; case JSGC_DECOMMIT_THRESHOLD: @@ -3157,9 +3159,9 @@ SliceBudget::describe(char* buffer, size_t maxlen) const if (isUnlimited()) return JS_snprintf(buffer, maxlen, "unlimited"); else if (isWorkBudget()) - return JS_snprintf(buffer, maxlen, "work(%lld)", workBudget.budget); + return JS_snprintf(buffer, maxlen, "work(%" PRId64 ")", workBudget.budget); else - return JS_snprintf(buffer, maxlen, "%lldms", timeBudget.budget); + return JS_snprintf(buffer, maxlen, "%" PRId64 "ms", timeBudget.budget); } bool @@ -4362,13 +4364,14 @@ js::gc::MarkingValidator::nonIncrementalMark() if (!WeakMapBase::saveZoneMarkedWeakMaps(zone, markedWeakMaps)) return; + AutoEnterOOMUnsafeRegion oomUnsafe; for (gc::WeakKeyTable::Range r = zone->gcWeakKeys.all(); !r.empty(); r.popFront()) { - AutoEnterOOMUnsafeRegion oomUnsafe; if (!savedWeakKeys.put(Move(r.front().key), Move(r.front().value))) oomUnsafe.crash("saving weak keys table for validator"); } - zone->gcWeakKeys.clear(); + if (!zone->gcWeakKeys.clear()) + oomUnsafe.crash("clearing weak keys table for validator"); } /* @@ -4439,7 +4442,9 @@ js::gc::MarkingValidator::nonIncrementalMark() for (GCZonesIter zone(runtime); !zone.done(); zone.next()) { WeakMapBase::unmarkZone(zone); - zone->gcWeakKeys.clear(); + AutoEnterOOMUnsafeRegion oomUnsafe; + if (!zone->gcWeakKeys.clear()) + oomUnsafe.crash("clearing weak keys table for validator"); } WeakMapBase::restoreMarkedWeakMaps(markedWeakMaps); @@ -5128,7 +5133,9 @@ GCRuntime::beginSweepingZoneGroup() zone->gcWeakRefs.clear(); /* No need to look up any more weakmap keys from this zone group. */ - zone->gcWeakKeys.clear(); + AutoEnterOOMUnsafeRegion oomUnsafe; + if (!zone->gcWeakKeys.clear()) + oomUnsafe.crash("clearing weak keys in beginSweepingZoneGroup()"); } FreeOp fop(rt); @@ -6242,22 +6249,6 @@ GCRuntime::budgetIncrementalGC(SliceBudget& budget) namespace { -class AutoDisableStoreBuffer -{ - StoreBuffer& sb; - bool prior; - - public: - explicit AutoDisableStoreBuffer(GCRuntime* gc) : sb(gc->storeBuffer) { - prior = sb.isEnabled(); - sb.disable(); - } - ~AutoDisableStoreBuffer() { - if (prior) - sb.enable(); - } -}; - class AutoScheduleZonesForGC { JSRuntime* rt_; @@ -6305,12 +6296,6 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason:: evictNursery(reason); - /* - * Marking can trigger many incidental post barriers, some of them for - * objects which are not going to be live after the GC. - */ - AutoDisableStoreBuffer adsb(this); - AutoTraceSession session(rt, JS::HeapState::MajorCollecting); majorGCTriggerReason = JS::gcreason::NO_REASON; @@ -6578,7 +6563,6 @@ GCRuntime::abortGC() SliceBudget::unlimited(), JS::gcreason::ABORT_GC); evictNursery(JS::gcreason::ABORT_GC); - AutoDisableStoreBuffer adsb(this); AutoTraceSession session(rt, JS::HeapState::MajorCollecting); number++; @@ -6880,6 +6864,10 @@ gc::MergeCompartments(JSCompartment* source, JSCompartment* target) script->compartment_ = target; script->setTypesGeneration(target->zone()->types.generation); + // If the script failed to compile, no need to fix up. + if (!script->code()) + continue; + // See warning in handleParseWorkload. If we start optimizing global // lexicals, we would need to merge the contents of the static global // lexical scope. diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 27b178f33c..76d51bae68 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -1063,7 +1063,7 @@ JS_CopyPropertyFrom(JSContext* cx, HandleId id, HandleObject target, { // |obj| and |cx| are generally not same-compartment with |target| here. assertSameCompartment(cx, obj, id); - Rooted desc(cx); + Rooted desc(cx); if (!GetOwnPropertyDescriptor(cx, obj, id, &desc)) return false; diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index e54a77edcc..5410252a10 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -99,7 +99,6 @@ struct JSFunctionSpec; struct JSLocaleCallbacks; struct JSObjectMap; struct JSPrincipals; -struct JS_PUBLIC_API(JSPropertyDescriptor); struct JSPropertyName; struct JSPropertySpec; struct JSRuntime; @@ -137,6 +136,8 @@ class StoreBuffer; namespace JS { +struct PropertyDescriptor; + typedef void (*OffThreadCompileCallback)(void* token, void* callbackData); enum class HeapState { @@ -241,6 +242,13 @@ class JS_PUBLIC_API(AutoGCRooter) void operator=(AutoGCRooter& ida) = delete; }; +// Our instantiations of Rooted and PersistentRooted require an +// instantiation of MapTypeToRootKind. +template <> +struct MapTypeToRootKind { + static const RootKind kind = RootKind::Traceable; +}; + } /* namespace JS */ namespace js { diff --git a/js/src/jsscript.h b/js/src/jsscript.h index 7ccde2f36d..f31fbaa410 100644 --- a/js/src/jsscript.h +++ b/js/src/jsscript.h @@ -165,7 +165,7 @@ class YieldOffsetArray { } }; -class Binding : public JS::Traceable +class Binding { // One JSScript stores one Binding per formal/variable so we use a // packed-word representation. @@ -214,7 +214,7 @@ JS_STATIC_ASSERT(sizeof(Binding) == sizeof(uintptr_t)); * both function and top-level scripts (the latter is needed to track names in * strict mode eval code, to give such code its own lexical environment). */ -class Bindings : public JS::Traceable +class Bindings { friend class BindingIter; friend class AliasedFormalIter; diff --git a/js/src/jswrapper.h b/js/src/jswrapper.h index f622e97ca0..858b322b86 100644 --- a/js/src/jswrapper.h +++ b/js/src/jswrapper.h @@ -110,9 +110,9 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, AutoIdVector& props) const override; @@ -139,7 +139,7 @@ class JS_FRIEND_API(CrossCompartmentWrapper) : public Wrapper /* SpiderMonkey extensions. */ virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper, AutoIdVector& props) const override; @@ -165,9 +165,9 @@ class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrap /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, AutoIdVector& props) const override; @@ -195,7 +195,7 @@ class JS_FRIEND_API(OpaqueCrossCompartmentWrapper) : public CrossCompartmentWrap /* SpiderMonkey extensions. */ virtual bool getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool hasOwn(JSContext* cx, HandleObject wrapper, HandleId id, bool* bp) const override; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject wrapper, @@ -231,7 +231,7 @@ class JS_FRIEND_API(SecurityWrapper) : public Base bool* bp) const override; virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool isExtensible(JSContext* cx, HandleObject wrapper, bool* extensible) const override; virtual bool preventExtensions(JSContext* cx, HandleObject wrapper, diff --git a/js/src/proxy/DeadObjectProxy.h b/js/src/proxy/DeadObjectProxy.h index eb836a36f9..70c847f9b7 100644 --- a/js/src/proxy/DeadObjectProxy.h +++ b/js/src/proxy/DeadObjectProxy.h @@ -20,9 +20,9 @@ class DeadObjectProxy : public BaseProxyHandler /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, HandleObject wrapper, AutoIdVector& props) const override; diff --git a/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp b/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp index afff989330..6a70cd5294 100644 --- a/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp +++ b/js/src/proxy/OpaqueCrossCompartmentWrapper.cpp @@ -22,7 +22,7 @@ OpaqueCrossCompartmentWrapper::getOwnPropertyDescriptor(JSContext* cx, bool OpaqueCrossCompartmentWrapper::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const { return result.succeed(); @@ -131,7 +131,7 @@ bool OpaqueCrossCompartmentWrapper::getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle desc) const + MutableHandle desc) const { return BaseProxyHandler::getPropertyDescriptor(cx, wrapper, id, desc); } diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index 7e1cc65f23..8f2856db55 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -553,7 +553,7 @@ js::proxy_LookupProperty(JSContext* cx, HandleObject obj, HandleId id, bool js::proxy_DefineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) { return Proxy::defineProperty(cx, obj, id, desc, result); @@ -581,7 +581,7 @@ js::proxy_SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue bool js::proxy_GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc) + MutableHandle desc) { return Proxy::getOwnPropertyDescriptor(cx, obj, id, desc); } diff --git a/js/src/proxy/Proxy.h b/js/src/proxy/Proxy.h index c1cf40fc7a..d2b955bbe5 100644 --- a/js/src/proxy/Proxy.h +++ b/js/src/proxy/Proxy.h @@ -27,9 +27,9 @@ class Proxy public: /* Standard internal methods. */ static bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc); + MutableHandle desc); static bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, ObjectOpResult& result); + Handle desc, ObjectOpResult& result); static bool ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props); static bool delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result); static bool enumerate(JSContext* cx, HandleObject proxy, MutableHandleObject objp); @@ -49,7 +49,7 @@ class Proxy /* SpiderMonkey extensions. */ static bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc); + MutableHandle desc); static bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp); static bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props); diff --git a/js/src/proxy/ScriptedDirectProxyHandler.h b/js/src/proxy/ScriptedDirectProxyHandler.h index a137f59d14..6c3744298d 100644 --- a/js/src/proxy/ScriptedDirectProxyHandler.h +++ b/js/src/proxy/ScriptedDirectProxyHandler.h @@ -20,9 +20,9 @@ class ScriptedDirectProxyHandler : public BaseProxyHandler { /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const override; diff --git a/js/src/proxy/ScriptedIndirectProxyHandler.h b/js/src/proxy/ScriptedIndirectProxyHandler.h index 7579a36a0e..f7a3436e3a 100644 --- a/js/src/proxy/ScriptedIndirectProxyHandler.h +++ b/js/src/proxy/ScriptedIndirectProxyHandler.h @@ -21,9 +21,9 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, HandleObject proxy, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const override; @@ -42,7 +42,7 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler /* SpiderMonkey extensions. */ virtual bool getPropertyDescriptor(JSContext* cx, HandleObject proxy, HandleId id, - MutableHandle desc) const override; + MutableHandle desc) const override; virtual bool hasOwn(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const override; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const override; diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index d5a80ff73a..61c950ec01 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -2450,7 +2450,7 @@ Debugger::markCrossCompartmentEdges(JSTracer* trc) // `Debugger::logTenurePromotion`, we can't hold onto CCWs inside the log, // and instead have unwrapped cross-compartment edges. We need to be sure to // mark those here. - TenurePromotionsLog::trace(&tenurePromotionsLog, trc); + tenurePromotionsLog.trace(trc); } /* @@ -2626,8 +2626,8 @@ Debugger::trace(JSTracer* trc) TraceEdge(trc, &frameobj, "live Debugger.Frame"); } - AllocationsLog::trace(&allocationsLog, trc); - TenurePromotionsLog::trace(&tenurePromotionsLog, trc); + allocationsLog.trace(trc); + tenurePromotionsLog.trace(trc); /* Trace the weak map from JSScript instances to Debugger.Script objects. */ scripts.trace(trc); diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index b35685a444..1acd3e1ec6 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -282,7 +282,7 @@ class Debugger : private mozilla::LinkedListElement void logTenurePromotion(JSRuntime* rt, JSObject& obj, double when); static SavedFrame* getObjectAllocationSite(JSObject& obj); - struct TenurePromotionsLogEntry : public JS::Traceable + struct TenurePromotionsLogEntry { TenurePromotionsLogEntry(JSRuntime* rt, JSObject& obj, double when); @@ -291,14 +291,13 @@ class Debugger : private mozilla::LinkedListElement RelocatablePtrObject frame; size_t size; - static void trace(TenurePromotionsLogEntry* e, JSTracer* trc) { e->trace(trc); } void trace(JSTracer* trc) { if (frame) TraceEdge(trc, &frame, "Debugger::TenurePromotionsLogEntry::frame"); } }; - struct AllocationsLogEntry : public JS::Traceable + struct AllocationsLogEntry { AllocationsLogEntry(HandleObject frame, double when, const char* className, HandleAtom ctorName, size_t size, bool inNursery) @@ -319,7 +318,6 @@ class Debugger : private mozilla::LinkedListElement size_t size; bool inNursery; - static void trace(AllocationsLogEntry* e, JSTracer* trc) { e->trace(trc); } void trace(JSTracer* trc) { if (frame) TraceEdge(trc, &frame, "Debugger::AllocationsLogEntry::frame"); diff --git a/js/src/vm/GlobalObject.h b/js/src/vm/GlobalObject.h index f1f4fa1d53..4a5c0397b7 100644 --- a/js/src/vm/GlobalObject.h +++ b/js/src/vm/GlobalObject.h @@ -31,6 +31,7 @@ class StaticBlockObject; class ClonedBlockObject; class SimdTypeDescr; +enum class SimdType : uint8_t; /* * Global object slots are reserved as follows: @@ -442,22 +443,11 @@ class GlobalObject : public NativeObject return getOrCreateObject(cx, APPLICATION_SLOTS + JSProto_SIMD, initSimdObject); } - template - static SimdTypeDescr* - getOrCreateSimdTypeDescr(JSContext* cx, Handle global) { - RootedObject globalSimdObject(cx, global->getOrCreateSimdGlobalObject(cx)); - if (!globalSimdObject) - return nullptr; - uint32_t typeSlotIndex = uint32_t(T::type); - if (globalSimdObject->as().getReservedSlot(typeSlotIndex).isUndefined() && - !GlobalObject::initSimdType(cx, global, typeSlotIndex)) - { - return nullptr; - } - const Value& slot = globalSimdObject->as().getReservedSlot(typeSlotIndex); - MOZ_ASSERT(slot.isObject()); - return &slot.toObject().as(); - } + // Get the type descriptor for one of the SIMD types. + // simdType is one of the JS_SIMDTYPEREPR_* constants. + // Implemented in builtin/SIMD.cpp. + static SimdTypeDescr* getOrCreateSimdTypeDescr(JSContext* cx, Handle global, + SimdType simdType); TypedObjectModuleObject& getTypedObjectModule() const; @@ -725,9 +715,9 @@ class GlobalObject : public NativeObject // Implemented in builtin/TypedObject.cpp static bool initTypedObjectModule(JSContext* cx, Handle global); - // Implemented in builtim/SIMD.cpp + // Implemented in builtin/SIMD.cpp static bool initSimdObject(JSContext* cx, Handle global); - static bool initSimdType(JSContext* cx, Handle global, uint32_t simdTypeDescrType); + static bool initSimdType(JSContext* cx, Handle global, SimdType simdType); static bool initStandardClasses(JSContext* cx, Handle global); static bool initSelfHostingBuiltins(JSContext* cx, Handle global, diff --git a/js/src/vm/JSONParser.h b/js/src/vm/JSONParser.h index 687972392b..0b48e06091 100644 --- a/js/src/vm/JSONParser.h +++ b/js/src/vm/JSONParser.h @@ -190,8 +190,7 @@ class MOZ_STACK_CLASS JSONParserBase }; template -class MOZ_STACK_CLASS JSONParser : public JSONParserBase, - public JS::Traceable +class MOZ_STACK_CLASS JSONParser : public JSONParserBase { private: typedef mozilla::RangedPtr CharPtr; diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index f4ebd1ef7f..b3e0ac2023 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -134,7 +134,7 @@ js::NativeObject::checkShapeConsistency() for (int n = throttle; --n >= 0 && shape->parent; shape = shape->parent) { MOZ_ASSERT_IF(lastProperty() != shape, !shape->hasTable()); - ShapeTable::Entry& entry = table.search(shape->propid(), false); + ShapeTable::Entry& entry = table.search(shape->propid()); MOZ_ASSERT(entry.shape() == shape); } @@ -155,7 +155,7 @@ js::NativeObject::checkShapeConsistency() ShapeTable& table = shape->table(); MOZ_ASSERT(shape->parent); for (Shape::Range r(shape); !r.empty(); r.popFront()) { - ShapeTable::Entry& entry = table.search(r.front().propid(), false); + ShapeTable::Entry& entry = table.search(r.front().propid()); MOZ_ASSERT(entry.shape() == &r.front()); } } @@ -356,7 +356,7 @@ void NativeObject::setLastPropertyMakeNative(ExclusiveContext* cx, Shape* shape) { MOZ_ASSERT(getClass()->isNative()); - MOZ_ASSERT(shape->isNative()); + MOZ_ASSERT(shape->getObjectClass()->isNative()); MOZ_ASSERT(!shape->inDictionary()); // This method is used to convert unboxed objects into native objects. In diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 3bd64e0713..d184bedf9a 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -1378,8 +1378,7 @@ ObjectGroup::newPlainObject(ExclusiveContext* cx, IdValuePair* properties, size_ // ObjectGroupCompartment AllocationSiteTable ///////////////////////////////////////////////////////////////////// -struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher, - public JS::Traceable { +struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher { ReadBarrieredScript script; uint32_t offset : 24; @@ -1421,9 +1420,9 @@ struct ObjectGroupCompartment::AllocationSiteKey : public DefaultHasher::match(a.proto, b.proto); } - static void trace(AllocationSiteKey* key, JSTracer* trc) { - TraceRoot(trc, &key->script, "AllocationSiteKey script"); - TraceNullableRoot(trc, &key->proto, "AllocationSiteKey proto"); + void trace(JSTracer* trc) { + TraceRoot(trc, &script, "AllocationSiteKey script"); + TraceNullableRoot(trc, &proto, "AllocationSiteKey proto"); } bool needsSweep() { diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 6e195d124e..f18685b916 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -123,6 +123,33 @@ RegExpObject::getShared(JSContext* cx, RegExpGuard* g) return createShared(cx, g); } +/* static */ bool +RegExpObject::isOriginalFlagGetter(JSNative native, unsigned* slot) +{ + if (native == regexp_global) { + *slot = GLOBAL_FLAG_SLOT; + return true; + } + if (native == regexp_ignoreCase) { + *slot = IGNORE_CASE_FLAG_SLOT; + return true; + } + if (native == regexp_multiline) { + *slot = MULTILINE_FLAG_SLOT; + return true; + } + if (native == regexp_sticky) { + *slot = STICKY_FLAG_SLOT; + return true; + } + if (native == regexp_unicode) { + *slot = UNICODE_FLAG_SLOT; + return true; + } + + return false; +} + /* static */ void RegExpObject::trace(JSTracer* trc, JSObject* obj) { diff --git a/js/src/vm/RegExpObject.h b/js/src/vm/RegExpObject.h index e0eb3b13b1..5aceb3eeaf 100644 --- a/js/src/vm/RegExpObject.h +++ b/js/src/vm/RegExpObject.h @@ -456,6 +456,8 @@ class RegExpObject : public NativeObject bool sticky() const { return getFixedSlot(STICKY_FLAG_SLOT).toBoolean(); } bool unicode() const { return getFixedSlot(UNICODE_FLAG_SLOT).toBoolean(); } + static bool isOriginalFlagGetter(JSNative native, unsigned* slot); + bool getShared(JSContext* cx, RegExpGuard* g); void setShared(RegExpShared& shared) { diff --git a/js/src/vm/SavedStacks.cpp b/js/src/vm/SavedStacks.cpp index 9e659f1328..636a8c0046 100644 --- a/js/src/vm/SavedStacks.cpp +++ b/js/src/vm/SavedStacks.cpp @@ -62,13 +62,13 @@ LiveSavedFrameCache::getFramePtr(FrameIter& iter) return Nothing(); } -/* static */ void -LiveSavedFrameCache::trace(LiveSavedFrameCache* cache, JSTracer* trc) +void +LiveSavedFrameCache::trace(JSTracer* trc) { - if (!cache->initialized()) + if (!initialized()) return; - for (auto* entry = cache->frames->begin(); entry < cache->frames->end(); entry++) { + for (auto* entry = frames->begin(); entry < frames->end(); entry++) { TraceEdge(trc, &entry->savedFrame, "LiveSavedFrameCache::frames SavedFrame"); diff --git a/js/src/vm/SavedStacks.h b/js/src/vm/SavedStacks.h index 3e26b3fc58..2abd9a383f 100644 --- a/js/src/vm/SavedStacks.h +++ b/js/src/vm/SavedStacks.h @@ -225,7 +225,7 @@ class SavedStacks { }; public: - struct LocationValue : public JS::Traceable { + struct LocationValue { LocationValue() : source(nullptr), line(0), column(0) { } LocationValue(JSAtom* source, size_t line, uint32_t column) : source(source), diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index a2697d9b78..ecfd450bc3 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -496,7 +496,7 @@ ModuleEnvironmentObject::setProperty(JSContext* cx, HandleObject obj, HandleId i /* static */ bool ModuleEnvironmentObject::getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc) + MutableHandle desc) { // We never call this hook on scope objects. MOZ_CRASH(); @@ -747,7 +747,7 @@ with_SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, static bool with_GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc) + MutableHandle desc) { MOZ_ASSERT(!JSID_IS_ATOM(id, cx->names().dotThis)); RootedObject actual(cx, &obj->as().object()); @@ -1046,7 +1046,7 @@ StaticBlockObject::addVar(ExclusiveContext* cx, Handle block /* Inline NativeObject::addProperty in order to trap the redefinition case. */ ShapeTable::Entry* entry; - if (Shape::search(cx, block->lastProperty(), id, &entry, true)) { + if (Shape::search(cx, block->lastProperty(), id, &entry)) { *redeclared = true; return nullptr; } @@ -1340,7 +1340,7 @@ lexicalError_SetProperty(JSContext* cx, HandleObject obj, HandleId id, HandleVal static bool lexicalError_GetOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc) + MutableHandle desc) { ReportRuntimeLexicalErrorId(cx, obj->as().errorNumber(), id); return false; diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index 26005a3762..6d3fea258d 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -416,7 +416,7 @@ class ModuleEnvironmentObject : public LexicalScopeBase static bool setProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v, HandleValue receiver, JS::ObjectOpResult& result); static bool getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc); + MutableHandle desc); static bool deleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result); static bool enumerate(JSContext* cx, HandleObject obj, AutoIdVector& properties, diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index ae3579c53e..7886022b55 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -1657,11 +1657,11 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("std_SIMD_Int8x16_extractLane", simd_int8x16_extractLane, 2,0), JS_FN("std_SIMD_Int16x8_extractLane", simd_int16x8_extractLane, 2,0), - JS_INLINABLE_FN("std_SIMD_Int32x4_extractLane", simd_int32x4_extractLane, 2,0, SimdInt32x4), + JS_INLINABLE_FN("std_SIMD_Int32x4_extractLane", simd_int32x4_extractLane, 2,0, SimdInt32x4_extractLane), JS_FN("std_SIMD_Uint8x16_extractLane", simd_uint8x16_extractLane, 2,0), JS_FN("std_SIMD_Uint16x8_extractLane", simd_uint16x8_extractLane, 2,0), JS_FN("std_SIMD_Uint32x4_extractLane", simd_uint32x4_extractLane, 2,0), - JS_INLINABLE_FN("std_SIMD_Float32x4_extractLane", simd_float32x4_extractLane,2,0, SimdFloat32x4), + JS_INLINABLE_FN("std_SIMD_Float32x4_extractLane", simd_float32x4_extractLane,2,0, SimdFloat32x4_extractLane), JS_FN("std_SIMD_Float64x2_extractLane", simd_float64x2_extractLane, 2,0), JS_FN("std_SIMD_Bool8x16_extractLane", simd_bool8x16_extractLane, 2,0), JS_FN("std_SIMD_Bool16x8_extractLane", simd_bool16x8_extractLane, 2,0), @@ -1814,18 +1814,7 @@ static const JSFunctionSpec intrinsic_functions[] = { JS_FN("TypedObjectTypeDescr", js::TypedObjectTypeDescr, 1, 0), JS_FN("ClampToUint8", js::ClampToUint8, 1, 0), JS_FN("GetTypedObjectModule", js::GetTypedObjectModule, 0, 0), - JS_FN("GetFloat32x4TypeDescr", js::GetFloat32x4TypeDescr, 0, 0), - JS_FN("GetFloat64x2TypeDescr", js::GetFloat64x2TypeDescr, 0, 0), - JS_FN("GetInt8x16TypeDescr", js::GetInt8x16TypeDescr, 0, 0), - JS_FN("GetInt16x8TypeDescr", js::GetInt16x8TypeDescr, 0, 0), - JS_FN("GetInt32x4TypeDescr", js::GetInt32x4TypeDescr, 0, 0), - JS_FN("GetUint8x16TypeDescr", js::GetUint8x16TypeDescr, 0, 0), - JS_FN("GetUint16x8TypeDescr", js::GetUint16x8TypeDescr, 0, 0), - JS_FN("GetUint32x4TypeDescr", js::GetUint32x4TypeDescr, 0, 0), - JS_FN("GetBool8x16TypeDescr", js::GetBool8x16TypeDescr, 0, 0), - JS_FN("GetBool16x8TypeDescr", js::GetBool16x8TypeDescr, 0, 0), - JS_FN("GetBool32x4TypeDescr", js::GetBool32x4TypeDescr, 0, 0), - JS_FN("GetBool64x2TypeDescr", js::GetBool64x2TypeDescr, 0, 0), + JS_FN("GetSimdTypeDescr", js::GetSimdTypeDescr, 1, 0), JS_INLINABLE_FN("ObjectIsTypeDescr" , js::ObjectIsTypeDescr, 1, 0, IntrinsicObjectIsTypeDescr), diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index 1ccc93fe88..123f454a61 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -37,25 +37,26 @@ Shape::search(ExclusiveContext* cx, jsid id) return search(cx, this, id, &_); } +template /* static */ inline Shape* -Shape::search(ExclusiveContext* cx, Shape* start, jsid id, ShapeTable::Entry** pentry, bool adding) +Shape::search(ExclusiveContext* cx, Shape* start, jsid id, ShapeTable::Entry** pentry) { if (start->inDictionary()) { - *pentry = &start->table().search(id, adding); + *pentry = &start->table().search(id); return (*pentry)->shape(); } *pentry = nullptr; if (start->hasTable()) { - ShapeTable::Entry& entry = start->table().search(id, adding); + ShapeTable::Entry& entry = start->table().search(id); return entry.shape(); } if (start->numLinearSearches() == LINEAR_SEARCHES_MAX) { if (start->isBigEnoughForAShapeTable()) { if (Shape::hashify(cx, start)) { - ShapeTable::Entry& entry = start->table().search(id, adding); + ShapeTable::Entry& entry = start->table().search(id); return entry.shape(); } else { cx->recoverFromOutOfMemory(); diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index d6c357ae9e..77eaa851dd 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -61,7 +61,7 @@ ShapeTable::init(ExclusiveContext* cx, Shape* lastProp) for (Shape::Range r(lastProp); !r.empty(); r.popFront()) { Shape& shape = r.front(); - Entry& entry = search(shape.propid(), true); + Entry& entry = search(shape.propid()); /* * Beware duplicate args and arg vs. var conflicts: the youngest shape @@ -187,8 +187,9 @@ Hash2(HashNumber hash0, uint32_t log2, uint32_t shift) return ((hash0 << log2) >> shift) | 1; } +template ShapeTable::Entry& -ShapeTable::search(jsid id, bool adding) +ShapeTable::search(jsid id) { MOZ_ASSERT(entries_); MOZ_ASSERT(!JSID_IS_EMPTY(id)); @@ -212,30 +213,31 @@ ShapeTable::search(jsid id, bool adding) HashNumber hash2 = Hash2(hash0, sizeLog2, hashShift_); uint32_t sizeMask = JS_BITMASK(sizeLog2); -#ifdef DEBUG - bool collisionFlag = true; -#endif - /* Save the first removed entry pointer so we can recycle it if adding. */ Entry* firstRemoved; - if (entry->isRemoved()) { - firstRemoved = entry; - } else { - firstRemoved = nullptr; - if (adding && !entry->hadCollision()) - entry->flagCollision(); -#ifdef DEBUG - collisionFlag &= entry->hadCollision(); -#endif + if (Adding == MaybeAdding::Adding) { + if (entry->isRemoved()) { + firstRemoved = entry; + } else { + firstRemoved = nullptr; + if (!entry->hadCollision()) + entry->flagCollision(); + } } +#ifdef DEBUG + bool collisionFlag = true; + if (!entry->isRemoved()) + collisionFlag = entry->hadCollision(); +#endif + while (true) { hash1 -= hash2; hash1 &= sizeMask; entry = &getEntry(hash1); if (entry->isFree()) - return (adding && firstRemoved) ? *firstRemoved : *entry; + return (Adding == MaybeAdding::Adding && firstRemoved) ? *firstRemoved : *entry; shape = entry->shape(); if (shape && shape->propidRaw() == id) { @@ -243,21 +245,28 @@ ShapeTable::search(jsid id, bool adding) return *entry; } - if (entry->isRemoved()) { - if (!firstRemoved) - firstRemoved = entry; - } else { - if (adding && !entry->hadCollision()) - entry->flagCollision(); + if (Adding == MaybeAdding::Adding) { + if (entry->isRemoved()) { + if (!firstRemoved) + firstRemoved = entry; + } else { + if (!entry->hadCollision()) + entry->flagCollision(); + } + } + #ifdef DEBUG + if (!entry->isRemoved()) collisionFlag &= entry->hadCollision(); #endif - } } MOZ_CRASH("Shape::search failed to find an expected entry."); } +template ShapeTable::Entry& ShapeTable::search(jsid id); +template ShapeTable::Entry& ShapeTable::search(jsid id); + bool ShapeTable::change(int log2Delta, ExclusiveContext* cx) { @@ -285,7 +294,7 @@ ShapeTable::change(int log2Delta, ExclusiveContext* cx) /* Copy only live entries, leaving removed and free ones behind. */ for (Entry* oldEntry = oldTable; oldSize != 0; oldEntry++) { if (Shape* shape = oldEntry->shape()) { - Entry& entry = search(shape->propid(), true); + Entry& entry = search(shape->propid()); MOZ_ASSERT(entry.isFree()); entry.setShape(shape); } @@ -496,7 +505,7 @@ NativeObject::addProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId ShapeTable::Entry* entry = nullptr; if (obj->inDictionaryMode()) - entry = &obj->lastProperty()->table().search(id, true); + entry = &obj->lastProperty()->table().search(id); return addPropertyInternal(cx, obj, id, getter, setter, slot, attrs, flags, entry, allowDictionary); @@ -546,14 +555,14 @@ NativeObject::addPropertyInternal(ExclusiveContext* cx, if (!obj->toDictionaryMode(cx)) return nullptr; table = &obj->lastProperty()->table(); - entry = &table->search(id, true); + entry = &table->search(id); } } else { table = &obj->lastProperty()->table(); if (table->needsToGrow()) { if (!table->grow(cx)) return nullptr; - entry = &table->search(id, true); + entry = &table->search(id); MOZ_ASSERT(!entry->shape()); } } @@ -714,7 +723,7 @@ NativeObject::putProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId * shape table. */ ShapeTable::Entry* entry; - RootedShape shape(cx, Shape::search(cx, obj->lastProperty(), id, &entry, true)); + RootedShape shape(cx, Shape::search(cx, obj->lastProperty(), id, &entry)); if (!shape) { /* * You can't add properties to a non-extensible object, but you can change @@ -778,7 +787,7 @@ NativeObject::putProperty(ExclusiveContext* cx, HandleNativeObject obj, HandleId if (shape != obj->lastProperty() && !obj->inDictionaryMode()) { if (!obj->toDictionaryMode(cx)) return nullptr; - entry = &obj->lastProperty()->table().search(shape->propid(), false); + entry = &obj->lastProperty()->table().search(shape->propid()); shape = entry->shape(); } @@ -926,7 +935,7 @@ NativeObject::removeProperty(ExclusiveContext* cx, jsid id_) if (!self->inDictionaryMode() && (shape != self->lastProperty() || !self->canRemoveLastProperty())) { if (!self->toDictionaryMode(cx)) return false; - entry = &self->lastProperty()->table().search(shape->propid(), false); + entry = &self->lastProperty()->table().search(shape->propid()); shape = entry->shape(); } @@ -1109,7 +1118,7 @@ NativeObject::replaceWithNewEquivalentShape(ExclusiveContext* cx, Shape* oldShap ShapeTable& table = self->lastProperty()->table(); ShapeTable::Entry* entry = oldShape->isEmptyShape() ? nullptr - : &table.search(oldShape->propidRef(), false); + : &table.search(oldShape->propidRef()); /* * Splice the new shape into the same position as the old shape, preserving @@ -1310,18 +1319,7 @@ BaseShape::traceChildren(JSTracer* trc) void JSCompartment::sweepBaseShapeTable() { - if (!baseShapes.initialized()) - return; - - for (BaseShapeSet::Enum e(baseShapes); !e.empty(); e.popFront()) { - UnownedBaseShape* base = e.front().unbarrieredGet(); - if (IsAboutToBeFinalizedUnbarriered(&base)) { - e.removeFront(); - } else if (base != e.front().unbarrieredGet()) { - ReadBarriered b(base); - e.rekeyFront(base, b); - } - } + baseShapes.sweep(); } #ifdef JSGC_HASH_TABLE_CHECKS @@ -1606,24 +1604,7 @@ EmptyShape::insertInitialShape(ExclusiveContext* cx, HandleShape shape, HandleOb void JSCompartment::sweepInitialShapeTable() { - if (initialShapes.initialized()) { - for (InitialShapeSet::Enum e(initialShapes); !e.empty(); e.popFront()) { - const InitialShapeEntry& entry = e.front(); - Shape* shape = entry.shape.unbarrieredGet(); - JSObject* proto = entry.proto.raw(); - if (IsAboutToBeFinalizedUnbarriered(&shape) || - (entry.proto.isObject() && IsAboutToBeFinalizedUnbarriered(&proto))) - { - e.removeFront(); - } else { - if (shape != entry.shape.unbarrieredGet() || proto != entry.proto.raw()) { - ReadBarrieredShape readBarrieredShape(shape); - InitialShapeEntry newKey(readBarrieredShape, TaggedProto(proto)); - e.rekeyFront(newKey.getLookup(), newKey); - } - } - } - } + initialShapes.sweep(); } void diff --git a/js/src/vm/Shape.h b/js/src/vm/Shape.h index aa05b3f318..f758484092 100644 --- a/js/src/vm/Shape.h +++ b/js/src/vm/Shape.h @@ -115,12 +115,13 @@ class TenuringTracer; typedef JSGetterOp GetterOp; typedef JSSetterOp SetterOp; -typedef JSPropertyDescriptor PropertyDescriptor; /* Limit on the number of slotful properties in an object. */ static const uint32_t SHAPE_INVALID_SLOT = JS_BIT(24) - 1; static const uint32_t SHAPE_MAXIMUM_SLOT = JS_BIT(24) - 2; +enum class MaybeAdding { Adding = true, NotAdding = false }; + /* * Shapes use multiplicative hashing, but specialized to * minimize footprint. @@ -223,7 +224,9 @@ class ShapeTable { */ bool init(ExclusiveContext* cx, Shape* lastProp); bool change(int log2Delta, ExclusiveContext* cx); - Entry& search(jsid id, bool adding); + + template + Entry& search(jsid id); private: Entry& getEntry(uint32_t i) const { @@ -516,10 +519,9 @@ struct StackBaseShape : public DefaultHasher> static inline bool match(ReadBarriered key, const Lookup& lookup); }; -typedef HashSet, - StackBaseShape, - SystemAllocPolicy> BaseShapeSet; - +using BaseShapeSet = js::GCHashSet, + StackBaseShape, + SystemAllocPolicy>; class Shape : public gc::TenuredCell { @@ -580,8 +582,9 @@ class Shape : public gc::TenuredCell last, else to obj->shape_ */ }; + template static inline Shape* search(ExclusiveContext* cx, Shape* start, jsid id, - ShapeTable::Entry** pentry, bool adding = false); + ShapeTable::Entry** pentry); static inline Shape* searchNoHashify(Shape* start, jsid id); void removeFromDictionary(NativeObject* obj); @@ -635,11 +638,6 @@ class Shape : public gc::TenuredCell info->shapesMallocHeapTreeKids += kids.toHash()->sizeOfIncludingThis(mallocSizeOf); } - bool isNative() const { - MOZ_ASSERT(!(flags & NON_NATIVE) == getObjectClass()->isNative()); - return !(flags & NON_NATIVE); - } - bool isAccessorShape() const { MOZ_ASSERT_IF(flags & ACCESSOR_SHAPE, getAllocKind() == gc::AllocKind::ACCESSOR_SHAPE); return flags & ACCESSOR_SHAPE; @@ -705,25 +703,24 @@ class Shape : public gc::TenuredCell * with these bits. */ enum { - /* Property is placeholder for a non-native class. */ - NON_NATIVE = 0x01, - /* Property stored in per-object dictionary, not shared property tree. */ - IN_DICTIONARY = 0x02, + IN_DICTIONARY = 0x01, /* * Slotful property was stored to more than once. This is used as a * hint for type inference. */ - OVERWRITTEN = 0x04, + OVERWRITTEN = 0x02, /* * This shape is an AccessorShape, a fat Shape that can store * getter/setter information. */ - ACCESSOR_SHAPE = 0x08, + ACCESSOR_SHAPE = 0x04, - UNUSED_BITS = 0x3C + /* Flags used to speed up isBigEnoughForAShapeTable(). */ + HAS_CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE = 0x08, + CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE = 0x10, }; /* Get a shape identical to this one, without parent/kids information. */ @@ -907,11 +904,10 @@ class Shape : public gc::TenuredCell return count; } - bool isBigEnoughForAShapeTable() { - MOZ_ASSERT(!hasTable()); - Shape* shape = this; + private: + bool isBigEnoughForAShapeTableSlow() { uint32_t count = 0; - for (Shape::Range r(shape); !r.empty(); r.popFront()) { + for (Shape::Range r(this); !r.empty(); r.popFront()) { ++count; if (count >= ShapeTable::MIN_ENTRIES) return true; @@ -919,6 +915,29 @@ class Shape : public gc::TenuredCell return false; } + public: + bool isBigEnoughForAShapeTable() { + MOZ_ASSERT(!inDictionary()); + MOZ_ASSERT(!hasTable()); + + // isBigEnoughForAShapeTableSlow is pretty inefficient so we only call + // it once and cache the result. + + if (flags & HAS_CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE) { + bool res = flags & CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE; + MOZ_ASSERT(res == isBigEnoughForAShapeTableSlow()); + return res; + } + + MOZ_ASSERT(!(flags & CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE)); + + bool res = isBigEnoughForAShapeTableSlow(); + if (res) + flags |= CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE; + flags |= HAS_CACHED_BIG_ENOUGH_FOR_SHAPE_TABLE; + return res; + } + #ifdef DEBUG void dump(JSContext* cx, FILE* fp) const; void dumpSubtree(JSContext* cx, int level, FILE* fp) const; @@ -1015,11 +1034,7 @@ struct EmptyShape : public js::Shape { EmptyShape(UnownedBaseShape* base, uint32_t nfixed) : js::Shape(base, nfixed) - { - // Only empty shapes can be NON_NATIVE. - if (!getObjectClass()->isNative()) - flags |= NON_NATIVE; - } + { } static Shape* new_(ExclusiveContext* cx, Handle base, uint32_t nfixed); @@ -1095,11 +1110,18 @@ struct InitialShapeEntry static inline HashNumber hash(const Lookup& lookup); static inline bool match(const InitialShapeEntry& key, const Lookup& lookup); static void rekey(InitialShapeEntry& k, const InitialShapeEntry& newKey) { k = newKey; } + + bool needsSweep() { + Shape* ushape = shape.unbarrieredGet(); + JSObject* protoObj = proto.raw(); + return (gc::IsAboutToBeFinalizedUnbarriered(&ushape) || + (proto.isObject() && gc::IsAboutToBeFinalizedUnbarriered(&protoObj))); + } }; -typedef HashSet InitialShapeSet; +using InitialShapeSet = js::GCHashSet; -struct StackShape : public JS::Traceable +struct StackShape { /* For performance, StackShape only roots when absolutely necessary. */ UnownedBaseShape* base; @@ -1369,7 +1391,7 @@ Shape::searchNoHashify(Shape* start, jsid id) * search. We never hashify into a table in parallel. */ if (start->hasTable()) { - ShapeTable::Entry& entry = start->table().search(id, false); + ShapeTable::Entry& entry = start->table().search(id); return entry.shape(); } diff --git a/js/src/vm/Stack.h b/js/src/vm/Stack.h index a03f67e7c8..6fd4734f14 100644 --- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1050,7 +1050,7 @@ struct DefaultHasher { // entries that must be scanned through, and to avoid the headaches of // maintaining a cache for each compartment and invalidating stale cache entries // in the presence of cross-compartment calls. -class LiveSavedFrameCache : public JS::Traceable +class LiveSavedFrameCache { public: using FramePtr = mozilla::Variant; @@ -1103,7 +1103,7 @@ class LiveSavedFrameCache : public JS::Traceable } static mozilla::Maybe getFramePtr(FrameIter& iter); - static void trace(LiveSavedFrameCache* cache, JSTracer* trc); + void trace(JSTracer* trc); void find(JSContext* cx, FrameIter& frameIter, MutableHandleSavedFrame frame) const; bool insert(JSContext* cx, FramePtr& framePtr, jsbytecode* pc, HandleSavedFrame savedFrame); diff --git a/js/src/vm/TaggedProto.h b/js/src/vm/TaggedProto.h index 412961a08b..53c5fd575c 100644 --- a/js/src/vm/TaggedProto.h +++ b/js/src/vm/TaggedProto.h @@ -14,7 +14,7 @@ namespace js { // Information about an object prototype, which can be either a particular // object, null, or a lazily generated object. The latter is only used by // certain kinds of proxies. -class TaggedProto : public JS::Traceable +class TaggedProto { public: static JSObject * const LazyProto; @@ -44,20 +44,15 @@ class TaggedProto : public JS::Traceable bool operator ==(const TaggedProto& other) const { return proto == other.proto; } bool operator !=(const TaggedProto& other) const { return proto != other.proto; } - static void trace(TaggedProto* protop, JSTracer* trc) { - TraceManuallyBarrieredEdge(trc, protop, "TaggedProto"); + void trace(JSTracer* trc) { + if (isObject()) + TraceManuallyBarrieredEdge(trc, &proto, "TaggedProto"); } private: JSObject* proto; }; -template <> -struct GCPolicy -{ - static TaggedProto initial() { return TaggedProto(); } -}; - template <> struct InternalBarrierMethods { diff --git a/js/src/vm/TypeInference.h b/js/src/vm/TypeInference.h index 4f72662d99..c4cde344ce 100644 --- a/js/src/vm/TypeInference.h +++ b/js/src/vm/TypeInference.h @@ -272,7 +272,7 @@ class TypeSet // Information about a single concrete type. We pack this into one word, // where small values are particular primitive or other singleton types and // larger values are either specific JS objects or object groups. - class Type : public JS::Traceable + class Type { friend class TypeSet; @@ -350,8 +350,8 @@ class TypeSet inline ObjectGroup* group() const; inline ObjectGroup* groupNoBarrier() const; - static void trace(Type* v, JSTracer* trc) { - MarkTypeUnbarriered(trc, v, "TypeSet::Type"); + void trace(JSTracer* trc) { + MarkTypeUnbarriered(trc, this, "TypeSet::Type"); } bool operator == (Type o) const { return data == o.data; } diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index 37b5f8e69e..a0b8259f82 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -735,7 +735,7 @@ UnboxedPlainObject::obj_lookupProperty(JSContext* cx, HandleObject obj, /* static */ bool UnboxedPlainObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) { const UnboxedLayout& layout = obj->as().layout(); @@ -844,7 +844,7 @@ UnboxedPlainObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id /* static */ bool UnboxedPlainObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc) + MutableHandle desc) { const UnboxedLayout& layout = obj->as().layout(); @@ -1428,7 +1428,7 @@ UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj, /* static */ bool UnboxedArrayObject::obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) { if (JSID_IS_INT(id) && !desc.getter() && !desc.setter() && desc.attributes() == JSPROP_ENUMERATE) { @@ -1532,7 +1532,7 @@ UnboxedArrayObject::obj_setProperty(JSContext* cx, HandleObject obj, HandleId id /* static */ bool UnboxedArrayObject::obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc) + MutableHandle desc) { if (obj->as().containsProperty(cx, id)) { if (JSID_IS_INT(id)) { diff --git a/js/src/vm/UnboxedObject.h b/js/src/vm/UnboxedObject.h index b08fcb5e1b..6f86c09125 100644 --- a/js/src/vm/UnboxedObject.h +++ b/js/src/vm/UnboxedObject.h @@ -245,7 +245,7 @@ class UnboxedPlainObject : public JSObject MutableHandleShape propp); static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result); static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp); @@ -257,7 +257,7 @@ class UnboxedPlainObject : public JSObject HandleValue receiver, ObjectOpResult& result); static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc); + MutableHandle desc); static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result); @@ -381,7 +381,7 @@ class UnboxedArrayObject : public JSObject MutableHandleShape propp); static bool obj_defineProperty(JSContext* cx, HandleObject obj, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result); static bool obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* foundp); @@ -393,7 +393,7 @@ class UnboxedArrayObject : public JSObject HandleValue receiver, ObjectOpResult& result); static bool obj_getOwnPropertyDescriptor(JSContext* cx, HandleObject obj, HandleId id, - MutableHandle desc); + MutableHandle desc); static bool obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, ObjectOpResult& result); diff --git a/js/xpconnect/src/Sandbox.cpp b/js/xpconnect/src/Sandbox.cpp index 3a091ba55d..209240ee4d 100644 --- a/js/xpconnect/src/Sandbox.cpp +++ b/js/xpconnect/src/Sandbox.cpp @@ -512,7 +512,7 @@ sandbox_addProperty(JSContext* cx, HandleObject obj, HandleId id, HandleValue v) // After bug 1015790 is fixed, we should be able to remove this unwrapping. RootedObject unwrappedProto(cx, js::UncheckedUnwrap(proto, /* stopAtWindowProxy = */ false)); - Rooted pd(cx); + Rooted pd(cx); if (!JS_GetPropertyDescriptorById(cx, proto, id, &pd)) return false; @@ -722,7 +722,7 @@ WrapCallable(JSContext* cx, HandleObject callable, HandleObject sandboxProtoProx } template -bool WrapAccessorFunction(JSContext* cx, Op& op, JSPropertyDescriptor* desc, +bool WrapAccessorFunction(JSContext* cx, Op& op, PropertyDescriptor* desc, unsigned attrFlag, HandleObject sandboxProtoProxy) { if (!op) { @@ -746,7 +746,7 @@ bool xpc::SandboxProxyHandler::getPropertyDescriptor(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::MutableHandle desc) const + JS::MutableHandle desc) const { JS::RootedObject obj(cx, wrappedObject(proxy)); @@ -781,7 +781,7 @@ bool xpc::SandboxProxyHandler::getOwnPropertyDescriptor(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::MutableHandle desc) + JS::MutableHandle desc) const { if (!getPropertyDescriptor(cx, proxy, id, desc)) @@ -817,7 +817,33 @@ xpc::SandboxProxyHandler::get(JSContext* cx, JS::Handle proxy, JS::Handle id, JS::MutableHandle vp) const { - return BaseProxyHandler::get(cx, proxy, receiver, id, vp); + // This uses getPropertyDescriptor for backward compatibility with + // the old BaseProxyHandler::get implementation. + Rooted desc(cx); + if (!getPropertyDescriptor(cx, proxy, id, &desc)) + return false; + desc.assertCompleteIfFound(); + + if (!desc.object()) { + vp.setUndefined(); + return true; + } + + // Everything after here follows [[Get]] for ordinary objects. + if (desc.isDataDescriptor()) { + vp.set(desc.value()); + return true; + } + + MOZ_ASSERT(desc.isAccessorDescriptor()); + RootedObject getter(cx, desc.getterObject()); + + if (!getter) { + vp.setUndefined(); + return true; + } + + return Call(cx, receiver, getter, HandleValueArray::empty(), vp); } bool diff --git a/js/xpconnect/src/XPCComponents.cpp b/js/xpconnect/src/XPCComponents.cpp index c319542678..9fb70fc85b 100644 --- a/js/xpconnect/src/XPCComponents.cpp +++ b/js/xpconnect/src/XPCComponents.cpp @@ -3021,6 +3021,7 @@ nsXPCComponents_Utils::SetGCZeal(int32_t aValue, JSContext* cx) NS_IMETHODIMP nsXPCComponents_Utils::NukeSandbox(HandleValue obj, JSContext* cx) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::JS); NS_ENSURE_TRUE(obj.isObject(), NS_ERROR_INVALID_ARG); JSObject* wrapper = &obj.toObject(); NS_ENSURE_TRUE(IsWrapper(wrapper), NS_ERROR_INVALID_ARG); diff --git a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp index e8b573b8e9..08926b6cce 100644 --- a/js/xpconnect/src/XPCWrappedNativeJSOps.cpp +++ b/js/xpconnect/src/XPCWrappedNativeJSOps.cpp @@ -398,7 +398,7 @@ DefinePropertyIfFound(XPCCallContext& ccx, } if (scope->HasInterposition()) { - Rooted desc(ccx); + Rooted desc(ccx); if (!xpc::InterposeProperty(ccx, obj, iface->GetIID(), id, &desc)) return false; diff --git a/js/xpconnect/wrappers/AccessCheck.cpp b/js/xpconnect/wrappers/AccessCheck.cpp index e66722c01f..5c8d4fde20 100644 --- a/js/xpconnect/wrappers/AccessCheck.cpp +++ b/js/xpconnect/wrappers/AccessCheck.cpp @@ -329,7 +329,7 @@ ExposedPropertiesOnly::check(JSContext* cx, HandleObject wrapper, HandleId id, W if (id == JSID_VOID) return true; - Rooted desc(cx); + Rooted desc(cx); if (!JS_GetPropertyDescriptorById(cx, wrappedObject, exposedPropsId, &desc)) return false; diff --git a/js/xpconnect/wrappers/AddonWrapper.cpp b/js/xpconnect/wrappers/AddonWrapper.cpp index bfc3e2e593..36e020bfb5 100644 --- a/js/xpconnect/wrappers/AddonWrapper.cpp +++ b/js/xpconnect/wrappers/AddonWrapper.cpp @@ -14,6 +14,8 @@ #include "mozilla/dom/BindingUtils.h" #include "nsGlobalWindow.h" +#include "GeckoProfiler.h" + #include "nsID.h" using namespace js; @@ -23,7 +25,7 @@ namespace xpc { bool InterposeProperty(JSContext* cx, HandleObject target, const nsIID* iid, HandleId id, - MutableHandle descriptor) + MutableHandle descriptor) { // We only want to do interpostion on DOM instances and // wrapped natives. @@ -142,7 +144,7 @@ bool AddonWrapper::call(JSContext* cx, JS::Handle wrapper, template bool AddonWrapper::getPropertyDescriptor(JSContext* cx, HandleObject wrapper, - HandleId id, MutableHandle desc) const + HandleId id, MutableHandle desc) const { if (!InterposeProperty(cx, wrapper, nullptr, id, desc)) return false; @@ -156,7 +158,7 @@ AddonWrapper::getPropertyDescriptor(JSContext* cx, HandleObject wrapper, template bool AddonWrapper::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, - HandleId id, MutableHandle desc) const + HandleId id, MutableHandle desc) const { if (!InterposeProperty(cx, wrapper, nullptr, id, desc)) return false; @@ -172,7 +174,9 @@ bool AddonWrapper::get(JSContext* cx, JS::Handle wrapper, JS::Handle receiver, JS::Handle id, JS::MutableHandle vp) const { - Rooted desc(cx); + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + + Rooted desc(cx); if (!InterposeProperty(cx, wrapper, nullptr, id, &desc)) return false; @@ -192,7 +196,7 @@ bool AddonWrapper::set(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::HandleValue v, JS::HandleValue receiver, JS::ObjectOpResult& result) const { - Rooted desc(cx); + Rooted desc(cx); if (!InterposeProperty(cx, wrapper, nullptr, id, &desc)) return false; @@ -217,10 +221,10 @@ AddonWrapper::set(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id template bool AddonWrapper::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, + Handle desc, ObjectOpResult& result) const { - Rooted interpDesc(cx); + Rooted interpDesc(cx); if (!InterposeProperty(cx, wrapper, nullptr, id, &interpDesc)) return false; @@ -236,7 +240,7 @@ bool AddonWrapper::delete_(JSContext* cx, HandleObject wrapper, HandleId id, ObjectOpResult& result) const { - Rooted desc(cx); + Rooted desc(cx); if (!InterposeProperty(cx, wrapper, nullptr, id, &desc)) return false; diff --git a/js/xpconnect/wrappers/AddonWrapper.h b/js/xpconnect/wrappers/AddonWrapper.h index 5d1a324c3d..f046899dce 100644 --- a/js/xpconnect/wrappers/AddonWrapper.h +++ b/js/xpconnect/wrappers/AddonWrapper.h @@ -17,7 +17,7 @@ namespace xpc { bool InterposeProperty(JSContext* cx, JS::HandleObject target, const nsIID* iid, JS::HandleId id, - JS::MutableHandle descriptor); + JS::MutableHandle descriptor); bool InterposeCall(JSContext* cx, JS::HandleObject wrapper, @@ -30,9 +30,9 @@ class AddonWrapper : public Base { virtual bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result) const override; virtual bool delete_(JSContext* cx, JS::HandleObject proxy, JS::HandleId id, JS::ObjectOpResult& result) const override; @@ -45,7 +45,7 @@ class AddonWrapper : public Base { virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; static const AddonWrapper singleton; }; diff --git a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp index fd542586c1..7c42f17e1a 100644 --- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp +++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp @@ -21,8 +21,8 @@ const ChromeObjectWrapper ChromeObjectWrapper::singleton; bool ChromeObjectWrapper::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, - JS::ObjectOpResult& result) const + Handle desc, + ObjectOpResult& result) const { if (!AccessCheck::checkPassToPrivilegedCode(cx, wrapper, desc.value())) return false; diff --git a/js/xpconnect/wrappers/ChromeObjectWrapper.h b/js/xpconnect/wrappers/ChromeObjectWrapper.h index 23db3500ac..71cba0f450 100644 --- a/js/xpconnect/wrappers/ChromeObjectWrapper.h +++ b/js/xpconnect/wrappers/ChromeObjectWrapper.h @@ -29,7 +29,7 @@ class ChromeObjectWrapper : public ChromeObjectWrapperBase virtual bool defineProperty(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result) const override; virtual bool set(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::HandleValue v, JS::HandleValue receiver, diff --git a/js/xpconnect/wrappers/FilteringWrapper.cpp b/js/xpconnect/wrappers/FilteringWrapper.cpp index 49fbcfed24..e149924ea2 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.cpp +++ b/js/xpconnect/wrappers/FilteringWrapper.cpp @@ -35,7 +35,7 @@ Filter(JSContext* cx, HandleObject wrapper, AutoIdVector& props) template static bool -FilterPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, JS::MutableHandle desc) +FilterPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, MutableHandle desc) { MOZ_ASSERT(!JS_IsExceptionPending(cx)); bool getAllowed = Policy::check(cx, wrapper, id, Wrapper::GET); @@ -68,7 +68,7 @@ template bool FilteringWrapper::getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - JS::MutableHandle desc) const + MutableHandle desc) const { assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET | BaseProxyHandler::GET_PROPERTY_DESCRIPTOR); @@ -81,7 +81,7 @@ template bool FilteringWrapper::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - JS::MutableHandle desc) const + MutableHandle desc) const { assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET | BaseProxyHandler::GET_PROPERTY_DESCRIPTOR); @@ -185,7 +185,7 @@ bool CrossOriginXrayWrapper::getPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const + JS::MutableHandle desc) const { if (!SecurityXrayDOM::getPropertyDescriptor(cx, wrapper, id, desc)) return false; @@ -207,7 +207,7 @@ bool CrossOriginXrayWrapper::getOwnPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const + JS::MutableHandle desc) const { // All properties on cross-origin DOM objects are |own|. return getPropertyDescriptor(cx, wrapper, id, desc); @@ -226,7 +226,7 @@ CrossOriginXrayWrapper::ownPropertyKeys(JSContext* cx, JS::Handle wra bool CrossOriginXrayWrapper::defineProperty(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result) const { JS_ReportError(cx, "Permission denied to define property on cross-origin object"); diff --git a/js/xpconnect/wrappers/FilteringWrapper.h b/js/xpconnect/wrappers/FilteringWrapper.h index a164be2239..26d6e9c630 100644 --- a/js/xpconnect/wrappers/FilteringWrapper.h +++ b/js/xpconnect/wrappers/FilteringWrapper.h @@ -12,8 +12,6 @@ #include "jswrapper.h" #include "js/CallNonGenericMethod.h" -struct JSPropertyDescriptor; - namespace JS { template class AutoVectorRooter; @@ -32,13 +30,13 @@ class FilteringWrapper : public Base { virtual bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; virtual bool ownPropertyKeys(JSContext* cx, JS::Handle wrapper, JS::AutoIdVector& props) const override; virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle wrapper, JS::AutoIdVector& props) const override; virtual bool enumerate(JSContext* cx, JS::Handle wrapper, @@ -69,10 +67,10 @@ class CrossOriginXrayWrapper : public SecurityXrayDOM { virtual bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, JS::Handle wrapper, JS::AutoIdVector& props) const override; @@ -81,7 +79,7 @@ class CrossOriginXrayWrapper : public SecurityXrayDOM { virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; }; } // namespace xpc diff --git a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp index 7e78c122c2..e32dd389f7 100644 --- a/js/xpconnect/wrappers/WaiveXrayWrapper.cpp +++ b/js/xpconnect/wrappers/WaiveXrayWrapper.cpp @@ -13,7 +13,7 @@ using namespace JS; namespace xpc { static bool -WaiveAccessors(JSContext* cx, JS::MutableHandle desc) +WaiveAccessors(JSContext* cx, MutableHandle desc) { if (desc.hasGetterObject() && desc.getterObject()) { RootedValue v(cx, JS::ObjectValue(*desc.getterObject())); @@ -32,18 +32,16 @@ WaiveAccessors(JSContext* cx, JS::MutableHandle desc) } bool -WaiveXrayWrapper::getPropertyDescriptor(JSContext* cx, HandleObject wrapper, - HandleId id, JS::MutableHandle desc) - const +WaiveXrayWrapper::getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, + MutableHandle desc) const { return CrossCompartmentWrapper::getPropertyDescriptor(cx, wrapper, id, desc) && WrapperFactory::WaiveXrayAndWrap(cx, desc.value()) && WaiveAccessors(cx, desc); } bool -WaiveXrayWrapper::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, - HandleId id, JS::MutableHandle desc) - const +WaiveXrayWrapper::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, + MutableHandle desc) const { return CrossCompartmentWrapper::getOwnPropertyDescriptor(cx, wrapper, id, desc) && WrapperFactory::WaiveXrayAndWrap(cx, desc.value()) && WaiveAccessors(cx, desc); diff --git a/js/xpconnect/wrappers/WaiveXrayWrapper.h b/js/xpconnect/wrappers/WaiveXrayWrapper.h index eeb1507dbb..880c7e9005 100644 --- a/js/xpconnect/wrappers/WaiveXrayWrapper.h +++ b/js/xpconnect/wrappers/WaiveXrayWrapper.h @@ -19,7 +19,7 @@ class WaiveXrayWrapper : public js::CrossCompartmentWrapper { virtual bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; virtual bool getPrototype(JSContext* cx, JS::Handle wrapper, JS::MutableHandle protop) const override; virtual bool get(JSContext* cx, JS::Handle wrapper, JS::Handle receiver, @@ -35,7 +35,7 @@ class WaiveXrayWrapper : public js::CrossCompartmentWrapper { JS::NativeImpl impl, const JS::CallArgs& args) const override; virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; static const WaiveXrayWrapper singleton; }; diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index faf57d3e48..f041528cbf 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -173,7 +173,7 @@ const JSClass JSXrayTraits::HolderClass = { bool OpaqueXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, HandleObject wrapper, HandleObject holder, HandleId id, - MutableHandle desc) + MutableHandle desc) { bool ok = XrayTraits::resolveOwnProperty(cx, jsWrapper, wrapper, holder, id, desc); if (!ok || desc.object()) @@ -273,7 +273,7 @@ ReportWrapperDenial(JSContext* cx, HandleId id, WrapperDenialType type, const ch bool JSXrayTraits::getOwnPropertyFromWrapperIfSafe(JSContext* cx, HandleObject wrapper, HandleId id, - MutableHandle outDesc) + MutableHandle outDesc) { MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx)); RootedObject target(cx, getTargetObject(wrapper)); @@ -289,7 +289,7 @@ bool JSXrayTraits::getOwnPropertyFromTargetIfSafe(JSContext* cx, HandleObject target, HandleObject wrapper, HandleId id, - MutableHandle outDesc) + MutableHandle outDesc) { // Note - This function operates in the target compartment, because it // avoids a bunch of back-and-forth wrapping in enumerateNames. @@ -298,7 +298,7 @@ bool JSXrayTraits::getOwnPropertyFromTargetIfSafe(JSContext* cx, MOZ_ASSERT(WrapperFactory::IsXrayWrapper(wrapper)); MOZ_ASSERT(outDesc.object() == nullptr); - Rooted desc(cx); + Rooted desc(cx); if (!JS_GetOwnPropertyDescriptorById(cx, target, id, &desc)) return false; @@ -377,7 +377,7 @@ bool JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, HandleObject wrapper, HandleObject holder, HandleId id, - MutableHandle desc) + MutableHandle desc) { // Call the common code. bool ok = XrayTraits::resolveOwnProperty(cx, jsWrapper, wrapper, holder, @@ -405,7 +405,7 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, // WebExtensions can't use cloneInto(), so we just let them do // the slow thing to maximize compatibility. if (CompartmentPrivate::Get(CurrentGlobalOrNull(cx))->isWebExtensionContentScript) { - Rooted innerDesc(cx); + Rooted innerDesc(cx); { JSAutoCompartment ac(cx, target); if (!JS_GetOwnPropertyDescriptorById(cx, target, id, &innerDesc)) @@ -625,7 +625,7 @@ JSXrayTraits::delete_(JSContext* cx, HandleObject wrapper, HandleId id, ObjectOp if (isObjectOrArrayInstance) { RootedObject target(cx, getTargetObject(wrapper)); JSAutoCompartment ac(cx, target); - Rooted desc(cx); + Rooted desc(cx); if (!getOwnPropertyFromTargetIfSafe(cx, target, wrapper, id, &desc)) return false; if (desc.object()) @@ -636,8 +636,8 @@ JSXrayTraits::delete_(JSContext* cx, HandleObject wrapper, HandleId id, ObjectOp bool JSXrayTraits::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, - Handle existingDesc, + Handle desc, + Handle existingDesc, ObjectOpResult& result, bool* defined) { @@ -680,7 +680,7 @@ JSXrayTraits::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, return false; } - Rooted wrappedDesc(cx, desc); + Rooted wrappedDesc(cx, desc); JSAutoCompartment ac(cx, target); if (!JS_WrapPropertyDescriptor(cx, &wrappedDesc) || !JS_DefinePropertyById(cx, target, id, wrappedDesc, result)) @@ -743,7 +743,7 @@ JSXrayTraits::enumerateNames(JSContext* cx, HandleObject wrapper, unsigned flags if (!props.reserve(targetProps.length())) return false; for (size_t i = 0; i < targetProps.length(); ++i) { - Rooted desc(cx); + Rooted desc(cx); RootedId id(cx, targetProps[i]); if (!getOwnPropertyFromTargetIfSafe(cx, target, wrapper, id, &desc)) return false; @@ -1209,7 +1209,7 @@ XrayToString(JSContext* cx, unsigned argc, JS::Value* vp); bool XPCWrappedNativeXrayTraits::resolveNativeProperty(JSContext* cx, HandleObject wrapper, HandleObject holder, HandleId id, - MutableHandle desc) + MutableHandle desc) { MOZ_ASSERT(js::GetObjectJSClass(holder) == &HolderClass); @@ -1371,7 +1371,7 @@ wrappedJSObject_getter(JSContext* cx, unsigned argc, Value* vp) bool XrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, HandleObject wrapper, HandleObject holder, HandleId id, - MutableHandle desc) + MutableHandle desc) { desc.object().set(nullptr); RootedObject target(cx, getTargetObject(wrapper)); @@ -1443,7 +1443,7 @@ bool XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, HandleObject wrapper, HandleObject holder, HandleId id, - MutableHandle desc) + MutableHandle desc) { // Call the common code. bool ok = XrayTraits::resolveOwnProperty(cx, jsWrapper, wrapper, holder, @@ -1482,8 +1482,8 @@ XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsW bool XPCWrappedNativeXrayTraits::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, - Handle existingDesc, + Handle desc, + Handle existingDesc, JS::ObjectOpResult& result, bool* defined) { *defined = false; @@ -1590,7 +1590,7 @@ XPCWrappedNativeXrayTraits::construct(JSContext* cx, HandleObject wrapper, bool DOMXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, HandleObject wrapper, HandleObject holder, HandleId id, - MutableHandle desc) + MutableHandle desc) { // Call the common code. bool ok = XrayTraits::resolveOwnProperty(cx, jsWrapper, wrapper, holder, id, desc); @@ -1642,8 +1642,8 @@ DOMXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, Handl bool DOMXrayTraits::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, - Handle desc, - Handle existingDesc, + Handle desc, + Handle existingDesc, JS::ObjectOpResult& result, bool* defined) { // Check for an indexed property on a Window. If that's happening, do @@ -1771,7 +1771,7 @@ HasNativeProperty(JSContext* cx, HandleObject wrapper, HandleId id, bool* hasPro RootedObject holder(cx, traits->ensureHolder(cx, wrapper)); NS_ENSURE_TRUE(holder, false); *hasProp = false; - Rooted desc(cx); + Rooted desc(cx); const Wrapper* handler = Wrapper::wrapperHandler(wrapper); // Try resolveOwnProperty. @@ -1879,7 +1879,7 @@ XrayWrapper::isExtensible(JSContext* cx, JS::Handle wra template bool XrayWrapper::getPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - JS::MutableHandle desc) + JS::MutableHandle desc) const { assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET | @@ -1967,7 +1967,7 @@ XrayWrapper::getPropertyDescriptor(JSContext* cx, HandleObject wra template bool XrayWrapper::getOwnPropertyDescriptor(JSContext* cx, HandleObject wrapper, HandleId id, - JS::MutableHandle desc) + JS::MutableHandle desc) const { assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::GET | BaseProxyHandler::SET | @@ -1996,8 +1996,8 @@ XrayWrapper::getOwnPropertyDescriptor(JSContext* cx, HandleObject // to the content object. This is ok, because the the expando object is only // ever accessed by code across the compartment boundary. static bool -RecreateLostWaivers(JSContext* cx, const JSPropertyDescriptor* orig, - MutableHandle wrapped) +RecreateLostWaivers(JSContext* cx, const PropertyDescriptor* orig, + MutableHandle wrapped) { // Compute whether the original objects were waived, and implicitly, whether // they were objects at all. @@ -2041,12 +2041,12 @@ RecreateLostWaivers(JSContext* cx, const JSPropertyDescriptor* orig, template bool XrayWrapper::defineProperty(JSContext* cx, HandleObject wrapper, - HandleId id, Handle desc, + HandleId id, Handle desc, ObjectOpResult& result) const { assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::SET); - Rooted existing_desc(cx); + Rooted existing_desc(cx); if (!JS_GetPropertyDescriptorById(cx, wrapper, id, &existing_desc)) return false; @@ -2091,7 +2091,7 @@ XrayWrapper::defineProperty(JSContext* cx, HandleObject wrapper, return false; // Wrap the property descriptor for the target compartment. - Rooted wrappedDesc(cx, desc); + Rooted wrappedDesc(cx, desc); if (!JS_WrapPropertyDescriptor(cx, &wrappedDesc)) return false; @@ -2146,7 +2146,34 @@ XrayWrapper::get(JSContext* cx, HandleObject wrapper, thisv = receiver; else thisv.setObject(*wrapper); - return js::BaseProxyHandler::get(cx, wrapper, thisv, id, vp); + + // This uses getPropertyDescriptor for backward compatibility with + // the old BaseProxyHandler::get implementation. + Rooted desc(cx); + if (!getPropertyDescriptor(cx, wrapper, id, &desc)) + return false; + desc.assertCompleteIfFound(); + + if (!desc.object()) { + vp.setUndefined(); + return true; + } + + // Everything after here follows [[Get]] for ordinary objects. + if (desc.isDataDescriptor()) { + vp.set(desc.value()); + return true; + } + + MOZ_ASSERT(desc.isAccessorDescriptor()); + RootedObject getter(cx, desc.getterObject()); + + if (!getter) { + vp.setUndefined(); + return true; + } + + return Call(cx, thisv, getter, HandleValueArray::empty(), vp); } template diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index eb9d9ac7dd..ca629be16b 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -69,14 +69,14 @@ public: virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, - JS::MutableHandle desc) = 0; + JS::MutableHandle desc) = 0; // NB: resolveOwnProperty may decide whether or not to cache what it finds // on the holder. If the result is not cached, the lookup will happen afresh // for each access, which is the right thing for things like dynamic NodeList // properties. virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper, JS::HandleObject wrapper, JS::HandleObject holder, - JS::HandleId id, JS::MutableHandle desc); + JS::HandleId id, JS::MutableHandle desc); bool delete_(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::ObjectOpResult& result) { @@ -128,13 +128,13 @@ public: virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, - JS::MutableHandle desc) override; + JS::MutableHandle desc) override; virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, - JS::MutableHandle desc) override; + JS::MutableHandle desc) override; bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, - JS::Handle desc, - JS::Handle existingDesc, + JS::Handle desc, + JS::Handle existingDesc, JS::ObjectOpResult& result, bool* defined); virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper, unsigned flags, JS::AutoIdVector& props); @@ -145,7 +145,7 @@ public: static bool resolveDOMCollectionProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); static XPCWrappedNative* getWN(JSObject* wrapper); @@ -168,7 +168,7 @@ public: virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, - JS::MutableHandle desc) override + JS::MutableHandle desc) override { // Xrays for DOM binding objects have a prototype chain that consists of // Xrays for the prototypes of the DOM binding object (ignoring changes @@ -183,10 +183,10 @@ public: } virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, - JS::MutableHandle desc) override; + JS::MutableHandle desc) override; bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, - JS::Handle desc, - JS::Handle existingDesc, + JS::Handle desc, + JS::Handle existingDesc, JS::ObjectOpResult& result, bool* defined); virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper, unsigned flags, JS::AutoIdVector& props); @@ -216,20 +216,20 @@ public: virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, - JS::MutableHandle desc) override + JS::MutableHandle desc) override { MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1"); } virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, - JS::MutableHandle desc) override; + JS::MutableHandle desc) override; bool delete_(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::ObjectOpResult& result); bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, - JS::Handle desc, - JS::Handle existingDesc, + JS::Handle desc, + JS::Handle existingDesc, JS::ObjectOpResult& result, bool* defined); virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper, unsigned flags, @@ -326,14 +326,14 @@ public: static bool getOwnPropertyFromWrapperIfSafe(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); // Like the above, but operates in the target compartment. static bool getOwnPropertyFromTargetIfSafe(JSContext* cx, JS::HandleObject target, JS::HandleObject wrapper, JS::HandleId id, - JS::MutableHandle desc); + JS::MutableHandle desc); static const JSClass HolderClass; static JSXrayTraits singleton; @@ -352,18 +352,18 @@ public: virtual bool resolveNativeProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, - JS::MutableHandle desc) override + JS::MutableHandle desc) override { MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1"); } virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, - JS::MutableHandle desc) override; + JS::MutableHandle desc) override; bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, - JS::Handle desc, - JS::Handle existingDesc, + JS::Handle desc, + JS::Handle existingDesc, JS::ObjectOpResult& result, bool* defined) { *defined = false; @@ -434,9 +434,9 @@ class XrayWrapper : public Base { /* Standard internal methods. */ virtual bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; virtual bool defineProperty(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::Handle desc, + JS::Handle desc, JS::ObjectOpResult& result) const override; virtual bool ownPropertyKeys(JSContext* cx, JS::Handle wrapper, JS::AutoIdVector& props) const override; @@ -467,7 +467,7 @@ class XrayWrapper : public Base { /* SpiderMonkey extensions. */ virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle wrapper, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; virtual bool hasOwn(JSContext* cx, JS::Handle wrapper, JS::Handle id, bool* bp) const override; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle wrapper, @@ -520,7 +520,7 @@ public: virtual bool getOwnPropertyDescriptor(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; // We just forward the high-level methods to the BaseProxyHandler versions // which implement them in terms of lower-level methods. @@ -534,7 +534,7 @@ public: virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle proxy, JS::Handle id, - JS::MutableHandle desc) const override; + JS::MutableHandle desc) const override; virtual bool hasOwn(JSContext* cx, JS::Handle proxy, JS::Handle id, bool* bp) const override; virtual bool getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle proxy, diff --git a/layout/generic/nsSubDocumentFrame.cpp b/layout/generic/nsSubDocumentFrame.cpp index 8188647901..b97fb19e1f 100644 --- a/layout/generic/nsSubDocumentFrame.cpp +++ b/layout/generic/nsSubDocumentFrame.cpp @@ -83,6 +83,7 @@ public: explicit AsyncFrameInit(nsIFrame* aFrame) : mFrame(aFrame) {} NS_IMETHOD Run() { + PROFILER_LABEL("mozilla", "AsyncFrameInit::Run", js::ProfileEntry::Category::OTHER); if (mFrame.IsAlive()) { static_cast(mFrame.GetFrame())->ShowViewer(); } diff --git a/startupcache/StartupCache.cpp b/startupcache/StartupCache.cpp index c4517a9c41..eeaf6d2290 100644 --- a/startupcache/StartupCache.cpp +++ b/startupcache/StartupCache.cpp @@ -305,7 +305,10 @@ GetBufferFromZipArchive(nsZipArchive *zip, bool doCRC, const char* id, nsresult StartupCache::GetBuffer(const char* id, char** outbuf, uint32_t* length) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + NS_ASSERTION(NS_IsMainThread(), "Startup cache only available on main thread"); + WaitOnWriteThread(); if (!mStartupWriteInitiated) { CacheEntry* entry; diff --git a/testing/mochitest/b2g_start_script.js b/testing/mochitest/b2g_start_script.js index 43de589ef9..8f7aa52490 100644 --- a/testing/mochitest/b2g_start_script.js +++ b/testing/mochitest/b2g_start_script.js @@ -83,13 +83,7 @@ container.addEventListener('mozbrowsershowmodalprompt', function (e) { }); if (outOfProcess) { - let specialpowers = {}; - let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].getService(Ci.mozIJSSubScriptLoader); - loader.loadSubScript("chrome://specialpowers/content/SpecialPowersObserver.js", specialpowers); - let specialPowersObserver = new specialpowers.SpecialPowersObserver(); - let mm = container.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader.messageManager; - specialPowersObserver.init(mm); //Workaround for bug 848411, once that bug is fixed, the following line can be removed function contentScript() { diff --git a/toolkit/commonjs/sdk/content/page-worker.js b/toolkit/commonjs/sdk/content/page-worker.js index cd70902761..e9e741120b 100644 --- a/toolkit/commonjs/sdk/content/page-worker.js +++ b/toolkit/commonjs/sdk/content/page-worker.js @@ -57,6 +57,7 @@ const ChildPage = Class({ dispose: function() { pages.delete(this.id); this.webProgress.removeProgressListener(this); + this.webNav.close(); this.webNav = null; }, diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp index 7250cb889d..47e9d4faf7 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp @@ -1310,6 +1310,7 @@ nsUrlClassifierDBService::ClassifyLocalWithTables(nsIURI *aURI, const nsACString & aTables, nsACString & aTableResults) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); MOZ_ASSERT(NS_IsMainThread(), "ClassifyLocalWithTables must be on main thread"); nsCOMPtr uri = NS_GetInnermostURI(aURI); diff --git a/toolkit/modules/Troubleshoot.jsm b/toolkit/modules/Troubleshoot.jsm index 9dfe40af1e..96bd90bcaf 100644 --- a/toolkit/modules/Troubleshoot.jsm +++ b/toolkit/modules/Troubleshoot.jsm @@ -330,11 +330,10 @@ let dataProviders = { QueryInterface(Ci.nsIInterfaceRequestor). getInterface(Ci.nsIDOMWindowUtils); try { - // Error-state windows need to be skipped - if (winUtils.layerManagerType == "None" || - winUtils.layerManagerType == "Reserved") { + // NOTE: windowless browser's windows should not be reported in the graphics troubleshoot report + if (winUtils.layerManagerType == "None") { continue; - } + } data.numTotalWindows++; data.windowLayerManagerType = winUtils.layerManagerType; data.windowLayerManagerRemote = winUtils.layerManagerRemote; diff --git a/toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp b/toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp index 941de81e1a..7b8a87d80d 100644 --- a/toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp +++ b/toolkit/system/windowsproxy/nsWindowsSystemProxySettings.cpp @@ -16,6 +16,7 @@ #include "nsNetCID.h" #include "nsISupportsPrimitives.h" #include "nsIURI.h" +#include "GeckoProfiler.h" class nsWindowsSystemProxySettings final : public nsISystemProxySettings { @@ -203,6 +204,7 @@ nsWindowsSystemProxySettings::PatternMatch(const nsACString& aHost, nsresult nsWindowsSystemProxySettings::GetPACURI(nsACString& aResult) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::STORAGE); nsresult rv; uint32_t flags = 0; nsAutoString buf; diff --git a/toolkit/xre/nsXREDirProvider.cpp b/toolkit/xre/nsXREDirProvider.cpp index a7c15026a5..6db9fb7fa2 100644 --- a/toolkit/xre/nsXREDirProvider.cpp +++ b/toolkit/xre/nsXREDirProvider.cpp @@ -902,6 +902,8 @@ nsXREDirProvider::DoStartup() void nsXREDirProvider::DoShutdown() { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + if (mProfileNotified) { nsCOMPtr obsSvc = mozilla::services::GetObserverService(); diff --git a/widget/nsBaseDragService.cpp b/widget/nsBaseDragService.cpp index 0c252d5751..16f4c970a9 100644 --- a/widget/nsBaseDragService.cpp +++ b/widget/nsBaseDragService.cpp @@ -212,6 +212,8 @@ nsBaseDragService::InvokeDragSession(nsIDOMNode *aDOMNode, nsIScriptableRegion* aDragRgn, uint32_t aActionType) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + NS_ENSURE_TRUE(aDOMNode, NS_ERROR_INVALID_ARG); NS_ENSURE_TRUE(mSuppressLevel == 0, NS_ERROR_FAILURE); diff --git a/widget/windows/nsFilePicker.cpp b/widget/windows/nsFilePicker.cpp index b41297d2c5..79cadedc0f 100644 --- a/widget/windows/nsFilePicker.cpp +++ b/widget/windows/nsFilePicker.cpp @@ -25,6 +25,7 @@ #include "nsToolkit.h" #include "WinUtils.h" #include "nsPIDOMWindow.h" +#include "GeckoProfiler.h" using mozilla::IsVistaOrLater; using mozilla::MakeUnique; @@ -868,6 +869,7 @@ nsFilePicker::ShowXPFilePicker(const nsString& aInitialDir) bool nsFilePicker::ShowFilePicker(const nsString& aInitialDir, bool &aWasInitError) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); RefPtr dialog; if (mMode != modeSave) { if (FAILED(CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC, diff --git a/xpcom/io/FileUtilsWin.cpp b/xpcom/io/FileUtilsWin.cpp index 6781264ecf..1be104fe46 100644 --- a/xpcom/io/FileUtilsWin.cpp +++ b/xpcom/io/FileUtilsWin.cpp @@ -10,6 +10,7 @@ #include #include "nsWindowsHelpers.h" +#include "GeckoProfiler.h" namespace { @@ -36,6 +37,8 @@ bool HandleToFilename(HANDLE aHandle, const LARGE_INTEGER& aOffset, nsAString& aFilename) { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::NETWORK); + aFilename.Truncate(); // This implementation is nice because it uses fully documented APIs that // are available on all Windows versions that we support. diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index dfbe8df9c4..2c03a814e4 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -11,6 +11,7 @@ #include "nsCOMPtr.h" #include "nsAutoPtr.h" #include "nsMemory.h" +#include "GeckoProfiler.h" #include "nsLocalFile.h" #include "nsIDirectoryEnumerator.h" @@ -1075,6 +1076,7 @@ nsLocalFile::ResolveAndStat() return NS_OK; } + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); // we can't resolve/stat anything that isn't a valid NSPR addressable path if (mWorkingPath.IsEmpty()) { return NS_ERROR_FILE_INVALID_PATH; diff --git a/xpfe/appshell/moz.build b/xpfe/appshell/moz.build index e7a753d6cd..085f5c2614 100644 --- a/xpfe/appshell/moz.build +++ b/xpfe/appshell/moz.build @@ -9,6 +9,7 @@ MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini'] XPIDL_SOURCES += [ 'nsIAppShellService.idl', 'nsIPopupWindowManager.idl', + 'nsIWindowlessBrowser.idl', 'nsIWindowMediator.idl', 'nsIWindowMediatorListener.idl', 'nsIXULBrowserWindow.idl', diff --git a/xpfe/appshell/nsAppShellService.cpp b/xpfe/appshell/nsAppShellService.cpp index 04fd132297..7d1e515b9a 100644 --- a/xpfe/appshell/nsAppShellService.cpp +++ b/xpfe/appshell/nsAppShellService.cpp @@ -34,10 +34,13 @@ #include "nsIScriptContext.h" #include "nsAppShellService.h" +#include "nsContentUtils.h" +#include "nsThreadUtils.h" #include "nsISupportsPrimitives.h" #include "nsIChromeRegistry.h" #include "nsILoadContext.h" #include "nsIWebNavigation.h" +#include "nsIWindowlessBrowser.h" #include "mozilla/Attributes.h" #include "mozilla/Preferences.h" @@ -406,43 +409,100 @@ WebBrowserChrome2Stub::Blur() return NS_ERROR_NOT_IMPLEMENTED; } -// This is the "stub" we return from CreateWindowlessBrowser - it exists -// purely to keep a strong reference to the browser and the container to -// prevent the container being collected while the stub remains alive. -class WindowlessBrowserStub final : public nsIWebNavigation, - public nsIInterfaceRequestor +class BrowserDestroyer final : public nsRunnable { public: - WindowlessBrowserStub(nsIWebBrowser *aBrowser, nsISupports *aContainer) { - mBrowser = aBrowser; + BrowserDestroyer(nsIWebBrowser *aBrowser, nsISupports *aContainer) : + mBrowser(aBrowser), + mContainer(aContainer) + { + } + + NS_IMETHOD + Run() override + { + // Explicitly destroy the browser, in case this isn't the last reference. + nsCOMPtr window = do_QueryInterface(mBrowser); + return window->Destroy(); + } + +protected: + virtual ~BrowserDestroyer() {} + +private: + nsCOMPtr mBrowser; + nsCOMPtr mContainer; +}; + +// This is the "stub" we return from CreateWindowlessBrowser - it exists +// to manage the lifetimes of the nsIWebBrowser and container window. +// In particular, it keeps a strong reference to both, to prevent them from +// being collected while this object remains alive, and ensures that they +// aren't destroyed when it's not safe to run scripts. +class WindowlessBrowser final : public nsIWindowlessBrowser, + public nsIInterfaceRequestor +{ +public: + WindowlessBrowser(nsIWebBrowser *aBrowser, nsISupports *aContainer) : + mBrowser(aBrowser), + mContainer(aContainer), + mClosed(false) + { mWebNavigation = do_QueryInterface(aBrowser); mInterfaceRequestor = do_QueryInterface(aBrowser); - mContainer = aContainer; } NS_DECL_ISUPPORTS - NS_FORWARD_NSIWEBNAVIGATION(mWebNavigation->) - NS_FORWARD_NSIINTERFACEREQUESTOR(mInterfaceRequestor->) + NS_FORWARD_SAFE_NSIWEBNAVIGATION(mWebNavigation) + NS_FORWARD_SAFE_NSIINTERFACEREQUESTOR(mInterfaceRequestor) + + NS_IMETHOD + Close() override + { + NS_ENSURE_TRUE(!mClosed, NS_ERROR_UNEXPECTED); + NS_ASSERTION(nsContentUtils::IsSafeToRunScript(), + "WindowlessBrowser::Close called when not safe to run scripts"); + + mClosed = true; + + mWebNavigation = nullptr; + mInterfaceRequestor = nullptr; + + nsCOMPtr window = do_QueryInterface(mBrowser); + return window->Destroy(); + } + +protected: + virtual ~WindowlessBrowser() + { + if (mClosed) { + return; + } + + NS_WARNING("Windowless browser was not closed prior to destruction"); + + // The docshell destructor needs to dispatch events, and can only run + // when it's safe to run scripts. If this was triggered by GC, it may + // not always be safe to run scripts, in which cases we need to delay + // destruction until it is. + nsCOMPtr runnable = new BrowserDestroyer(mBrowser, mContainer); + nsContentUtils::AddScriptRunner(runnable); + } + private: - ~WindowlessBrowserStub() {} nsCOMPtr mBrowser; nsCOMPtr mWebNavigation; nsCOMPtr mInterfaceRequestor; // we don't use the container but just hold a reference to it. nsCOMPtr mContainer; + + bool mClosed; }; -NS_INTERFACE_MAP_BEGIN(WindowlessBrowserStub) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIWebNavigation) - NS_INTERFACE_MAP_ENTRY(nsIWebNavigation) - NS_INTERFACE_MAP_ENTRY(nsIInterfaceRequestor) -NS_INTERFACE_MAP_END - -NS_IMPL_ADDREF(WindowlessBrowserStub) -NS_IMPL_RELEASE(WindowlessBrowserStub) +NS_IMPL_ISUPPORTS(WindowlessBrowser, nsIWindowlessBrowser, nsIWebNavigation, nsIInterfaceRequestor) NS_IMETHODIMP -nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, nsIWebNavigation **aResult) +nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, nsIWindowlessBrowser **aResult) { /* First, we create an instance of nsWebBrowser. Instances of this class have * an associated doc shell, which is what we're interested in. @@ -487,7 +547,7 @@ nsAppShellService::CreateWindowlessBrowser(bool aIsChrome, nsIWebNavigation **aR window->Create(); nsISupports *isstub = NS_ISUPPORTS_CAST(nsIWebBrowserChrome2*, stub); - RefPtr result = new WindowlessBrowserStub(browser, isstub); + RefPtr result = new WindowlessBrowser(browser, isstub); nsCOMPtr docshell = do_GetInterface(result); docshell->SetInvisible(true); diff --git a/xpfe/appshell/nsIAppShellService.idl b/xpfe/appshell/nsIAppShellService.idl index 151b0e36de..58599d450f 100644 --- a/xpfe/appshell/nsIAppShellService.idl +++ b/xpfe/appshell/nsIAppShellService.idl @@ -6,7 +6,7 @@ #include "nsISupports.idl" interface nsIXULWindow; -interface nsIWebNavigation; +interface nsIWindowlessBrowser; interface nsIURI; interface nsIDOMWindow; interface nsIAppShell; @@ -18,7 +18,7 @@ interface nsITabParent; #include "js/TypeDecls.h" %} -[scriptable, uuid(83f23c7e-6ce0-433f-9fe2-f287ae8c6e0c)] +[scriptable, uuid(0cc1c790-6873-4b31-944f-71d3725e373d)] interface nsIAppShellService : nsISupports { /** @@ -53,7 +53,7 @@ interface nsIAppShellService : nsISupports * representation. * @param aIsChrome Set true if you want to use it for chrome content. */ - nsIWebNavigation createWindowlessBrowser([optional] in bool aIsChrome); + nsIWindowlessBrowser createWindowlessBrowser([optional] in bool aIsChrome); [noscript] void createHiddenWindow(); diff --git a/xpfe/appshell/nsIWindowlessBrowser.idl b/xpfe/appshell/nsIWindowlessBrowser.idl new file mode 100644 index 0000000000..c959e47a41 --- /dev/null +++ b/xpfe/appshell/nsIWindowlessBrowser.idl @@ -0,0 +1,27 @@ +/* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * 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 "nsIWebNavigation.idl" + +/** + * This interface represents a nsIWebBrowser instance with no associated OS + * window. Its main function is to manage the lifetimes of those windows. + * A strong reference to this object must be held until the window is + * ready to be destroyed. + */ +[scriptable, uuid(abb46f48-abfc-41bf-aa9a-7feccefcf977)] +interface nsIWindowlessBrowser : nsIWebNavigation +{ + /** + * "Closes" the windowless browser and destroys its associated nsIWebBrowser + * and docshell. + * + * This method *must* be called for every windowless browser before its last + * reference is released. + */ + void close(); +}; + diff --git a/xpfe/appshell/nsXULWindow.cpp b/xpfe/appshell/nsXULWindow.cpp index ba1bfe966e..f66e8bec99 100644 --- a/xpfe/appshell/nsXULWindow.cpp +++ b/xpfe/appshell/nsXULWindow.cpp @@ -383,6 +383,8 @@ NS_IMETHODIMP nsXULWindow::RemoveChildWindow(nsIXULWindow *aChild) NS_IMETHODIMP nsXULWindow::ShowModal() { + PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER); + // Store locally so it doesn't die on us nsCOMPtr window = mWindow; nsCOMPtr tempRef = this; diff --git a/xpfe/appshell/test/test_windowlessBrowser.xul b/xpfe/appshell/test/test_windowlessBrowser.xul index 92540c2643..ef91f76550 100644 --- a/xpfe/appshell/test/test_windowlessBrowser.xul +++ b/xpfe/appshell/test/test_windowlessBrowser.xul @@ -59,6 +59,8 @@ function testWindowlessBrowser(chromePrivileged) { } ok(!exception, "window.external.AddSearchProvider should be ignore withour raising an exception"); + + webNav.close(); } info("Test Bug 1214174 on a content privileged windowless browser");