Merge m-i to m-c, a=merge

MozReview-Commit-ID: EDVoIcyWOhi

--HG--
rename : storage/test/test_AsXXX_helpers.cpp => storage/test/gtest/test_AsXXX_helpers.cpp
rename : storage/test/test_binding_params.cpp => storage/test/gtest/test_binding_params.cpp
rename : storage/test/test_mutex.cpp => storage/test/gtest/test_mutex.cpp
This commit is contained in:
Phil Ringnalda 2016-11-22 20:03:03 -08:00
commit feef954874
217 changed files with 3440 additions and 3359 deletions

13
.clang-tidy Normal file
View File

@ -0,0 +1,13 @@
# Checks run by clang-tidy over Mozilla code.
# NOTE: please request review from ehsan when changing this file.
# The following checks are currently enabled:
# * misc-use-override
# Adds missing override keywords, and removes override keywords if the final
# keyword is present as well.
Checks: '-*,misc-use-override'
CheckOptions:
# Don't touch the virtual keyword!
- key: misc-use-override.KeepVirtual
value: '1'

View File

@ -85,6 +85,20 @@ DocManager::FindAccessibleInCache(nsINode* aNode) const
return nullptr;
}
void
DocManager::RemoveFromXPCDocumentCache(DocAccessible* aDocument)
{
xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
if (xpcDoc) {
xpcDoc->Shutdown();
mXPCDocumentCache.Remove(aDocument);
}
if (!HasXPCDocuments()) {
MaybeShutdownAccService(nsAccessibilityService::eXPCOM);
}
}
void
DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
nsIDocument* aDOMDocument)
@ -99,23 +113,28 @@ DocManager::NotifyOfDocumentShutdown(DocAccessible* aDocument,
return;
}
xpcAccessibleDocument* xpcDoc = mXPCDocumentCache.GetWeak(aDocument);
if (xpcDoc) {
xpcDoc->Shutdown();
mXPCDocumentCache.Remove(aDocument);
}
RemoveFromXPCDocumentCache(aDocument);
mDocAccessibleCache.Remove(aDOMDocument);
}
void
DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
DocManager::RemoveFromRemoteXPCDocumentCache(DocAccessibleParent* aDoc)
{
xpcAccessibleDocument* doc = GetCachedXPCDocument(aDoc);
if (doc) {
doc->Shutdown();
sRemoteXPCDocumentCache->Remove(aDoc);
}
if (sRemoteXPCDocumentCache && sRemoteXPCDocumentCache->Count() == 0) {
MaybeShutdownAccService(nsAccessibilityService::eXPCOM);
}
}
void
DocManager::NotifyOfRemoteDocShutdown(DocAccessibleParent* aDoc)
{
RemoveFromRemoteXPCDocumentCache(aDoc);
}
xpcAccessibleDocument*

View File

@ -66,6 +66,8 @@ public:
void NotifyOfDocumentShutdown(DocAccessible* aDocument,
nsIDocument* aDOMDocument);
void RemoveFromXPCDocumentCache(DocAccessible* aDocument);
/**
* Return XPCOM accessible document.
*/
@ -95,6 +97,8 @@ public:
*/
static void NotifyOfRemoteDocShutdown(DocAccessibleParent* adoc);
static void RemoveFromRemoteXPCDocumentCache(DocAccessibleParent* aDoc);
/**
* Get a XPC document for a remote document.
*/
@ -123,6 +127,12 @@ protected:
*/
void Shutdown();
bool HasXPCDocuments()
{
return mXPCDocumentCache.Count() > 0 ||
(sRemoteXPCDocumentCache && sRemoteXPCDocumentCache->Count() > 0);
}
private:
DocManager(const DocManager&);
DocManager& operator =(const DocManager&);

View File

@ -1815,7 +1815,8 @@ MaybeShutdownAccService(uint32_t aFormerConsumer)
}
if (nsCoreUtils::AccEventObserversExist() ||
xpcAccessibilityService::IsInUse()) {
xpcAccessibilityService::IsInUse() ||
accService->HasXPCDocuments()) {
// Still used by XPCOM
nsAccessibilityService::gConsumers =
(nsAccessibilityService::gConsumers & ~aFormerConsumer) |

View File

@ -4,9 +4,21 @@ support-files =
head.js
shared-head.js
[browser_shutdown_acc_reference.js]
[browser_shutdown_doc_acc_reference.js]
[browser_shutdown_multi_acc_reference_obj.js]
[browser_shutdown_multi_acc_reference_doc.js]
[browser_shutdown_multi_reference.js]
[browser_shutdown_parent_own_reference.js]
skip-if = !e10s # e10s specific test for a11y start/shutdown between parent and content.
[browser_shutdown_proxy_acc_reference.js]
skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
[browser_shutdown_proxy_doc_acc_reference.js]
skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
[browser_shutdown_multi_proxy_acc_reference_doc.js]
skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
[browser_shutdown_multi_proxy_acc_reference_obj.js]
skip-if = !e10s || (os == 'win') # e10s specific test for a11y start/shutdown between parent and content.
[browser_shutdown_remote_no_reference.js]
skip-if = !e10s # e10s specific test for a11y start/shutdown between parent and content.
[browser_shutdown_remote_only.js]

View File

@ -0,0 +1,55 @@
/* 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/. */
'use strict';
add_task(function* () {
// Create a11y service.
let a11yInit = initPromise();
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
Ci.nsIAccessibilityService);
yield a11yInit;
ok(accService, 'Service initialized');
// Accessible object reference will live longer than the scope of this
// function.
let acc = yield new Promise(resolve => {
let intervalId = setInterval(() => {
let tabAcc = accService.getAccessibleFor(gBrowser.mCurrentTab);
if (tabAcc) {
clearInterval(intervalId);
resolve(tabAcc);
}
}, 10);
});
ok(acc, 'Accessible object is created');
let canShutdown = false;
// This promise will resolve only if canShutdown flag is set to true. If
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
// down, the promise will reject.
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject('Accessible service was shut down incorrectly')));
accService = null;
ok(!accService, 'Service is removed');
// Force garbage collection that should not trigger shutdown because there is
// a reference to an accessible object.
forceGC();
// Have some breathing room when removing a11y service references.
yield new Promise(resolve => executeSoon(resolve));
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a reference to an accessible object.
acc = null;
ok(!acc, 'Accessible object is removed');
// Force garbage collection that should now trigger shutdown.
forceGC();
yield a11yShutdown;
});

View File

@ -0,0 +1,47 @@
/* 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/. */
'use strict';
add_task(function* () {
// Create a11y service.
let a11yInit = initPromise();
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
Ci.nsIAccessibilityService);
yield a11yInit;
ok(accService, 'Service initialized');
// Accessible document reference will live longer than the scope of this
// function.
let docAcc = accService.getAccessibleFor(document);
ok(docAcc, 'Accessible document is created');
let canShutdown = false;
// This promise will resolve only if canShutdown flag is set to true. If
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
// down, the promise will reject.
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject('Accessible service was shut down incorrectly')));
accService = null;
ok(!accService, 'Service is removed');
// Force garbage collection that should not trigger shutdown because there is
// a reference to an accessible document.
forceGC();
// Have some breathing room when removing a11y service references.
yield new Promise(resolve => executeSoon(resolve));
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a reference to an accessible document.
docAcc = null;
ok(!docAcc, 'Accessible document is removed');
// Force garbage collection that should now trigger shutdown.
forceGC();
yield a11yShutdown;
});

View File

@ -0,0 +1,67 @@
/* 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/. */
'use strict';
add_task(function* () {
// Create a11y service.
let a11yInit = initPromise();
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
Ci.nsIAccessibilityService);
yield a11yInit;
ok(accService, 'Service initialized');
let docAcc = accService.getAccessibleFor(document);
ok(docAcc, 'Accessible document is created');
// Accessible object reference will live longer than the scope of this
// function.
let acc = yield new Promise(resolve => {
let intervalId = setInterval(() => {
let tabAcc = accService.getAccessibleFor(gBrowser.mCurrentTab);
if (tabAcc) {
clearInterval(intervalId);
resolve(tabAcc);
}
}, 10);
});
ok(acc, 'Accessible object is created');
let canShutdown = false;
// This promise will resolve only if canShutdown flag is set to true. If
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
// down, the promise will reject.
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject('Accessible service was shut down incorrectly')));
accService = null;
ok(!accService, 'Service is removed');
// Force garbage collection that should not trigger shutdown because there are
// references to accessible objects.
forceGC();
// Have some breathing room when removing a11y service references.
yield new Promise(resolve => executeSoon(resolve));
// Remove a reference to an accessible object.
acc = null;
ok(!acc, 'Accessible object is removed');
// Force garbage collection that should not trigger shutdown because there is
// a reference to an accessible document.
forceGC();
// Have some breathing room when removing a11y service references.
yield new Promise(resolve => executeSoon(resolve));
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a reference to an accessible document.
docAcc = null;
ok(!docAcc, 'Accessible document is removed');
// Force garbage collection that should now trigger shutdown.
forceGC();
yield a11yShutdown;
});

View File

@ -0,0 +1,67 @@
/* 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/. */
'use strict';
add_task(function* () {
// Create a11y service.
let a11yInit = initPromise();
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
Ci.nsIAccessibilityService);
yield a11yInit;
ok(accService, 'Service initialized');
let docAcc = accService.getAccessibleFor(document);
ok(docAcc, 'Accessible document is created');
// Accessible object reference will live longer than the scope of this
// function.
let acc = yield new Promise(resolve => {
let intervalId = setInterval(() => {
let tabAcc = accService.getAccessibleFor(gBrowser.mCurrentTab);
if (tabAcc) {
clearInterval(intervalId);
resolve(tabAcc);
}
}, 10);
});
ok(acc, 'Accessible object is created');
let canShutdown = false;
// This promise will resolve only if canShutdown flag is set to true. If
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
// down, the promise will reject.
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject('Accessible service was shut down incorrectly')));
accService = null;
ok(!accService, 'Service is removed');
// Force garbage collection that should not trigger shutdown because there are
// references to accessible objects.
forceGC();
// Have some breathing room when removing a11y service references.
yield new Promise(resolve => executeSoon(resolve));
// Remove a reference to an accessible document.
docAcc = null;
ok(!docAcc, 'Accessible document is removed');
// Force garbage collection that should not trigger shutdown because there is
// a reference to an accessible object.
forceGC();
// Have some breathing room when removing a11y service references.
yield new Promise(resolve => executeSoon(resolve));
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a reference to an accessible object.
acc = null;
ok(!acc, 'Accessible object is removed');
// Force garbage collection that should now trigger shutdown.
forceGC();
yield a11yShutdown;
});

View File

@ -0,0 +1,76 @@
/* 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/. */
'use strict';
add_task(function* () {
// Making sure that the e10s is enabled on Windows for testing.
yield setE10sPrefs();
let docLoaded = waitForEvent(
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, 'body');
let a11yInit = initPromise();
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
Ci.nsIAccessibilityService);
ok(accService, 'Service initialized');
yield a11yInit;
yield BrowserTestUtils.withNewTab({
gBrowser,
url: `data:text/html,
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>
</head>
<body id="body"><div id="div"></div></body>
</html>`
}, function*(browser) {
let docLoadedEvent = yield docLoaded;
let docAcc = docLoadedEvent.accessibleDocument;
ok(docAcc, 'Accessible document proxy is created');
// Remove unnecessary dangling references
docLoaded = null;
docLoadedEvent = null;
forceGC();
let acc = docAcc.getChildAt(0);
ok(acc, 'Accessible proxy is created');
let canShutdown = false;
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject('Accessible service was shut down incorrectly')));
accService = null;
ok(!accService, 'Service is removed');
// Force garbage collection that should not trigger shutdown because there
// is a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
yield new Promise(resolve => executeSoon(resolve));
// Remove a reference to an accessible proxy.
acc = null;
ok(!acc, 'Accessible proxy is removed');
// Force garbage collection that should not trigger shutdown because there is
// a reference to an accessible document proxy.
forceGC();
// Have some breathing room when removing a11y service references.
yield new Promise(resolve => executeSoon(resolve));
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a last reference to an accessible document proxy.
docAcc = null;
ok(!docAcc, 'Accessible document proxy is removed');
// Force garbage collection that should now trigger shutdown.
forceGC();
yield a11yShutdown;
});
// Unsetting e10s related preferences.
yield unsetE10sPrefs();
});

View File

@ -0,0 +1,76 @@
/* 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/. */
'use strict';
add_task(function* () {
// Making sure that the e10s is enabled on Windows for testing.
yield setE10sPrefs();
let docLoaded = waitForEvent(
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, 'body');
let a11yInit = initPromise();
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
Ci.nsIAccessibilityService);
ok(accService, 'Service initialized');
yield a11yInit;
yield BrowserTestUtils.withNewTab({
gBrowser,
url: `data:text/html,
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>
</head>
<body id="body"><div id="div"></div></body>
</html>`
}, function*(browser) {
let docLoadedEvent = yield docLoaded;
let docAcc = docLoadedEvent.accessibleDocument;
ok(docAcc, 'Accessible document proxy is created');
// Remove unnecessary dangling references
docLoaded = null;
docLoadedEvent = null;
forceGC();
let acc = docAcc.getChildAt(0);
ok(acc, 'Accessible proxy is created');
let canShutdown = false;
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject('Accessible service was shut down incorrectly')));
accService = null;
ok(!accService, 'Service is removed');
// Force garbage collection that should not trigger shutdown because there
// is a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
yield new Promise(resolve => executeSoon(resolve));
// Remove a reference to an accessible document proxy.
docAcc = null;
ok(!docAcc, 'Accessible document proxy is removed');
// Force garbage collection that should not trigger shutdown because there is
// a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
yield new Promise(resolve => executeSoon(resolve));
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a last reference to an accessible proxy.
acc = null;
ok(!acc, 'Accessible proxy is removed');
// Force garbage collection that should now trigger shutdown.
forceGC();
yield a11yShutdown;
});
// Unsetting e10s related preferences.
yield unsetE10sPrefs();
});

View File

@ -21,7 +21,7 @@ add_task(function* () {
info('Removing all service references');
let canShutdown = false;
// This promise will resolve only if canShutdonw flag is set to true. If
// This promise will resolve only if canShutdown flag is set to true. If
// 'a11y-init-or-shutdown' event with '0' flag comes before it can be shut
// down, the promise will reject.
let a11yShutdown = new Promise((resolve, reject) =>

View File

@ -0,0 +1,64 @@
/* 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/. */
'use strict';
add_task(function* () {
// Making sure that the e10s is enabled on Windows for testing.
yield setE10sPrefs();
let a11yInit = initPromise();
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
Ci.nsIAccessibilityService);
ok(accService, 'Service initialized');
yield a11yInit;
yield BrowserTestUtils.withNewTab({
gBrowser,
url: `data:text/html,
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>
</head>
<body><div id="div" style="visibility: hidden;"></div></body>
</html>`
}, function*(browser) {
let onShow = waitForEvent(Ci.nsIAccessibleEvent.EVENT_SHOW, 'div');
yield invokeSetStyle(browser, 'div', 'visibility', 'visible');
let showEvent = yield onShow;
let divAcc = showEvent.accessible;
ok(divAcc, 'Accessible proxy is created');
// Remove unnecessary dangling references
onShow = null;
showEvent = null;
forceGC();
let canShutdown = false;
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject('Accessible service was shut down incorrectly')));
accService = null;
ok(!accService, 'Service is removed');
// Force garbage collection that should not trigger shutdown because there
// is a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
yield new Promise(resolve => executeSoon(resolve));
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a last reference to an accessible proxy.
divAcc = null;
ok(!divAcc, 'Accessible proxy is removed');
// Force garbage collection that should now trigger shutdown.
forceGC();
yield a11yShutdown;
});
// Unsetting e10s related preferences.
yield unsetE10sPrefs();
});

View File

@ -0,0 +1,64 @@
/* 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/. */
'use strict';
add_task(function* () {
// Making sure that the e10s is enabled on Windows for testing.
yield setE10sPrefs();
let docLoaded = waitForEvent(
Ci.nsIAccessibleEvent.EVENT_DOCUMENT_LOAD_COMPLETE, 'body');
let a11yInit = initPromise();
let accService = Cc['@mozilla.org/accessibilityService;1'].getService(
Ci.nsIAccessibilityService);
ok(accService, 'Service initialized');
yield a11yInit;
yield BrowserTestUtils.withNewTab({
gBrowser,
url: `data:text/html,
<html>
<head>
<meta charset="utf-8"/>
<title>Accessibility Test</title>
</head>
<body id="body"></body>
</html>`
}, function*(browser) {
let docLoadedEvent = yield docLoaded;
let docAcc = docLoadedEvent.accessibleDocument;
ok(docAcc, 'Accessible document proxy is created');
// Remove unnecessary dangling references
docLoaded = null;
docLoadedEvent = null;
forceGC();
let canShutdown = false;
let a11yShutdown = new Promise((resolve, reject) =>
shutdownPromise().then(flag => canShutdown ? resolve() :
reject('Accessible service was shut down incorrectly')));
accService = null;
ok(!accService, 'Service is removed');
// Force garbage collection that should not trigger shutdown because there
// is a reference to an accessible proxy.
forceGC();
// Have some breathing room when removing a11y service references.
yield new Promise(resolve => executeSoon(resolve));
// Now allow a11y service to shutdown.
canShutdown = true;
// Remove a last reference to an accessible document proxy.
docAcc = null;
ok(!docAcc, 'Accessible document proxy is removed');
// Force garbage collection that should now trigger shutdown.
forceGC();
yield a11yShutdown;
});
// Unsetting e10s related preferences.
yield unsetE10sPrefs();
});

View File

@ -4,8 +4,8 @@
'use strict';
/* exported initPromise, shutdownPromise,
setE10sPrefs, unsetE10sPrefs, forceGC */
/* exported initPromise, shutdownPromise, waitForEvent, setE10sPrefs,
unsetE10sPrefs, forceGC */
/**
* Set e10s related preferences in the test environment.
@ -107,10 +107,34 @@ function shutdownPromise(contentBrowser) {
() => ok(false, 'Service initialized incorrectly'));
}
/**
* Simpler verions of waitForEvent defined in
* accessible/tests/browser/e10s/events.js
*/
function waitForEvent(eventType, expectedId) {
return new Promise(resolve => {
let eventObserver = {
observe(subject) {
let event = subject.QueryInterface(Ci.nsIAccessibleEvent);
if (event.eventType === eventType &&
event.accessible.id === expectedId) {
Services.obs.removeObserver(this, 'accessible-event');
resolve(event);
}
}
};
Services.obs.addObserver(eventObserver, 'accessible-event', false);
});
}
/**
* Force garbage collection.
*/
function forceGC() {
Cu.forceCC();
Cu.forceGC();
SpecialPowers.gc();
SpecialPowers.forceGC();
SpecialPowers.forceCC();
SpecialPowers.gc();
SpecialPowers.forceGC();
SpecialPowers.forceCC();
}

View File

@ -33,7 +33,10 @@ public:
NS_IMETHOD GetPlatformVersion(nsAString& aVersion) final override;
protected:
virtual ~xpcAccessibleApplication() {}
virtual ~xpcAccessibleApplication()
{
Shutdown();
}
private:
ApplicationAccessible* Intl() { return mIntl.AsAccessible()->AsApplication(); }

View File

@ -17,26 +17,28 @@ using namespace mozilla;
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// nsISupports and cycle collection
NS_IMPL_CYCLE_COLLECTION_CLASS(xpcAccessibleDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(xpcAccessibleDocument,
xpcAccessibleGeneric)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCache)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(xpcAccessibleDocument,
xpcAccessibleGeneric)
tmp->mCache.Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(xpcAccessibleDocument)
NS_INTERFACE_MAP_ENTRY(nsIAccessibleDocument)
NS_INTERFACE_MAP_END_INHERITING(xpcAccessibleHyperText)
// nsISupports
NS_IMPL_QUERY_INTERFACE_INHERITED(xpcAccessibleDocument, xpcAccessibleHyperText,
nsIAccessibleDocument)
NS_IMPL_ADDREF_INHERITED(xpcAccessibleDocument, xpcAccessibleHyperText)
NS_IMPL_RELEASE_INHERITED(xpcAccessibleDocument, xpcAccessibleHyperText)
NS_IMETHODIMP_(MozExternalRefCountType) xpcAccessibleDocument::Release(void)
{
nsrefcnt r = xpcAccessibleHyperText::Release();
NS_LOG_RELEASE(this, r, "xpcAccessibleDocument");
// The only reference to the xpcAccessibleDocument is in DocManager's cache.
if (r == 1 && !mIntl.IsNull() && mCache.Count() == 0) {
if (mIntl.IsAccessible()) {
GetAccService()->RemoveFromXPCDocumentCache(
mIntl.AsAccessible()->AsDoc());
} else {
GetAccService()->RemoveFromRemoteXPCDocumentCache(
mIntl.AsProxy()->AsDoc());
}
}
return r;
}
////////////////////////////////////////////////////////////////////////////////
// nsIAccessibleDocument
@ -179,7 +181,7 @@ xpcAccessibleDocument::GetAccessible(Accessible* aAccessible)
if (aAccessible->IsDoc())
return this;
xpcAccessibleGeneric* xpcAcc = mCache.GetWeak(aAccessible);
xpcAccessibleGeneric* xpcAcc = mCache.Get(aAccessible);
if (xpcAcc)
return xpcAcc;
@ -207,7 +209,7 @@ xpcAccessibleDocument::GetXPCAccessible(ProxyAccessible* aProxy)
return this;
}
xpcAccessibleGeneric* acc = mCache.GetWeak(aProxy);
xpcAccessibleGeneric* acc = mCache.Get(aProxy);
if (acc) {
return acc;
}
@ -217,7 +219,7 @@ xpcAccessibleDocument::GetXPCAccessible(ProxyAccessible* aProxy)
if (aProxy->mHasValue) {
interfaces |= eValue;
}
if (aProxy->mIsHyperLink) {
interfaces |= eHyperLink;
}

View File

@ -32,8 +32,6 @@ public:
mRemote(true) {}
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(xpcAccessibleDocument,
xpcAccessibleGeneric)
// nsIAccessibleDocument
NS_IMETHOD GetURL(nsAString& aURL) final override;
@ -75,33 +73,43 @@ private:
void NotifyOfShutdown(Accessible* aAccessible)
{
MOZ_ASSERT(!mRemote);
xpcAccessibleGeneric* xpcAcc = mCache.GetWeak(aAccessible);
if (xpcAcc)
xpcAccessibleGeneric* xpcAcc = mCache.Get(aAccessible);
if (xpcAcc) {
xpcAcc->Shutdown();
}
mCache.Remove(aAccessible);
if (mCache.Count() == 0 && mRefCnt == 1) {
GetAccService()->RemoveFromXPCDocumentCache(
mIntl.AsAccessible()->AsDoc());
}
}
void NotifyOfShutdown(ProxyAccessible* aProxy)
{
MOZ_ASSERT(mRemote);
xpcAccessibleGeneric* acc = mCache.GetWeak(aProxy);
if (acc) {
acc->Shutdown();
xpcAccessibleGeneric* xpcAcc = mCache.Get(aProxy);
if (xpcAcc) {
xpcAcc->Shutdown();
}
mCache.Remove(aProxy);
if (mCache.Count() == 0 && mRefCnt == 1) {
GetAccService()->RemoveFromRemoteXPCDocumentCache(
mIntl.AsProxy()->AsDoc());
}
}
friend class DocManager;
friend class DocAccessible;
friend class ProxyAccessible;
friend class ProxyAccessibleBase<ProxyAccessible>;
friend class xpcAccessibleGeneric;
xpcAccessibleDocument(const xpcAccessibleDocument&) = delete;
xpcAccessibleDocument& operator =(const xpcAccessibleDocument&) = delete;
nsRefPtrHashtable<nsPtrHashKey<const void>, xpcAccessibleGeneric> mCache;
nsDataHashtable<nsPtrHashKey<const void>, xpcAccessibleGeneric*> mCache;
bool mRemote;
};

View File

@ -9,11 +9,9 @@
using namespace mozilla::a11y;
////////////////////////////////////////////////////////////////////////////////
// nsISupports and cycle collection
// nsISupports
NS_IMPL_CYCLE_COLLECTION_0(xpcAccessibleGeneric)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(xpcAccessibleGeneric)
NS_INTERFACE_MAP_BEGIN(xpcAccessibleGeneric)
NS_INTERFACE_MAP_ENTRY(nsIAccessible)
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAccessibleSelectable,
mSupportedIfaces & eSelectable)
@ -24,8 +22,30 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(xpcAccessibleGeneric)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAccessible)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTING_ADDREF(xpcAccessibleGeneric)
NS_IMPL_CYCLE_COLLECTING_RELEASE(xpcAccessibleGeneric)
NS_IMPL_ADDREF(xpcAccessibleGeneric)
NS_IMPL_RELEASE(xpcAccessibleGeneric)
xpcAccessibleGeneric::~xpcAccessibleGeneric()
{
if (mIntl.IsNull()) {
return;
}
xpcAccessibleDocument* xpcDoc = nullptr;
if (mIntl.IsAccessible()) {
Accessible* acc = mIntl.AsAccessible();
if (!acc->IsDoc() && !acc->IsApplication()) {
xpcDoc = GetAccService()->GetXPCDocument(acc->Document());
xpcDoc->NotifyOfShutdown(acc);
}
} else {
ProxyAccessible* proxy = mIntl.AsProxy();
if (!proxy->IsDoc()) {
xpcDoc = GetAccService()->GetXPCDocument(proxy->Document());
xpcDoc->NotifyOfShutdown(proxy);
}
}
}
////////////////////////////////////////////////////////////////////////////////
// nsIAccessible

View File

@ -41,8 +41,7 @@ public:
xpcAccessibleGeneric(ProxyAccessible* aProxy, uint8_t aInterfaces) :
mIntl(aProxy), mSupportedIfaces(aInterfaces) {}
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(xpcAccessibleGeneric, nsIAccessible)
NS_DECL_ISUPPORTS
// nsIAccessible
virtual Accessible* ToInternalAccessible() const final override;
@ -51,7 +50,7 @@ public:
virtual void Shutdown();
protected:
virtual ~xpcAccessibleGeneric() {}
virtual ~xpcAccessibleGeneric();
AccessibleOrProxy mIntl;

View File

@ -13,14 +13,8 @@ const Cr = Components.results;
const Cu = Components.utils;
const Cc = Components.classes;
const PROMPT_FOR_UNKNOWN = ["audio-capture",
"desktop-notification",
"geolocation",
"video-capture"];
// Due to privary issue, permission requests like GetUserMedia should prompt
// every time instead of providing session persistence.
const PERMISSION_NO_SESSION = ["audio-capture", "video-capture"];
const ALLOW_MULTIPLE_REQUESTS = ["audio-capture", "video-capture"];
const PROMPT_FOR_UNKNOWN = ["desktop-notification",
"geolocation"];
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
@ -113,23 +107,6 @@ ContentPermissionPrompt.prototype = {
return false;
},
// multiple requests should be audio and video
checkMultipleRequest: function checkMultipleRequest(typesInfo) {
if (typesInfo.length == 1) {
return true;
} else if (typesInfo.length > 1) {
let checkIfAllowMultiRequest = function(type) {
return (ALLOW_MULTIPLE_REQUESTS.indexOf(type.access) !== -1);
}
if (typesInfo.every(checkIfAllowMultiRequest)) {
debug("legal multiple requests");
return true;
}
}
return false;
},
handledByPermissionType: function handledByPermissionType(request, typesInfo) {
for (let i in typesInfo) {
if (permissionSpecificChecker.hasOwnProperty(typesInfo[i].permission) &&
@ -176,11 +153,6 @@ ContentPermissionPrompt.prototype = {
return;
}
if(!this.checkMultipleRequest(typesInfo)) {
request.cancel();
return;
}
if (this.handledByPermissionType(request, typesInfo)) {
return;
}
@ -258,11 +230,6 @@ ContentPermissionPrompt.prototype = {
if (remember) {
Services.perms.addFromPrincipal(request.principal, type.access,
Ci.nsIPermissionManager.DENY_ACTION);
} else if (PERMISSION_NO_SESSION.indexOf(type.access) < 0) {
Services.perms.addFromPrincipal(request.principal, type.access,
Ci.nsIPermissionManager.DENY_ACTION,
Ci.nsIPermissionManager.EXPIRE_SESSION,
0);
}
}
try {
@ -297,11 +264,7 @@ ContentPermissionPrompt.prototype = {
}
let principal = request.principal;
let isApp = principal.appStatus != Ci.nsIPrincipal.APP_STATUS_NOT_INSTALLED;
let remember = (principal.appStatus == Ci.nsIPrincipal.APP_STATUS_PRIVILEGED ||
principal.appStatus == Ci.nsIPrincipal.APP_STATUS_CERTIFIED)
? true
: request.remember;
let remember = request.remember;
let isGranted = typesInfo.every(function(type) {
return type.action == Ci.nsIPermissionManager.ALLOW_ACTION;
});
@ -319,15 +282,11 @@ ContentPermissionPrompt.prototype = {
// compare against the mozApp.origin of app windows, so we
// are not concerned with origin suffixes here (appId, etc).
origin: principal.originNoSuffix,
isApp: isApp,
isApp: false,
remember: remember,
isGranted: isGranted,
};
if (isApp) {
details.manifestURL = DOMApplicationRegistry.getManifestURLByLocalId(principal.appId);
}
// request.element is defined for OOP content, while request.window
// is defined for In-Process content.
// In both cases the message needs to be dispatched to the top-level
@ -352,18 +311,5 @@ ContentPermissionPrompt.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentPermissionPrompt])
};
(function() {
// Do not allow GetUserMedia while in call.
permissionSpecificChecker["audio-capture"] = function(request) {
let forbid = false;
if (forbid) {
request.cancel();
}
return forbid;
};
})();
//module initialization
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([ContentPermissionPrompt]);

View File

@ -25,10 +25,6 @@ function fireOrientationEvent(window) {
function hookScreen(window) {
let nodePrincipal = window.document.nodePrincipal;
let origin = nodePrincipal.origin;
if (nodePrincipal.appStatus == nodePrincipal.APP_STATUS_NOT_INSTALLED) {
// Only inject screen mock for apps
return;
}
let screen = window.wrappedJSObject.screen;

View File

@ -3,27 +3,6 @@
<script>
var actions = [
{
permissions: ["video-capture"],
action: function() {
// invoke video-capture permission prompt
navigator.mozGetUserMedia({video: true}, function () {}, function () {});
}
},
{
permissions: ["audio-capture", "video-capture"],
action: function() {
// invoke audio-capture + video-capture permission prompt
navigator.mozGetUserMedia({audio: true, video: true}, function () {}, function () {});
}
},
{
permissions: ["audio-capture"],
action: function() {
// invoke audio-capture permission prompt
navigator.mozGetUserMedia({audio: true}, function () {}, function () {});
}
},
{
permissions: ["geolocation"],
action: function() {

View File

@ -10,10 +10,6 @@ support-files =
[test_filepicker_path.html]
skip-if = toolkit != "gonk"
[test_permission_deny.html]
skip-if = toolkit != "gonk"
[test_permission_gum_remember.html]
skip-if = true # Bug 1019572 - frequent timeouts
[test_sandbox_permission.html]
skip-if = toolkit != "gonk"
[test_screenshot.html]

View File

@ -1,83 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=981113
-->
<head>
<meta charset="utf-8">
<title>Permission Deny Test</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=981113">Test Permission Deny</a>
<script type="application/javascript;version=1.8">
'use strict';
SimpleTest.waitForExplicitFinish();
const PROMPT_ACTION = SpecialPowers.Ci.nsIPermissionManager.PROMPT_ACTION;
var gUrl = SimpleTest.getTestFileURL('permission_handler_chrome.js');
var gScript = SpecialPowers.loadChromeScript(gUrl);
var gTests = [
{
'video': true,
},
{
'audio': true,
'video': true,
},
{
'audio': true,
},
];
function runNext() {
if (gTests.length > 0) {
// Put the requested permission in query string
let requestedType = gTests.shift();
info('getUserMedia for ' + JSON.stringify(requestedType));
navigator.mozGetUserMedia(requestedType, function success() {
ok(false, 'unexpected success, permission request should be denied');
runNext();
}, function failure(err) {
is(err.name, 'SecurityError', 'expected permission denied');
runNext();
});
} else {
info('test finished, teardown');
gScript.sendAsyncMessage('teardown', '');
gScript.destroy();
SimpleTest.finish();
}
}
gScript.addMessageListener('permission-request', function(detail) {
let response = {
id: detail.id,
type: 'permission-deny',
remember: false,
};
gScript.sendAsyncMessage('permission-response', response);
});
// Need to change camera permission from ALLOW to PROMPT, otherwise
// MediaManager will automatically allow video-only gUM request.
SpecialPowers.pushPermissions([
{type: 'video-capture', allow: PROMPT_ACTION, context: document},
{type: 'audio-capture', allow: PROMPT_ACTION, context: document},
{type: 'camera', allow: PROMPT_ACTION, context: document},
], function() {
SpecialPowers.pushPrefEnv({
'set': [
['media.navigator.permission.disabled', false],
]
}, runNext);
}
);
</script>
</pre>
</body>
</html>

View File

@ -1,170 +0,0 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=978660
-->
<head>
<meta charset="utf-8">
<title>gUM Remember Permission Test</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=978660">Test remembering gUM Permission</a>
<script type="application/javascript;version=1.8">
'use strict';
SimpleTest.waitForExplicitFinish();
const PROMPT_ACTION = SpecialPowers.Ci.nsIPermissionManager.PROMPT_ACTION;
var gUrl = SimpleTest.getTestFileURL('permission_handler_chrome.js');
var gScript = SpecialPowers.loadChromeScript(gUrl);
gScript.addMessageListener('permission-request', function(detail) {
ok(false, 'unexpected mozChromeEvent for permission prompt');
let response = {
id: detail.id,
type: 'permission-deny',
remember: false,
};
gScript.sendAsyncMessage('permission-response', response);
});
var gTests = [
{
'audio': true,
'video': {facingMode: 'environment', required: ['facingMode']},
},
{
'video': {facingMode: 'environment', required: ['facingMode']},
},
{
'audio': true,
},
];
function testGranted() {
info('test remember permission granted');
return new Promise(function(resolve, reject) {
let steps = [].concat(gTests);
function nextStep() {
if (steps.length > 0) {
let requestedType = steps.shift();
info('getUserMedia for ' + JSON.stringify(requestedType));
navigator.mozGetUserMedia(requestedType, function success(stream) {
ok(true, 'expected gUM success');
stream.stop();
nextStep();
}, function failure(err) {
ok(false, 'unexpected gUM fail: ' + err);
nextStep();
});
} else {
resolve();
}
}
SpecialPowers.pushPermissions([
{type: 'video-capture', allow: true, context: document},
{type: 'audio-capture', allow: true, context: document},
], nextStep);
});
}
function testDenied() {
info('test remember permission denied');
return new Promise(function(resolve, reject) {
let steps = [].concat(gTests);
function nextStep() {
if (steps.length > 0) {
let requestedType = steps.shift();
info('getUserMedia for ' + JSON.stringify(requestedType));
navigator.mozGetUserMedia(requestedType, function success(stream) {
ok(false, 'unexpected gUM success');
stream.stop();
nextStep();
}, function failure(err) {
ok(true, 'expected gUM fail: ' + err);
nextStep();
});
} else {
resolve();
}
}
SpecialPowers.pushPermissions([
{type: 'video-capture', allow: false, context: document},
{type: 'audio-capture', allow: false, context: document},
], nextStep);
});
}
function testPartialDeniedAudio() {
info('test remember permission partial denied: audio');
return new Promise(function(resolve, reject) {
info('getUserMedia for video and audio');
function nextStep() {
navigator.mozGetUserMedia({video: {facingMode: 'environment', required: ['facingMode']},
audio: true}, function success(stream) {
ok(false, 'unexpected gUM success');
stream.stop();
resolve();
}, function failure(err) {
ok(true, 'expected gUM fail: ' + err);
resolve();
});
}
SpecialPowers.pushPermissions([
{type: 'video-capture', allow: true, context: document},
{type: 'audio-capture', allow: false, context: document},
], nextStep);
});
}
function testPartialDeniedVideo() {
info('test remember permission partial denied: video');
return new Promise(function(resolve, reject) {
info('getUserMedia for video and audio');
function nextStep() {
navigator.mozGetUserMedia({video: {facingMode: 'environment', required: ['facingMode']},
audio: true}, function success(stream) {
ok(false, 'unexpected gUM success');
stream.stop();
resolve();
}, function failure(err) {
ok(true, 'expected gUM fail: ' + err);
resolve();
});
}
SpecialPowers.pushPermissions([
{type: 'video-capture', allow: false, context: document},
{type: 'audio-capture', allow: true, context: document},
], nextStep);
});
}
function runTests() {
testGranted()
.then(testDenied)
.then(testPartialDeniedAudio)
.then(testPartialDeniedVideo)
.then(function() {
info('test finished, teardown');
gScript.sendAsyncMessage('teardown', '');
gScript.destroy();
SimpleTest.finish();
});
}
SpecialPowers.pushPrefEnv({
'set': [
['media.navigator.permission.disabled', false],
]
}, runTests);
</script>
</pre>
</body>
</html>

View File

@ -21,16 +21,6 @@ var iframe;
var gUrl = SimpleTest.getTestFileURL("permission_handler_chrome.js");
var gScript = SpecialPowers.loadChromeScript(gUrl);
var gResult = [
{
"video-capture": ["back"],
},
{
"audio-capture": [""],
"video-capture": ["back"],
},
{
"audio-capture": [""],
},
{
"geolocation": [],
},
@ -86,10 +76,6 @@ gScript.addMessageListener("permission-request", function (detail) {
// should prompt for permission, not allow it without prompt.
SpecialPowers.pushPrefEnv({"set": [["media.navigator.permission.disabled", false]]},
function() {
SpecialPowers.addPermission('video-capture',
SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION, document);
SpecialPowers.addPermission('audio-capture',
SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION, document);
SpecialPowers.addPermission('geolocation',
SpecialPowers.Ci.nsIPermissionManager.ALLOW_ACTION, document);
SpecialPowers.addPermission('desktop-notification',

View File

@ -41,7 +41,6 @@ function setup_fs() {
function setup_sdcard() {
let volName = "sdcard";
let mountPoint = "/data/local/tmp/sdcard";
volumeService.createFakeVolume(volName, mountPoint);
let vol = volumeService.getVolumeByName(volName);
ok(vol, "volume shouldn't be null");

View File

@ -57,6 +57,7 @@ nsContextMenu.prototype = {
onAudio: this.onAudio,
onCanvas: this.onCanvas,
onEditableArea: this.onEditableArea,
onPassword: this.onPassword,
srcUrl: this.mediaURL,
frameUrl: gContextMenuContentData ? gContextMenuContentData.docLocation : undefined,
pageUrl: this.browser ? this.browser.currentURI.spec : undefined,

View File

@ -239,6 +239,10 @@ function getContexts(contextData) {
contexts.add("editable");
}
if (contextData.onPassword) {
contexts.add("password");
}
if (contextData.onImage) {
contexts.add("image");
}
@ -412,7 +416,7 @@ MenuItem.prototype = {
let info = {
menuItemId: this.id,
editable: contextData.onEditableArea,
editable: contextData.onEditableArea || contextData.onPassword,
};
function setIfDefined(argName, value) {

View File

@ -31,7 +31,7 @@
{
"id": "ContextType",
"type": "string",
"enum": ["all", "page", "frame", "selection", "link", "editable", "image", "video", "audio", "launcher", "browser_action", "page_action"],
"enum": ["all", "page", "frame", "selection", "link", "editable", "password", "image", "video", "audio", "launcher", "browser_action", "page_action"],
"description": "The different contexts a menu can appear in. Specifying 'all' is equivalent to the combination of all other contexts except for 'launcher'. The 'launcher' context is only supported by apps and is used to add menu items to the context menu that appears when clicking on the app icon in the launcher/taskbar/dock/etc. Different platforms might put limitations on what is actually supported in a launcher context menu."
},
{

View File

@ -72,7 +72,7 @@ add_task(function* () {
type: "separator",
});
let contexts = ["page", "selection", "image", "editable"];
let contexts = ["page", "selection", "image", "editable", "password"];
for (let i = 0; i < contexts.length; i++) {
let context = contexts[i];
let title = context;
@ -204,6 +204,21 @@ add_task(function* () {
result = yield extension.awaitMessage("browser.contextMenus.onClicked");
checkClickInfo(result);
extensionMenuRoot = yield openExtensionContextMenu("#password");
items = extensionMenuRoot.getElementsByAttribute("label", "password");
is(items.length, 1, "contextMenu item for password input element was found (context=password)");
let password = items[0];
yield closeExtensionContextMenu(password);
expectedClickInfo = {
menuItemId: "ext-password",
pageUrl: PAGE,
editable: true,
};
result = yield extension.awaitMessage("onclick");
checkClickInfo(result);
result = yield extension.awaitMessage("browser.contextMenus.onClicked");
checkClickInfo(result);
// Select some text
yield ContentTask.spawn(gBrowser.selectedBrowser, { }, function* (arg) {

View File

@ -17,7 +17,8 @@
</p>
<p>
<input type="text" id="edit-me">
<input type="text" id="edit-me"><br>
<input type="password" id="password">
</p>
</body>
</html>

View File

@ -119,12 +119,12 @@ this.CaptivePortalWatcher = {
// If the tab is gone or going, we need to open a new one.
if (!tab || tab.closing || !tab.parentNode) {
tab = win.gBrowser.addTab(this.canonicalURL);
tab = win.gBrowser.addTab(this.canonicalURL,
{ ownerTab: win.gBrowser.selectedTab });
this._captivePortalTab = Cu.getWeakReference(tab);
}
this._captivePortalTab = Cu.getWeakReference(tab);
win.gBrowser.selectedTab = tab;
return tab;
},
/**

View File

@ -102,14 +102,14 @@ nsPrincipal::GetScriptLocation(nsACString &aStr)
return mCodebase->GetSpec(aStr);
}
/* static */ nsresult
nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin)
nsresult
nsPrincipal::GetOriginInternal(nsACString& aOrigin)
{
if (!aURI) {
if (!mCodebase) {
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIURI> origin = NS_GetInnermostURI(aURI);
nsCOMPtr<nsIURI> origin = NS_GetInnermostURI(mCodebase);
if (!origin) {
return NS_ERROR_FAILURE;
}
@ -178,12 +178,6 @@ nsPrincipal::GetOriginForURI(nsIURI* aURI, nsACString& aOrigin)
return NS_OK;
}
nsresult
nsPrincipal::GetOriginInternal(nsACString& aOrigin)
{
return GetOriginForURI(mCodebase, aOrigin);
}
bool
nsPrincipal::SubsumesInternal(nsIPrincipal* aOther,
BasePrincipal::DocumentDomainConsideration aConsideration)

View File

@ -37,11 +37,6 @@ public:
virtual nsresult GetScriptLocation(nsACString& aStr) override;
void SetURI(nsIURI* aURI);
/**
* Computes the puny-encoded origin of aURI.
*/
static nsresult GetOriginForURI(nsIURI* aURI, nsACString& aOrigin);
/**
* Called at startup to setup static data, e.g. about:config pref-observers.
*/

View File

@ -115,7 +115,7 @@ const TEST_DATA = [ // eslint-disable-line
expected: [
{
type: "click",
filename: TEST_URL + ":1",
filename: TEST_URL + ":0",
attributes: [
"Bubbling",
"DOM2"
@ -129,7 +129,7 @@ const TEST_DATA = [ // eslint-disable-line
expected: [
{
type: "click",
filename: TEST_URL + ":1",
filename: TEST_URL + ":0",
attributes: [
"Bubbling",
"DOM2"

View File

@ -212,6 +212,10 @@ CssRuleView.prototype = {
* @return {Promise} Resolves to the instance of the highlighter.
*/
getSelectorHighlighter: Task.async(function* () {
if (!this.inspector) {
return null;
}
let utils = this.inspector.toolbox.highlighterUtils;
if (!utils.supportsCustomHighlighters()) {
return null;
@ -270,13 +274,13 @@ CssRuleView.prototype = {
},
highlightSelector: Task.async(function* (selector) {
let node = this.inspector.selection.nodeFront;
let highlighter = yield this.getSelectorHighlighter();
if (!highlighter) {
return;
}
let node = this.inspector.selection.nodeFront;
yield highlighter.show(node, {
hideInfoBar: true,
hideGuides: true,

View File

@ -375,7 +375,7 @@ body {
.animation-timeline .animation .name {
position: absolute;
color: var(--theme-selection-color3);
color: var(--theme-content-color3);
top: 0px;
left: 0px;
height: 100%;

View File

@ -175,7 +175,6 @@ function* testJSTerm(hud) {
"JSMSG_BAD_RADIX": "(42).toString(0);",
"JSMSG_BAD_ARRAY_LENGTH": "([]).length = -1",
"JSMSG_NEGATIVE_REPETITION_COUNT": "'abc'.repeat(-1);",
"JSMSG_BAD_FORMAL": "var f = Function('x y', 'return x + y;');",
"JSMSG_PRECISION_RANGE": "77.1234.toExponential(-1);",
};

View File

@ -18,7 +18,6 @@ const ErrorDocs = {
JSMSG_RESULTING_STRING_TOO_LARGE: "Resulting_string_too_large",
JSMSG_BAD_RADIX: "Bad_radix",
JSMSG_PRECISION_RANGE: "Precision_range",
JSMSG_BAD_FORMAL: "Malformed_formal_parameter",
JSMSG_STMT_AFTER_RETURN: "Stmt_after_return",
JSMSG_NOT_A_CODEPOINT: "Not_a_codepoint",
JSMSG_BAD_SORT_ARG: "Array_sort_argument",

View File

@ -102,16 +102,6 @@ function doPageErrors()
warning: false,
exception: true,
},
"var f = Function('x y', 'return x + y;');": {
errorMessage: /malformed formal/,
errorMessageName: "JSMSG_BAD_FORMAL",
sourceName: /test_page_errors/,
category: "chrome javascript",
timeStamp: /^\d+$/,
error: false,
warning: false,
exception: true,
},
"function a() { return; 1 + 1; }": {
errorMessage: /unreachable code/,
errorMessageName: "JSMSG_STMT_AFTER_RETURN",

View File

@ -59,7 +59,6 @@ support-files = bug530396-noref.sjs bug530396-subframe.html
[test_bug540462.html]
[test_bug551225.html]
[test_bug570341.html]
skip-if = toolkit == 'android' && debug # Bug 1040769
[test_bug580069.html]
[test_bug590573.html]
[test_bug598895.html]

View File

@ -108,9 +108,10 @@ window.onload = function() {
}, true);
frames[0].location = 'bug570341_recordevents.html'
var interval = setInterval(function () {
// time constants here are arbitrary, chosen to allow the test to pass
var stopPolling = (win.performance && win.performance.loadEventEnd) ||
(seenLoad && Date.now() >= seenLoad + 200) ||
Date.now() >= start + 5000;
(seenLoad && Date.now() >= seenLoad + 3000) ||
Date.now() >= start + 30000;
if (stopPolling) {
clearInterval(interval);
checkValues();

View File

@ -996,14 +996,12 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
}
aListener = nullptr;
uint32_t lineNo = 0;
nsAutoCString url (NS_LITERAL_CSTRING("-moz-evil:lying-event-listener"));
MOZ_ASSERT(body);
MOZ_ASSERT(aElement);
nsIURI *uri = aElement->OwnerDoc()->GetDocumentURI();
if (uri) {
uri->GetSpec(url);
lineNo = 1;
}
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryInterface(mTarget);
@ -1073,8 +1071,9 @@ EventListenerManager::CompileEventHandlerInternal(Listener* aListener,
return NS_ERROR_FAILURE;
}
JS::CompileOptions options(cx);
// Use line 0 to make the function body starts from line 1.
options.setIntroductionType("eventHandler")
.setFileAndLine(url.get(), lineNo)
.setFileAndLine(url.get(), 0)
.setVersion(JSVERSION_DEFAULT)
.setElement(&v.toObject())
.setElementAttributeName(jsStr);

View File

@ -7,4 +7,6 @@ support-files =
[test_anchor_ping.html]
skip-if = os == 'android'
[test_audio_wakelock.html]
skip-if = os == 'android' && processor == 'x86' # bug 1315749
[test_video_wakelock.html]
skip-if = os == 'android' && processor == 'x86' # bug 1315749

View File

@ -37,6 +37,7 @@
#include "mozilla/dom/PushNotifier.h"
#include "mozilla/dom/workers/ServiceWorkerManager.h"
#include "mozilla/dom/nsIContentChild.h"
#include "mozilla/dom/URLClassifierChild.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/psm/PSMContentListener.h"
#include "mozilla/hal_sandbox/PHalChild.h"
@ -2409,18 +2410,6 @@ ContentChild::RecvLastPrivateDocShellDestroyed()
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvVolumes(nsTArray<VolumeInfo>&& aVolumes)
{
#ifdef MOZ_WIDGET_GONK
RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
if (vs) {
vs->RecvVolumesFromParent(aVolumes);
}
#endif
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvFilePathUpdate(const nsString& aStorageType,
const nsString& aStorageName,
@ -2443,61 +2432,6 @@ ContentChild::RecvFilePathUpdate(const nsString& aStorageType,
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvFileSystemUpdate(const nsString& aFsName,
const nsString& aVolumeName,
const int32_t& aState,
const int32_t& aMountGeneration,
const bool& aIsMediaPresent,
const bool& aIsSharing,
const bool& aIsFormatting,
const bool& aIsFake,
const bool& aIsUnmounting,
const bool& aIsRemovable,
const bool& aIsHotSwappable)
{
#ifdef MOZ_WIDGET_GONK
RefPtr<nsVolume> volume = new nsVolume(aFsName, aVolumeName, aState,
aMountGeneration, aIsMediaPresent,
aIsSharing, aIsFormatting, aIsFake,
aIsUnmounting, aIsRemovable, aIsHotSwappable);
RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
if (vs) {
vs->UpdateVolume(volume);
}
#else
// Remove warnings about unused arguments
Unused << aFsName;
Unused << aVolumeName;
Unused << aState;
Unused << aMountGeneration;
Unused << aIsMediaPresent;
Unused << aIsSharing;
Unused << aIsFormatting;
Unused << aIsFake;
Unused << aIsUnmounting;
Unused << aIsRemovable;
Unused << aIsHotSwappable;
#endif
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvVolumeRemoved(const nsString& aFsName)
{
#ifdef MOZ_WIDGET_GONK
RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
if (vs) {
vs->RemoveVolumeByName(aFsName);
}
#else
// Remove warnings about unused arguments
Unused << aFsName;
#endif
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvNotifyProcessPriorityChanged(
const hal::ProcessPriority& aPriority)
@ -2525,16 +2459,6 @@ ContentChild::RecvMinimizeMemoryUsage()
return IPC_OK();
}
mozilla::ipc::IPCResult
ContentChild::RecvNotifyPhoneStateChange(const nsString& aState)
{
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
if (os) {
os->NotifyObservers(nullptr, "phone-state-changed", aState.get());
}
return IPC_OK();
}
void
ContentChild::AddIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS)
{
@ -3232,5 +3156,22 @@ ContentChild::FatalErrorIfNotUsingGPUProcess(const char* const aProtocolName,
}
}
PURLClassifierChild*
ContentChild::AllocPURLClassifierChild(const Principal& aPrincipal,
const bool& aUseTrackingProtection,
bool* aSuccess)
{
*aSuccess = true;
return new URLClassifierChild();
}
bool
ContentChild::DeallocPURLClassifierChild(PURLClassifierChild* aActor)
{
MOZ_ASSERT(aActor);
delete aActor;
return true;
}
} // namespace dom
} // namespace mozilla

View File

@ -30,6 +30,7 @@ class nsIObserver;
struct SubstitutionMapping;
struct OverrideMapping;
class nsIDomainPolicy;
class nsIURIClassifierCallback;
namespace mozilla {
class RemoteSpellcheckEngineChild;
@ -431,27 +432,11 @@ public:
virtual mozilla::ipc::IPCResult RecvLastPrivateDocShellDestroyed() override;
virtual mozilla::ipc::IPCResult RecvVolumes(InfallibleTArray<VolumeInfo>&& aVolumes) override;
virtual mozilla::ipc::IPCResult RecvFilePathUpdate(const nsString& aStorageType,
const nsString& aStorageName,
const nsString& aPath,
const nsCString& aReason) override;
virtual mozilla::ipc::IPCResult RecvFileSystemUpdate(const nsString& aFsName,
const nsString& aVolumeName,
const int32_t& aState,
const int32_t& aMountGeneration,
const bool& aIsMediaPresent,
const bool& aIsSharing,
const bool& aIsFormatting,
const bool& aIsFake,
const bool& aIsUnmounting,
const bool& aIsRemovable,
const bool& aIsHotSwappable) override;
virtual mozilla::ipc::IPCResult RecvVolumeRemoved(const nsString& aFsName) override;
virtual mozilla::ipc::IPCResult
RecvNotifyProcessPriorityChanged(const hal::ProcessPriority& aPriority) override;
@ -463,8 +448,6 @@ public:
virtual mozilla::ipc::IPCResult RecvUnregisterSheet(const URIParams& aURI,
const uint32_t& aType) override;
virtual mozilla::ipc::IPCResult RecvNotifyPhoneStateChange(const nsString& aState) override;
void AddIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS);
void RemoveIdleObserver(nsIObserver* aObserver, uint32_t aIdleTimeInS);
@ -631,6 +614,13 @@ public:
return mFontFamilies;
}
virtual PURLClassifierChild*
AllocPURLClassifierChild(const Principal& aPrincipal,
const bool& aUseTrackingProtection,
bool* aSuccess) override;
virtual bool
DeallocPURLClassifierChild(PURLClassifierChild* aActor) override;
/**
* Helper function for protocols that use the GPU process when available.
* Overrides FatalError to just be a warning when communicating with the

View File

@ -63,6 +63,7 @@
#include "mozilla/dom/FlyWebPublishedServerIPC.h"
#include "mozilla/dom/quota/QuotaManagerService.h"
#include "mozilla/dom/time/DateCacheCleaner.h"
#include "mozilla/dom/URLClassifierParent.h"
#include "mozilla/embedding/printingui/PrintingParent.h"
#include "mozilla/gfx/gfxVars.h"
#include "mozilla/gfx/GPUProcessManager.h"
@ -527,11 +528,6 @@ static const char* sObserverTopics[] = {
"child-mmu-request",
"last-pb-context-exited",
"file-watcher-update",
#ifdef MOZ_WIDGET_GONK
NS_VOLUME_STATE_CHANGED,
NS_VOLUME_REMOVED,
"phone-state-changed",
#endif
#ifdef ACCESSIBILITY
"a11y-init-or-shutdown",
#endif
@ -702,8 +698,6 @@ ContentParent::GetNewOrUsedBrowserProcess(bool aForBrowserElement,
p->mLargeAllocationProcess = aLargeAllocationProcess;
p->ForwardKnownInfo();
contentParents->AppendElement(p);
return p.forget();
}
@ -1138,23 +1132,6 @@ ContentParent::Init()
gmps->UpdateContentProcessGMPCapabilities();
}
void
ContentParent::ForwardKnownInfo()
{
MOZ_ASSERT(mMetamorphosed);
if (!mMetamorphosed) {
return;
}
#ifdef MOZ_WIDGET_GONK
InfallibleTArray<VolumeInfo> volumeInfo;
RefPtr<nsVolumeService> vs = nsVolumeService::GetSingleton();
if (vs) {
vs->GetVolumesForIPC(&volumeInfo);
Unused << SendVolumes(volumeInfo);
}
#endif /* MOZ_WIDGET_GONK */
}
namespace {
class RemoteWindowContext final : public nsIRemoteWindowContext
@ -1752,7 +1729,6 @@ ContentParent::InitializeMembers()
mGeolocationWatchID = -1;
mNumDestroyingTabs = 0;
mIsAlive = true;
mMetamorphosed = false;
mSendPermissionUpdates = false;
mCalledClose = false;
mCalledKillHard = false;
@ -1799,8 +1775,6 @@ ContentParent::ContentParent(ContentParent* aOpener,
{
InitializeMembers(); // Perform common initialization.
mMetamorphosed = true;
// Insert ourselves into the global linked list of ContentParent objects.
if (!sContentParents) {
sContentParents = new LinkedList<ContentParent>();
@ -2420,50 +2394,6 @@ ContentParent::Observe(nsISupports* aSubject,
DeviceStorageFile* file = static_cast<DeviceStorageFile*>(aSubject);
Unused << SendFilePathUpdate(file->mStorageType, file->mStorageName, file->mPath, creason);
}
#ifdef MOZ_WIDGET_GONK
else if(!strcmp(aTopic, NS_VOLUME_STATE_CHANGED)) {
nsCOMPtr<nsIVolume> vol = do_QueryInterface(aSubject);
if (!vol) {
return NS_ERROR_NOT_AVAILABLE;
}
nsString volName;
nsString mountPoint;
int32_t state;
int32_t mountGeneration;
bool isMediaPresent;
bool isSharing;
bool isFormatting;
bool isFake;
bool isUnmounting;
bool isRemovable;
bool isHotSwappable;
vol->GetName(volName);
vol->GetMountPoint(mountPoint);
vol->GetState(&state);
vol->GetMountGeneration(&mountGeneration);
vol->GetIsMediaPresent(&isMediaPresent);
vol->GetIsSharing(&isSharing);
vol->GetIsFormatting(&isFormatting);
vol->GetIsFake(&isFake);
vol->GetIsUnmounting(&isUnmounting);
vol->GetIsRemovable(&isRemovable);
vol->GetIsHotSwappable(&isHotSwappable);
Unused << SendFileSystemUpdate(volName, mountPoint, state,
mountGeneration, isMediaPresent,
isSharing, isFormatting, isFake,
isUnmounting, isRemovable, isHotSwappable);
} else if (!strcmp(aTopic, "phone-state-changed")) {
nsString state(aData);
Unused << SendNotifyPhoneStateChange(state);
}
else if(!strcmp(aTopic, NS_VOLUME_REMOVED)) {
nsString volName(aData);
Unused << SendVolumeRemoved(volName);
}
#endif
#ifdef ACCESSIBILITY
else if (aData && !strcmp(aTopic, "a11y-init-or-shutdown")) {
if (*aData == '1') {
@ -3709,55 +3639,6 @@ ContentParent::SendPBrowserConstructor(PBrowserParent* aActor,
aIsForBrowser);
}
mozilla::ipc::IPCResult
ContentParent::RecvCreateFakeVolume(const nsString& fsName,
const nsString& mountPoint)
{
#ifdef MOZ_WIDGET_GONK
nsresult rv;
nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
if (vs) {
vs->CreateFakeVolume(fsName, mountPoint);
}
return IPC_OK();
#else
NS_WARNING("ContentParent::RecvCreateFakeVolume shouldn't be called when MOZ_WIDGET_GONK is not defined");
return IPC_FAIL_NO_REASON(this);
#endif
}
mozilla::ipc::IPCResult
ContentParent::RecvSetFakeVolumeState(const nsString& fsName, const int32_t& fsState)
{
#ifdef MOZ_WIDGET_GONK
nsresult rv;
nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
if (vs) {
vs->SetFakeVolumeState(fsName, fsState);
}
return IPC_OK();
#else
NS_WARNING("ContentParent::RecvSetFakeVolumeState shouldn't be called when MOZ_WIDGET_GONK is not defined");
return IPC_FAIL_NO_REASON(this);
#endif
}
mozilla::ipc::IPCResult
ContentParent::RecvRemoveFakeVolume(const nsString& fsName)
{
#ifdef MOZ_WIDGET_GONK
nsresult rv;
nsCOMPtr<nsIVolumeService> vs = do_GetService(NS_VOLUMESERVICE_CONTRACTID, &rv);
if (vs) {
vs->RemoveFakeVolume(fsName);
}
return IPC_OK();
#else
NS_WARNING("ContentParent::RecvRemoveFakeVolume shouldn't be called when MOZ_WIDGET_GONK is not defined");
return IPC_FAIL_NO_REASON(this);
#endif
}
mozilla::ipc::IPCResult
ContentParent::RecvKeywordToURI(const nsCString& aKeyword,
nsString* aProviderName,
@ -4818,3 +4699,64 @@ ContentParent::RecvAccumulateChildKeyedHistogram(
Telemetry::AccumulateChildKeyed(GeckoProcessType_Content, aAccumulations);
return IPC_OK();
}
PURLClassifierParent*
ContentParent::AllocPURLClassifierParent(const Principal& aPrincipal,
const bool& aUseTrackingProtection,
bool* aSuccess)
{
MOZ_ASSERT(NS_IsMainThread());
*aSuccess = true;
RefPtr<URLClassifierParent> actor = new URLClassifierParent();
return actor.forget().take();
}
mozilla::ipc::IPCResult
ContentParent::RecvPURLClassifierConstructor(PURLClassifierParent* aActor,
const Principal& aPrincipal,
const bool& aUseTrackingProtection,
bool* aSuccess)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aActor);
auto* actor = static_cast<URLClassifierParent*>(aActor);
nsCOMPtr<nsIPrincipal> principal(aPrincipal);
if (!principal) {
return IPC_FAIL_NO_REASON(this);
}
return actor->StartClassify(principal, aUseTrackingProtection, aSuccess);
}
bool
ContentParent::DeallocPURLClassifierParent(PURLClassifierParent* aActor)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(aActor);
RefPtr<URLClassifierParent> actor =
dont_AddRef(static_cast<URLClassifierParent*>(aActor));
return true;
}
mozilla::ipc::IPCResult
ContentParent::RecvClassifyLocal(const URIParams& aURI, const nsCString& aTables,
nsCString* aResults)
{
MOZ_ASSERT(aResults);
nsCOMPtr<nsIURI> uri = DeserializeURI(aURI);
if (!uri) {
return IPC_FAIL_NO_REASON(this);
}
nsCOMPtr<nsIURIClassifier> uriClassifier =
do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID);
if (!uriClassifier) {
return IPC_FAIL_NO_REASON(this);
}
nsresult rv = uriClassifier->ClassifyLocalWithTables(uri, aTables, *aResults);
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL(this, "ClassifyLocalWithTables error");
}
return IPC_OK();
}

View File

@ -522,6 +522,23 @@ public:
virtual int32_t Pid() const override;
virtual PURLClassifierParent*
AllocPURLClassifierParent(const Principal& aPrincipal,
const bool& aUseTrackingProtection,
bool* aSuccess) override;
virtual mozilla::ipc::IPCResult
RecvPURLClassifierConstructor(PURLClassifierParent* aActor,
const Principal& aPrincipal,
const bool& aUseTrackingProtection,
bool* aSuccess) override;
virtual bool
DeallocPURLClassifierParent(PURLClassifierParent* aActor) override;
virtual mozilla::ipc::IPCResult
RecvClassifyLocal(const URIParams& aURI,
const nsCString& aTables,
nsCString* aResults) override;
// Use the PHangMonitor channel to ask the child to repaint a tab.
void ForceTabPaint(TabParent* aTabParent, uint64_t aLayerObserverEpoch);
@ -913,14 +930,6 @@ private:
virtual mozilla::ipc::IPCResult RecvGetLookAndFeelCache(nsTArray<LookAndFeelInt>* aLookAndFeelIntCache) override;
virtual mozilla::ipc::IPCResult RecvCreateFakeVolume(const nsString& aFsName,
const nsString& aMountPoint) override;
virtual mozilla::ipc::IPCResult RecvSetFakeVolumeState(const nsString& aFsName,
const int32_t& aFsState) override;
virtual mozilla::ipc::IPCResult RecvRemoveFakeVolume(const nsString& fsName) override;
virtual mozilla::ipc::IPCResult RecvKeywordToURI(const nsCString& aKeyword,
nsString* aProviderName,
OptionalInputStreamParams* aPostData,
@ -1065,10 +1074,6 @@ private:
// through.
bool mIsAlive;
// True only the if process is already a browser or has
// been transformed into one.
bool mMetamorphosed;
bool mSendPermissionUpdates;
bool mIsForBrowser;

View File

@ -46,6 +46,7 @@ include protocol PRemoteSpellcheckEngine;
include protocol PWebBrowserPersistDocument;
include protocol PWebrtcGlobal;
include protocol PPresentation;
include protocol PURLClassifier;
include protocol PVRManager;
include protocol PVideoDecoderManager;
include protocol PFlyWebPublishedServer;
@ -264,22 +265,6 @@ struct DataStorageItem {
DataStorageType type;
};
// Note: Any changes to this structure should also be changed in
// FileSystemUpdate below.
struct VolumeInfo {
nsString name;
nsString mountPoint;
int32_t volState;
int32_t mountGeneration;
bool isMediaPresent;
bool isSharing;
bool isFormatting;
bool isFake;
bool isUnmounting;
bool isRemovable;
bool isHotSwappable;
};
struct ClipboardCapabilities {
bool supportsSelectionClipboard;
bool supportsFindClipboard;
@ -394,6 +379,7 @@ nested(upto inside_cpow) sync protocol PContent
manages PWebrtcGlobal;
manages PPresentation;
manages PFlyWebPublishedServer;
manages PURLClassifier;
both:
// Depending on exactly how the new browser is being created, it might be
@ -508,8 +494,6 @@ child:
// nsIPermissionManager messages
async AddPermission(Permission permission);
async Volumes(VolumeInfo[] volumes);
async FlushMemory(nsString reason);
async GarbageCollect();
@ -547,16 +531,6 @@ child:
async FilePathUpdate(nsString storageType, nsString storageName, nsString filepath,
nsCString reasons);
// Note: Any changes to this structure should also be changed in
// VolumeInfo above.
async FileSystemUpdate(nsString fsName, nsString mountPoint, int32_t fsState,
int32_t mountGeneration, bool isMediaPresent,
bool isSharing, bool isFormatting, bool isFake,
bool isUnmounting, bool isRemovable, bool isHotSwappable);
// Notify volume is removed.
async VolumeRemoved(nsString fsName);
async NotifyProcessPriorityChanged(ProcessPriority priority);
async MinimizeMemoryUsage();
@ -566,8 +540,6 @@ child:
async LoadAndRegisterSheet(URIParams uri, uint32_t type);
async UnregisterSheet(URIParams uri, uint32_t type);
async NotifyPhoneStateChange(nsString newState);
/**
* Notify idle observers in the child
*/
@ -826,6 +798,11 @@ parent:
async PFlyWebPublishedServer(nsString name, FlyWebPublishOptions params);
sync PURLClassifier(Principal principal, bool useTrackingProtection)
returns (bool success);
sync ClassifyLocal(URIParams uri, nsCString tables)
returns (nsCString results);
// Services remoting
async StartVisitedQuery(URIParams uri);
@ -927,11 +904,6 @@ parent:
nsString aFilepath,
nsCString aReason);
// called by the child (test code only) to propagate volume changes to the parent
async CreateFakeVolume(nsString fsName, nsString mountPoint);
async SetFakeVolumeState(nsString fsName, int32_t fsState);
async RemoveFakeVolume(nsString fsName);
sync KeywordToURI(nsCString keyword)
returns (nsString providerName, OptionalInputStreamParams postData, OptionalURIParams uri);

View File

@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: sw=2 ts=8 et :
*/
/* 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/. */
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
include protocol PContent;
namespace mozilla {
namespace dom {
union MaybeResult {
nsresult;
void_t;
};
protocol PURLClassifier
{
manager PContent;
child:
async __delete__(MaybeResult status);
};
} // namespace dom
} // namespace mozilla

View File

@ -0,0 +1,20 @@
/* -*- 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 "URLClassifierChild.h"
#include "nsComponentManagerUtils.h"
using namespace mozilla::dom;
mozilla::ipc::IPCResult
URLClassifierChild::Recv__delete__(const MaybeResult& aResult)
{
MOZ_ASSERT(mCallback);
if (aResult.type() == MaybeResult::Tnsresult) {
mCallback->OnClassifyComplete(aResult.get_nsresult());
}
return IPC_OK();
}

View File

@ -0,0 +1,36 @@
/* -*- 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_URLClassifierChild_h
#define mozilla_dom_URLClassifierChild_h
#include "mozilla/dom/PURLClassifierChild.h"
#include "nsIURIClassifier.h"
namespace mozilla {
namespace dom {
class URLClassifierChild : public PURLClassifierChild
{
public:
URLClassifierChild() = default;
void SetCallback(nsIURIClassifierCallback* aCallback)
{
mCallback = aCallback;
}
mozilla::ipc::IPCResult Recv__delete__(const MaybeResult& aResult) override;
private:
~URLClassifierChild() = default;
nsCOMPtr<nsIURIClassifierCallback> mCallback;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_URLClassifierChild_h

View File

@ -0,0 +1,50 @@
/* -*- 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 "URLClassifierParent.h"
#include "nsComponentManagerUtils.h"
#include "mozilla/Unused.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_ISUPPORTS(URLClassifierParent, nsIURIClassifierCallback)
mozilla::ipc::IPCResult
URLClassifierParent::StartClassify(nsIPrincipal* aPrincipal,
bool aUseTrackingProtection,
bool* aSuccess)
{
nsCOMPtr<nsIURIClassifier> uriClassifier =
do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID);
if (!uriClassifier) {
return IPC_FAIL_NO_REASON(this);
}
nsresult rv = uriClassifier->Classify(aPrincipal, aUseTrackingProtection,
this, aSuccess);
if (NS_FAILED(rv) || !*aSuccess) {
// We treat the case where we fail to classify and the case where the
// classifier returns successfully but doesn't perform a lookup as the
// classification not yielding any results, so we just kill the child actor
// without ever calling out callback in both cases.
// This means that code using this in the child process will only get a hit
// on its callback if some classification actually happens.
Unused << Send__delete__(this, void_t());
}
return IPC_OK();
}
nsresult
URLClassifierParent::OnClassifyComplete(nsresult aRv)
{
Unused << Send__delete__(this, aRv);
return NS_OK;
}
void
URLClassifierParent::ActorDestroy(ActorDestroyReason aWhy)
{
}

View File

@ -0,0 +1,37 @@
/* -*- 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_URLClassifierParent_h
#define mozilla_dom_URLClassifierParent_h
#include "mozilla/dom/PURLClassifierParent.h"
#include "nsIURIClassifier.h"
namespace mozilla {
namespace dom {
class URLClassifierParent : public nsIURIClassifierCallback,
public PURLClassifierParent
{
public:
URLClassifierParent() = default;
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIURICLASSIFIERCALLBACK
mozilla::ipc::IPCResult StartClassify(nsIPrincipal* aPrincipal,
bool aUseTrackingProtection,
bool* aSuccess);
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
~URLClassifierParent() = default;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_URLClassifierParent_h

View File

@ -36,6 +36,8 @@ EXPORTS.mozilla.dom += [
'TabContext.h',
'TabMessageUtils.h',
'TabParent.h',
'URLClassifierChild.h',
'URLClassifierParent.h',
]
EXPORTS.mozilla += [
@ -64,6 +66,8 @@ UNIFIED_SOURCES += [
'TabContext.cpp',
'TabMessageUtils.cpp',
'TabParent.cpp',
'URLClassifierChild.cpp',
'URLClassifierParent.cpp',
]
# Blob.cpp cannot be compiled in unified mode because it triggers a fatal gcc warning.
@ -99,6 +103,7 @@ IPDL_SOURCES += [
'PProcessHangMonitor.ipdl',
'PScreenManager.ipdl',
'PTabContext.ipdlh',
'PURLClassifier.ipdl',
'ServiceWorkerConfiguration.ipdlh',
]

View File

@ -63,18 +63,18 @@ public:
using Promise = MozPromise<RefPtr<Token>, bool, true>;
// Acquire a token for decoder creation. Thread-safe.
auto Alloc(TrackType aTrack) -> RefPtr<Promise>;
auto Alloc() -> RefPtr<Promise>;
// Called by ClearOnShutdown() to delete the singleton.
void operator=(decltype(nullptr));
// Get the singleton. Thread-safe.
static DecoderAllocPolicy& Instance();
// Get the singleton for the given track type. Thread-safe.
static DecoderAllocPolicy& Instance(TrackType aTrack);
private:
class AutoDeallocToken;
using PromisePrivate = Promise::Private;
DecoderAllocPolicy();
explicit DecoderAllocPolicy(TrackType aTrack);
~DecoderAllocPolicy();
// Called by the destructor of TokenImpl to restore the decoder limit.
void Dealloc();
@ -87,6 +87,8 @@ private:
ReentrantMonitor mMonitor;
// The number of decoders available for creation.
int mDecoderLimit;
// Track type.
const TrackType mTrack;
// Requests to acquire tokens.
std::queue<RefPtr<PromisePrivate>> mPromises;
};
@ -95,13 +97,24 @@ StaticMutex DecoderAllocPolicy::sMutex;
class DecoderAllocPolicy::AutoDeallocToken : public Token
{
public:
explicit AutoDeallocToken(TrackType aTrack)
: mTrack(aTrack)
{}
private:
~AutoDeallocToken() { DecoderAllocPolicy::Instance().Dealloc(); }
~AutoDeallocToken()
{
DecoderAllocPolicy::Instance(mTrack).Dealloc();
}
const TrackType mTrack;
};
DecoderAllocPolicy::DecoderAllocPolicy()
DecoderAllocPolicy::DecoderAllocPolicy(TrackType aTrack)
: mMonitor("DecoderAllocPolicy::mMonitor")
, mDecoderLimit(MediaPrefs::MediaDecoderLimit())
, mTrack(aTrack)
{
AbstractThread::MainThread()->Dispatch(NS_NewRunnableFunction([this] () {
ClearOnShutdown(this, ShutdownPhase::ShutdownThreads);
@ -118,18 +131,23 @@ DecoderAllocPolicy::~DecoderAllocPolicy()
}
DecoderAllocPolicy&
DecoderAllocPolicy::Instance()
DecoderAllocPolicy::Instance(TrackType aTrack)
{
StaticMutexAutoLock lock(sMutex);
static auto sPolicy = new DecoderAllocPolicy();
return *sPolicy;
if (aTrack == TrackType::kAudioTrack) {
static auto sAudioPolicy = new DecoderAllocPolicy(TrackType::kAudioTrack);
return *sAudioPolicy;
} else {
static auto sVideoPolicy = new DecoderAllocPolicy(TrackType::kVideoTrack);
return *sVideoPolicy;
}
}
auto
DecoderAllocPolicy::Alloc(TrackType aTrack) -> RefPtr<Promise>
DecoderAllocPolicy::Alloc() -> RefPtr<Promise>
{
// No limit for audio decoders or a negative number.
if (aTrack == TrackInfo::kAudioTrack || mDecoderLimit < 0) {
// No decoder limit set.
if (mDecoderLimit < 0) {
return Promise::CreateAndResolve(new Token(), __func__);
}
@ -157,7 +175,7 @@ DecoderAllocPolicy::ResolvePromise(ReentrantMonitorAutoEnter& aProofOfLock)
--mDecoderLimit;
RefPtr<PromisePrivate> p = mPromises.front().forget();
mPromises.pop();
p->Resolve(new AutoDeallocToken(), __func__);
p->Resolve(new AutoDeallocToken(mTrack), __func__);
}
}
@ -266,7 +284,7 @@ MediaFormatReader::DecoderFactory::RunStage(TrackType aTrack)
switch (data.mStage) {
case Stage::None: {
MOZ_ASSERT(!data.mToken);
data.mTokenPromise.Begin(DecoderAllocPolicy::Instance().Alloc(aTrack)->Then(
data.mTokenPromise.Begin(DecoderAllocPolicy::Instance(aTrack).Alloc()->Then(
mOwner->OwnerThread(), __func__,
[this, &data, aTrack] (Token* aToken) {
data.mTokenPromise.Complete();

View File

@ -2079,8 +2079,14 @@ if (privileged) {
(uint32_t) GetUserMediaSecurityState::Other);
}
nsCString origin;
rv = nsPrincipal::GetOriginForURI(docURI, origin);
nsCOMPtr<nsIPrincipal> principal =
nsGlobalWindow::Cast(aWindow)->GetPrincipal();
if (NS_WARN_IF(!principal)) {
return NS_ERROR_FAILURE;
}
nsAutoCString origin;
rv = principal->GetOrigin(origin);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
@ -2236,7 +2242,6 @@ if (privileged) {
StreamListeners* listeners = AddWindowID(windowID);
// Create a disabled listener to act as a placeholder
nsIPrincipal* principal = aWindow->GetExtantDoc()->NodePrincipal();
RefPtr<GetUserMediaCallbackMediaStreamListener> listener =
new GetUserMediaCallbackMediaStreamListener(mMediaThread, windowID,
MakePrincipalHandle(principal));
@ -2492,8 +2497,12 @@ MediaManager::EnumerateDevicesImpl(uint64_t aWindowId,
// 3. Anonymize the raw list with the origin-key.
bool privateBrowsing = IsPrivateBrowsing(window);
nsCString origin;
nsPrincipal::GetOriginForURI(window->GetDocumentURI(), origin);
nsCOMPtr<nsIPrincipal> principal =
nsGlobalWindow::Cast(window)->GetPrincipal();
MOZ_ASSERT(principal);
nsAutoCString origin;
principal->GetOrigin(origin);
bool persist = IsActivelyCapturingOrHasAPermission(aWindowId);

View File

@ -1,522 +0,0 @@
/* 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 "MediaManager.h"
#include "MediaPermissionGonk.h"
#include "nsArray.h"
#include "nsCOMPtr.h"
#include "nsIContentPermissionPrompt.h"
#include "nsIDocument.h"
#include "nsIDOMNavigatorUserMedia.h"
#include "nsIStringEnumerator.h"
#include "nsJSUtils.h"
#include "nsQueryObject.h"
#include "nsPIDOMWindow.h"
#include "nsTArray.h"
#include "GetUserMediaRequest.h"
#include "mozilla/dom/PBrowserChild.h"
#include "mozilla/dom/MediaStreamTrackBinding.h"
#include "mozilla/dom/MediaStreamError.h"
#include "nsISupportsPrimitives.h"
#include "nsServiceManagerUtils.h"
#include "nsArrayUtils.h"
#include "nsContentPermissionHelper.h"
#include "mozilla/dom/PermissionMessageUtils.h"
#define AUDIO_PERMISSION_NAME "audio-capture"
#define VIDEO_PERMISSION_NAME "video-capture"
using namespace mozilla::dom;
namespace mozilla {
static MediaPermissionManager *gMediaPermMgr = nullptr;
static void
CreateDeviceNameList(nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices,
nsTArray<nsString> &aDeviceNameList)
{
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
nsString name;
nsresult rv = aDevices[i]->GetName(name);
NS_ENSURE_SUCCESS_VOID(rv);
aDeviceNameList.AppendElement(name);
}
}
static already_AddRefed<nsIMediaDevice>
FindDeviceByName(nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices,
const nsAString &aDeviceName)
{
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
nsCOMPtr<nsIMediaDevice> device = aDevices[i];
nsString deviceName;
device->GetName(deviceName);
if (deviceName.Equals(aDeviceName)) {
return device.forget();
}
}
return nullptr;
}
// Helper function for notifying permission granted
static nsresult
NotifyPermissionAllow(const nsAString &aCallID, nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices)
{
nsresult rv;
nsCOMPtr<nsIMutableArray> array = nsArray::Create();
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
rv = array->AppendElement(aDevices.ElementAt(i), /*weak =*/ false);
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
return obs->NotifyObservers(array, "getUserMedia:response:allow",
aCallID.BeginReading());
}
// Helper function for notifying permision denial or error
static nsresult
NotifyPermissionDeny(const nsAString &aCallID, const nsAString &aErrorMsg)
{
nsresult rv;
nsCOMPtr<nsISupportsString> supportsString =
do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
rv = supportsString->SetData(aErrorMsg);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
NS_ENSURE_TRUE(obs, NS_ERROR_FAILURE);
return obs->NotifyObservers(supportsString, "getUserMedia:response:deny",
aCallID.BeginReading());
}
namespace {
/**
* MediaPermissionRequest will send a prompt ipdl request to b2g process according
* to its owned type.
*/
class MediaPermissionRequest : public nsIContentPermissionRequest
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSICONTENTPERMISSIONREQUEST
MediaPermissionRequest(RefPtr<dom::GetUserMediaRequest> &aRequest,
nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices);
already_AddRefed<nsPIDOMWindowInner> GetOwner();
protected:
virtual ~MediaPermissionRequest() {}
private:
nsresult DoAllow(const nsString &audioDevice, const nsString &videoDevice);
bool mAudio; // Request for audio permission
bool mVideo; // Request for video permission
RefPtr<dom::GetUserMediaRequest> mRequest;
nsTArray<nsCOMPtr<nsIMediaDevice> > mAudioDevices; // candidate audio devices
nsTArray<nsCOMPtr<nsIMediaDevice> > mVideoDevices; // candidate video devices
nsCOMPtr<nsIContentPermissionRequester> mRequester;
};
// MediaPermissionRequest
NS_IMPL_ISUPPORTS(MediaPermissionRequest, nsIContentPermissionRequest)
MediaPermissionRequest::MediaPermissionRequest(RefPtr<dom::GetUserMediaRequest> &aRequest,
nsTArray<nsCOMPtr<nsIMediaDevice> > &aDevices)
: mRequest(aRequest)
{
dom::MediaStreamConstraints constraints;
mRequest->GetConstraints(constraints);
mAudio = !constraints.mAudio.IsBoolean() || constraints.mAudio.GetAsBoolean();
mVideo = !constraints.mVideo.IsBoolean() || constraints.mVideo.GetAsBoolean();
for (uint32_t i = 0; i < aDevices.Length(); ++i) {
nsCOMPtr<nsIMediaDevice> device(aDevices[i]);
nsAutoString deviceType;
device->GetType(deviceType);
if (mAudio && deviceType.EqualsLiteral("audio")) {
mAudioDevices.AppendElement(device);
}
if (mVideo && deviceType.EqualsLiteral("video")) {
mVideoDevices.AppendElement(device);
}
}
nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
mRequester = new nsContentPermissionRequester(window);
}
// nsIContentPermissionRequest methods
NS_IMETHODIMP
MediaPermissionRequest::GetTypes(nsIArray** aTypes)
{
nsCOMPtr<nsIMutableArray> types = do_CreateInstance(NS_ARRAY_CONTRACTID);
//XXX append device list
if (mAudio) {
nsTArray<nsString> audioDeviceNames;
CreateDeviceNameList(mAudioDevices, audioDeviceNames);
nsCOMPtr<nsISupports> AudioType =
new ContentPermissionType(NS_LITERAL_CSTRING(AUDIO_PERMISSION_NAME),
NS_LITERAL_CSTRING("unused"),
audioDeviceNames);
types->AppendElement(AudioType, false);
}
if (mVideo) {
nsTArray<nsString> videoDeviceNames;
CreateDeviceNameList(mVideoDevices, videoDeviceNames);
nsCOMPtr<nsISupports> VideoType =
new ContentPermissionType(NS_LITERAL_CSTRING(VIDEO_PERMISSION_NAME),
NS_LITERAL_CSTRING("unused"),
videoDeviceNames);
types->AppendElement(VideoType, false);
}
NS_IF_ADDREF(*aTypes = types);
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::GetPrincipal(nsIPrincipal **aRequestingPrincipal)
{
NS_ENSURE_ARG_POINTER(aRequestingPrincipal);
nsCOMPtr<nsPIDOMWindowInner> window =
nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())->AsInner();
NS_ENSURE_TRUE(window, NS_ERROR_FAILURE);
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
NS_ADDREF(*aRequestingPrincipal = doc->NodePrincipal());
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::GetWindow(mozIDOMWindow** aRequestingWindow)
{
NS_ENSURE_ARG_POINTER(aRequestingWindow);
nsCOMPtr<nsPIDOMWindowInner> window =
nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())->AsInner();
window.forget(aRequestingWindow);
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::GetElement(nsIDOMElement** aRequestingElement)
{
NS_ENSURE_ARG_POINTER(aRequestingElement);
*aRequestingElement = nullptr;
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::Cancel()
{
nsString callID;
mRequest->GetCallID(callID);
NotifyPermissionDeny(callID, NS_LITERAL_STRING("SecurityError"));
return NS_OK;
}
NS_IMETHODIMP
MediaPermissionRequest::Allow(JS::HandleValue aChoices)
{
// check if JS object
if (!aChoices.isObject()) {
MOZ_ASSERT(false, "Not a correct format of PermissionChoice");
return NS_ERROR_INVALID_ARG;
}
// iterate through audio-capture and video-capture
AutoJSAPI jsapi;
if (!jsapi.Init(&aChoices.toObject())) {
return NS_ERROR_UNEXPECTED;
}
JSContext* cx = jsapi.cx();
JS::Rooted<JSObject*> obj(cx, &aChoices.toObject());
JS::Rooted<JS::Value> v(cx);
// get selected audio device name
nsString audioDevice;
if (mAudio) {
if (!JS_GetProperty(cx, obj, AUDIO_PERMISSION_NAME, &v) || !v.isString()) {
return NS_ERROR_FAILURE;
}
nsAutoJSString deviceName;
if (!deviceName.init(cx, v)) {
MOZ_ASSERT(false, "Couldn't initialize string from aChoices");
return NS_ERROR_FAILURE;
}
audioDevice = deviceName;
}
// get selected video device name
nsString videoDevice;
if (mVideo) {
if (!JS_GetProperty(cx, obj, VIDEO_PERMISSION_NAME, &v) || !v.isString()) {
return NS_ERROR_FAILURE;
}
nsAutoJSString deviceName;
if (!deviceName.init(cx, v)) {
MOZ_ASSERT(false, "Couldn't initialize string from aChoices");
return NS_ERROR_FAILURE;
}
videoDevice = deviceName;
}
return DoAllow(audioDevice, videoDevice);
}
NS_IMETHODIMP
MediaPermissionRequest::GetRequester(nsIContentPermissionRequester** aRequester)
{
NS_ENSURE_ARG_POINTER(aRequester);
nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
requester.forget(aRequester);
return NS_OK;
}
nsresult
MediaPermissionRequest::DoAllow(const nsString &audioDevice,
const nsString &videoDevice)
{
nsTArray<nsCOMPtr<nsIMediaDevice> > selectedDevices;
if (mAudio) {
nsCOMPtr<nsIMediaDevice> device =
FindDeviceByName(mAudioDevices, audioDevice);
if (device) {
selectedDevices.AppendElement(device);
}
}
if (mVideo) {
nsCOMPtr<nsIMediaDevice> device =
FindDeviceByName(mVideoDevices, videoDevice);
if (device) {
selectedDevices.AppendElement(device);
}
}
nsString callID;
mRequest->GetCallID(callID);
return NotifyPermissionAllow(callID, selectedDevices);
}
already_AddRefed<nsPIDOMWindowInner>
MediaPermissionRequest::GetOwner()
{
nsCOMPtr<nsPIDOMWindowInner> window =
nsGlobalWindow::GetInnerWindowWithId(mRequest->InnerWindowID())->AsInner();
return window.forget();
}
// Success callback for MediaManager::GetUserMediaDevices().
class MediaDeviceSuccessCallback: public nsIGetUserMediaDevicesSuccessCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIGETUSERMEDIADEVICESSUCCESSCALLBACK
explicit MediaDeviceSuccessCallback(RefPtr<dom::GetUserMediaRequest> &aRequest)
: mRequest(aRequest) {}
protected:
virtual ~MediaDeviceSuccessCallback() {}
private:
nsresult DoPrompt(RefPtr<MediaPermissionRequest> &req);
RefPtr<dom::GetUserMediaRequest> mRequest;
};
NS_IMPL_ISUPPORTS(MediaDeviceSuccessCallback, nsIGetUserMediaDevicesSuccessCallback)
// nsIGetUserMediaDevicesSuccessCallback method
NS_IMETHODIMP
MediaDeviceSuccessCallback::OnSuccess(nsIVariant* aDevices)
{
nsIID elementIID;
uint16_t elementType;
void* rawArray;
uint32_t arrayLen;
nsresult rv;
rv = aDevices->GetAsArray(&elementType, &elementIID, &arrayLen, &rawArray);
NS_ENSURE_SUCCESS(rv, rv);
if (elementType != nsIDataType::VTYPE_INTERFACE) {
free(rawArray);
return NS_ERROR_FAILURE;
}
// Create array for nsIMediaDevice
nsTArray<nsCOMPtr<nsIMediaDevice> > devices;
nsISupports **supportsArray = reinterpret_cast<nsISupports **>(rawArray);
for (uint32_t i = 0; i < arrayLen; ++i) {
nsCOMPtr<nsIMediaDevice> device(do_QueryInterface(supportsArray[i]));
devices.AppendElement(device);
NS_IF_RELEASE(supportsArray[i]); // explicitly decrease reference count for raw pointer
}
free(rawArray); // explicitly free for the memory from nsIVariant::GetAsArray
// Send MediaPermissionRequest
RefPtr<MediaPermissionRequest> req = new MediaPermissionRequest(mRequest, devices);
rv = DoPrompt(req);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
// Trigger permission prompt UI
nsresult
MediaDeviceSuccessCallback::DoPrompt(RefPtr<MediaPermissionRequest> &req)
{
nsCOMPtr<nsPIDOMWindowInner> window(req->GetOwner());
return dom::nsContentPermissionUtils::AskPermission(req, window);
}
// Error callback for MediaManager::GetUserMediaDevices()
class MediaDeviceErrorCallback: public nsIDOMGetUserMediaErrorCallback
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIDOMGETUSERMEDIAERRORCALLBACK
explicit MediaDeviceErrorCallback(const nsAString &aCallID)
: mCallID(aCallID) {}
protected:
virtual ~MediaDeviceErrorCallback() {}
private:
const nsString mCallID;
};
NS_IMPL_ISUPPORTS(MediaDeviceErrorCallback, nsIDOMGetUserMediaErrorCallback)
// nsIDOMGetUserMediaErrorCallback method
NS_IMETHODIMP
MediaDeviceErrorCallback::OnError(nsISupports* aError)
{
RefPtr<MediaStreamError> error = do_QueryObject(aError);
if (!error) {
return NS_ERROR_NO_INTERFACE;
}
nsString name;
error->GetName(name);
return NotifyPermissionDeny(mCallID, name);
}
} // namespace anonymous
// MediaPermissionManager
NS_IMPL_ISUPPORTS(MediaPermissionManager, nsIObserver)
MediaPermissionManager*
MediaPermissionManager::GetInstance()
{
if (!gMediaPermMgr) {
gMediaPermMgr = new MediaPermissionManager();
}
return gMediaPermMgr;
}
MediaPermissionManager::MediaPermissionManager()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->AddObserver(this, "getUserMedia:request", false);
obs->AddObserver(this, "xpcom-shutdown", false);
}
}
MediaPermissionManager::~MediaPermissionManager()
{
this->Deinit();
}
nsresult
MediaPermissionManager::Deinit()
{
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->RemoveObserver(this, "getUserMedia:request");
obs->RemoveObserver(this, "xpcom-shutdown");
}
return NS_OK;
}
// nsIObserver method
NS_IMETHODIMP
MediaPermissionManager::Observe(nsISupports* aSubject, const char* aTopic,
const char16_t* aData)
{
nsresult rv;
if (!strcmp(aTopic, "getUserMedia:request")) {
RefPtr<dom::GetUserMediaRequest> req =
static_cast<dom::GetUserMediaRequest*>(aSubject);
rv = HandleRequest(req);
if (NS_FAILED(rv)) {
nsString callID;
req->GetCallID(callID);
NotifyPermissionDeny(callID, NS_LITERAL_STRING("unable to enumerate media device"));
}
} else if (!strcmp(aTopic, "xpcom-shutdown")) {
rv = this->Deinit();
} else {
// not reachable
rv = NS_ERROR_FAILURE;
}
return rv;
}
// Handle GetUserMediaRequest, query available media device first.
nsresult
MediaPermissionManager::HandleRequest(RefPtr<dom::GetUserMediaRequest> &req)
{
nsString callID;
req->GetCallID(callID);
uint64_t innerWindowID = req->InnerWindowID();
nsCOMPtr<nsPIDOMWindowInner> innerWindow =
nsGlobalWindow::GetInnerWindowWithId(innerWindowID)->AsInner();
if (!innerWindow) {
MOZ_ASSERT(false, "No inner window");
return NS_ERROR_FAILURE;
}
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> onSuccess =
new MediaDeviceSuccessCallback(req);
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> onError =
new MediaDeviceErrorCallback(callID);
dom::MediaStreamConstraints constraints;
req->GetConstraints(constraints);
RefPtr<MediaManager> MediaMgr = MediaManager::GetInstance();
nsresult rv = MediaMgr->GetUserMediaDevices(innerWindow, constraints,
onSuccess, onError,
innerWindowID, callID);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
} // namespace mozilla

View File

@ -1,39 +0,0 @@
/* 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 DOM_MEDIA_MEDIAPERMISSIONGONK_H
#define DOM_MEDIA_MEDIAPERMISSIONGONK_H
#include "nsError.h"
#include "nsIObserver.h"
#include "nsISupportsImpl.h"
#include "GetUserMediaRequest.h"
namespace mozilla {
/**
* The observer to create the MediaPermissionMgr. This is the entry point of
* permission request on b2g.
*/
class MediaPermissionManager : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
NS_DECL_NSIOBSERVER
static MediaPermissionManager* GetInstance();
protected:
virtual ~MediaPermissionManager();
private:
MediaPermissionManager();
nsresult Deinit();
nsresult HandleRequest(RefPtr<dom::GetUserMediaRequest> &req);
};
} // namespace mozilla
#endif // DOM_MEDIA_MEDIAPERMISSIONGONK_H

View File

@ -714,35 +714,6 @@ private:
return PrincipalSubsumes(principal);
}
bool CheckPermission(const char* aType)
{
if (!mRecorder || !mRecorder->GetOwner()) {
return false;
}
nsCOMPtr<nsIDocument> doc = mRecorder->GetOwner()->GetExtantDoc();
if (!doc) {
return false;
}
// Certified applications can always assign AUDIO_3GPP
if (doc->NodePrincipal()->GetAppStatus() ==
nsIPrincipal::APP_STATUS_CERTIFIED) {
return true;
}
nsCOMPtr<nsIPermissionManager> pm =
do_GetService(NS_PERMISSIONMANAGER_CONTRACTID);
if (!pm) {
return false;
}
uint32_t perm = nsIPermissionManager::DENY_ACTION;
pm->TestExactPermissionFromPrincipal(doc->NodePrincipal(), aType, &perm);
return perm == nsIPermissionManager::ALLOW_ACTION;
}
void InitEncoder(uint8_t aTrackTypes, TrackRate aTrackRate)
{
LOG(LogLevel::Debug, ("Session.InitEncoder %p", this));
@ -755,26 +726,11 @@ private:
// Allocate encoder and bind with union stream.
// At this stage, the API doesn't allow UA to choose the output mimeType format.
// Make sure the application has permission to assign AUDIO_3GPP
if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP) && CheckPermission("audio-capture:3gpp")) {
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP),
mRecorder->GetAudioBitrate(),
mRecorder->GetVideoBitrate(),
mRecorder->GetBitrate(),
aTrackTypes, aTrackRate);
} else if (mRecorder->mMimeType.EqualsLiteral(AUDIO_3GPP2) && CheckPermission("audio-capture:3gpp2")) {
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(AUDIO_3GPP2),
mRecorder->GetAudioBitrate(),
mRecorder->GetVideoBitrate(),
mRecorder->GetBitrate(),
aTrackTypes, aTrackRate);
} else {
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""),
mRecorder->GetAudioBitrate(),
mRecorder->GetVideoBitrate(),
mRecorder->GetBitrate(),
aTrackTypes, aTrackRate);
}
mEncoder = MediaEncoder::CreateEncoder(NS_LITERAL_STRING(""),
mRecorder->GetAudioBitrate(),
mRecorder->GetVideoBitrate(),
mRecorder->GetBitrate(),
aTrackTypes, aTrackRate);
if (!mEncoder) {
LOG(LogLevel::Debug, ("Session.InitEncoder !mEncoder %p", this));

View File

@ -94,7 +94,7 @@ mozilla::ipc::IPCResult
VideoDecoderChild::RecvInitComplete(const bool& aHardware, const nsCString& aHardwareReason)
{
AssertOnManagerThread();
mInitPromise.Resolve(TrackInfo::kVideoTrack, __func__);
mInitPromise.ResolveIfExists(TrackInfo::kVideoTrack, __func__);
mInitialized = true;
mIsHardwareAccelerated = aHardware;
mHardwareAcceleratedReason = aHardwareReason;
@ -105,7 +105,7 @@ mozilla::ipc::IPCResult
VideoDecoderChild::RecvInitFailed(const nsresult& aReason)
{
AssertOnManagerThread();
mInitPromise.Reject(aReason, __func__);
mInitPromise.RejectIfExists(aReason, __func__);
return IPC_OK();
}

View File

@ -54,6 +54,7 @@ VideoDecoderParent::VideoDecoderParent(VideoDecoderManagerParent* aParent,
, mDestroyed(false)
{
MOZ_COUNT_CTOR(VideoDecoderParent);
MOZ_ASSERT(OnManagerThread());
// We hold a reference to ourselves to keep us alive until IPDL
// explictly destroys us. There may still be refs held by
// tasks, but no new ones should be added after we're
@ -91,6 +92,7 @@ VideoDecoderParent::~VideoDecoderParent()
void
VideoDecoderParent::Destroy()
{
MOZ_ASSERT(OnManagerThread());
mDecodeTaskQueue->AwaitShutdownAndIdle();
mDestroyed = true;
mIPDLSelfRef = nullptr;
@ -99,10 +101,11 @@ VideoDecoderParent::Destroy()
mozilla::ipc::IPCResult
VideoDecoderParent::RecvInit()
{
MOZ_ASSERT(OnManagerThread());
RefPtr<VideoDecoderParent> self = this;
mDecoder->Init()->Then(mManagerTaskQueue, __func__,
[self] (TrackInfo::TrackType aTrack) {
if (!self->mDestroyed) {
if (self->mDecoder) {
nsCString hardwareReason;
bool hardwareAccelerated = self->mDecoder->IsHardwareAccelerated(hardwareReason);
Unused << self->SendInitComplete(hardwareAccelerated, hardwareReason);
@ -119,6 +122,7 @@ VideoDecoderParent::RecvInit()
mozilla::ipc::IPCResult
VideoDecoderParent::RecvInput(const MediaRawDataIPDL& aData)
{
MOZ_ASSERT(OnManagerThread());
// XXX: This copies the data into a buffer owned by the MediaRawData. Ideally we'd just take ownership
// of the shmem.
RefPtr<MediaRawData> data = new MediaRawData(aData.buffer().get<uint8_t>(), aData.buffer().Size<uint8_t>());
@ -138,6 +142,7 @@ mozilla::ipc::IPCResult
VideoDecoderParent::RecvFlush()
{
MOZ_ASSERT(!mDestroyed);
MOZ_ASSERT(OnManagerThread());
if (mDecoder) {
mDecoder->Flush();
}
@ -158,6 +163,7 @@ mozilla::ipc::IPCResult
VideoDecoderParent::RecvDrain()
{
MOZ_ASSERT(!mDestroyed);
MOZ_ASSERT(OnManagerThread());
mDecoder->Drain();
return IPC_OK();
}
@ -166,6 +172,7 @@ mozilla::ipc::IPCResult
VideoDecoderParent::RecvShutdown()
{
MOZ_ASSERT(!mDestroyed);
MOZ_ASSERT(OnManagerThread());
if (mDecoder) {
mDecoder->Shutdown();
}
@ -177,6 +184,7 @@ mozilla::ipc::IPCResult
VideoDecoderParent::RecvSetSeekThreshold(const int64_t& aTime)
{
MOZ_ASSERT(!mDestroyed);
MOZ_ASSERT(OnManagerThread());
mDecoder->SetSeekThreshold(media::TimeUnit::FromMicroseconds(aTime));
return IPC_OK();
}
@ -185,6 +193,7 @@ void
VideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy)
{
MOZ_ASSERT(!mDestroyed);
MOZ_ASSERT(OnManagerThread());
if (mDecoder) {
mDecoder->Shutdown();
mDecoder = nullptr;
@ -278,6 +287,12 @@ VideoDecoderParent::OnReaderTaskQueue()
// Most of our calls into mDecoder come directly from IPDL so are on
// the right thread, but not actually on the task queue. We only ever
// run a single thread, not a pool, so this should work fine.
return OnManagerThread();
}
bool
VideoDecoderParent::OnManagerThread()
{
return mParent->OnManagerThread();
}

View File

@ -53,6 +53,8 @@ public:
bool OnReaderTaskQueue() override;
private:
bool OnManagerThread();
~VideoDecoderParent();
RefPtr<VideoDecoderManagerParent> mParent;

View File

@ -166,11 +166,6 @@ IPDL_SOURCES += [
'webrtc/PWebrtcGlobal.ipdl'
]
if CONFIG['MOZ_B2G']:
EXPORTS.mozilla += [
'MediaPermissionGonk.h',
]
EXPORTS.mozilla.dom += [
'AudioStreamTrack.h',
'AudioTrack.h',
@ -267,11 +262,6 @@ UNIFIED_SOURCES += [
if CONFIG['OS_TARGET'] == 'WINNT':
SOURCES += [ 'ThreadPoolCOMListener.cpp' ]
if CONFIG['MOZ_B2G']:
SOURCES += [
'MediaPermissionGonk.cpp',
]
# DecoderTraits.cpp needs to be built separately because of Mac OS X headers.
SOURCES += [
'DecoderTraits.cpp',

View File

@ -20,13 +20,6 @@ interface nsIVolumeService : nsISupports
nsIArray getVolumeNames();
void Dump(in DOMString label);
/* for test case only to simulate sdcard insertion/removal */
void createFakeVolume(in DOMString name, in DOMString path);
void SetFakeVolumeState(in DOMString name, in long state);
/* for test case only to test removal of storage area */
void removeFakeVolume(in DOMString name);
};
%{C++

View File

@ -24,32 +24,8 @@ public:
// This constructor is used by the UpdateVolumeRunnable constructor
nsVolume(const Volume* aVolume);
// This constructor is used by nsVolumeService::SetFakeVolumeState
nsVolume(const nsVolume* aVolume);
// This constructor is used by ContentChild::RecvFileSystemUpdate which is
// used to update the volume cache maintained in the child process.
nsVolume(const nsAString& aName, const nsAString& aMountPoint,
const int32_t& aState, const int32_t& aMountGeneration,
const bool& aIsMediaPresent, const bool& aIsSharing,
const bool& aIsFormatting, const bool& aIsFake,
const bool& aIsUnmounting, const bool& aIsRemovable,
const bool& aIsHotSwappable)
: mName(aName),
mMountPoint(aMountPoint),
mState(aState),
mMountGeneration(aMountGeneration),
mMountLocked(false),
mIsFake(aIsFake),
mIsMediaPresent(aIsMediaPresent),
mIsSharing(aIsSharing),
mIsFormatting(aIsFormatting),
mIsUnmounting(aIsUnmounting),
mIsRemovable(aIsRemovable),
mIsHotSwappable(aIsHotSwappable)
{
}
bool Equals(nsIVolume* aVolume);
void UpdateMountLock(nsVolume* aOldVolume);

View File

@ -416,67 +416,6 @@ nsVolumeService::UpdateVolume(nsVolume* aVolume, bool aNotifyObservers)
obs->NotifyObservers(aVolume, NS_VOLUME_STATE_CHANGED, stateStr.get());
}
NS_IMETHODIMP
nsVolumeService::CreateFakeVolume(const nsAString& name, const nsAString& path)
{
if (XRE_IsParentProcess()) {
RefPtr<nsVolume> vol = new nsVolume(name, path, nsIVolume::STATE_INIT,
-1 /* mountGeneration */,
true /* isMediaPresent */,
false /* isSharing */,
false /* isFormatting */,
true /* isFake */,
false /* isUnmounting */,
false /* isRemovable */,
false /* isHotSwappable */);
vol->SetState(nsIVolume::STATE_MOUNTED);
vol->LogState();
UpdateVolume(vol.get());
return NS_OK;
}
ContentChild::GetSingleton()->SendCreateFakeVolume(nsString(name), nsString(path));
return NS_OK;
}
NS_IMETHODIMP
nsVolumeService::SetFakeVolumeState(const nsAString& name, int32_t state)
{
if (XRE_IsParentProcess()) {
RefPtr<nsVolume> vol;
{
MonitorAutoLock autoLock(mArrayMonitor);
vol = FindVolumeByName(name);
}
if (!vol || !vol->IsFake()) {
return NS_ERROR_NOT_AVAILABLE;
}
// Clone the existing volume so we can replace it
RefPtr<nsVolume> volume = new nsVolume(vol);
volume->SetState(state);
volume->LogState();
UpdateVolume(volume.get());
return NS_OK;
}
ContentChild::GetSingleton()->SendSetFakeVolumeState(nsString(name), state);
return NS_OK;
}
NS_IMETHODIMP
nsVolumeService::RemoveFakeVolume(const nsAString& name)
{
if (XRE_IsParentProcess()) {
SetFakeVolumeState(name, nsIVolume::STATE_NOMEDIA);
RemoveVolumeByName(name);
return NS_OK;
}
ContentChild::GetSingleton()->SendRemoveFakeVolume(nsString(name));
return NS_OK;
}
void
nsVolumeService::RemoveVolumeByName(const nsAString& aName)
{

View File

@ -3,7 +3,6 @@ run-if = buildapp == 'b2g'
[test_geolocation.js]
skip-if = true # Bug 808783
[test_fakevolume.js]
[test_ril_code_quality.py]
[test_screen_state.js]
[test_dsds_numRadioInterfaces.js]

View File

@ -1,25 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
MARIONETTE_TIMEOUT = 10000;
var Cc = SpecialPowers.Cc;
var Ci = SpecialPowers.Ci;
var volumeService = Cc["@mozilla.org/telephony/volume-service;1"].getService(Ci.nsIVolumeService);
ok(volumeService, "Should have volume service");
var volName = "fake";
var mountPoint = "/data/fake/storage";
volumeService.createFakeVolume(volName, mountPoint);
var vol = volumeService.getVolumeByName(volName);
ok(vol, "volume shouldn't be null");
is(volName, vol.name, "name");
is(mountPoint, vol.mountPoint, "moutnPoint");
is(Ci.nsIVolume.STATE_MOUNTED, vol.state, "state");
ok(vol.mountGeneration > 0, "mount generation should not be zero");
finish();

View File

@ -36,7 +36,8 @@ DrawEventRecorderPrivate::RecordEvent(const RecordedEvent &aEvent)
}
DrawEventRecorderFile::DrawEventRecorderFile(const char *aFilename)
: DrawEventRecorderPrivate(nullptr)
: DrawEventRecorderPrivate(nullptr)
, mOutputFilename(aFilename)
, mOutputFile(aFilename, ofstream::binary)
{
mOutputStream = &mOutputFile;
@ -55,6 +56,25 @@ DrawEventRecorderFile::Flush()
mOutputFile.flush();
}
void
DrawEventRecorderFile::OpenAndTruncate()
{
if (mOutputFile.is_open()) {
return;
}
mOutputFile.open(mOutputFilename.c_str(), ofstream::binary | ofstream::trunc);
WriteHeader();
}
void
DrawEventRecorderFile::Close()
{
MOZ_ASSERT(mOutputFile.is_open());
mOutputFile.close();
}
DrawEventRecorderMemory::DrawEventRecorderMemory()
: DrawEventRecorderPrivate(nullptr)
{

View File

@ -10,6 +10,7 @@
#include "RecordedEvent.h"
#include <ostream>
#include <fstream>
#include <string>
#if defined(_MSC_VER)
#include <unordered_set>
@ -78,9 +79,24 @@ public:
explicit DrawEventRecorderFile(const char *aFilename);
~DrawEventRecorderFile();
/**
* Re-opens and truncates the file. The recorder does NOT forget which objects
* it has recorded. This can be used with Close, so that a recording can be
* processed in chunks. If the file is already open this does nothing.
*/
void OpenAndTruncate();
/**
* Closes the file so that it can be processed. The recorder does NOT forget
* which objects it has recorded. This can be used with OpenAndTruncate, so
* that a recording can be processed in chunks. The file must be open.
*/
void Close();
private:
virtual void Flush();
std::string mOutputFilename;
std::ofstream mOutputFile;
};

View File

@ -146,6 +146,9 @@ ClientLayerManager::Destroy()
});
NS_DispatchToMainThread(task.forget());
}
// Forget the widget pointer in case we outlive our owning widget.
mWidget = nullptr;
}
int32_t

View File

@ -67,5 +67,54 @@ PrintTargetCG::CreateOrNull(CGContextRef aContext, const IntSize& aSize)
return target.forget();
}
static size_t
PutBytesNull(void* info, const void* buffer, size_t count)
{
return count;
}
already_AddRefed<DrawTarget>
PrintTargetCG::GetReferenceDrawTarget(DrawEventRecorder* aRecorder)
{
if (!mRefDT) {
const IntSize size(1, 1);
CGDataConsumerCallbacks callbacks = {PutBytesNull, nullptr};
CGDataConsumerRef consumer = CGDataConsumerCreate(nullptr, &callbacks);
CGContextRef pdfContext = CGPDFContextCreate(consumer, nullptr, nullptr);
CGDataConsumerRelease(consumer);
cairo_surface_t* similar =
cairo_quartz_surface_create_for_cg_context(
pdfContext, size.width, size.height);
CGContextRelease(pdfContext);
if (cairo_surface_status(similar)) {
return nullptr;
}
RefPtr<DrawTarget> dt =
Factory::CreateDrawTargetForCairoSurface(similar, size);
// The DT addrefs the surface, so we need drop our own reference to it:
cairo_surface_destroy(similar);
if (!dt || !dt->IsValid()) {
return nullptr;
}
if (aRecorder) {
dt = CreateRecordingDrawTarget(aRecorder, dt);
if (!dt || !dt->IsValid()) {
return nullptr;
}
}
mRefDT = dt.forget();
}
return do_AddRef(mRefDT);
}
} // namespace gfx
} // namespace mozilla

View File

@ -28,6 +28,9 @@ public:
static already_AddRefed<PrintTargetCG>
CreateOrNull(CGContextRef aContext, const IntSize& aSize);
virtual already_AddRefed<DrawTarget>
GetReferenceDrawTarget(DrawEventRecorder* aRecorder) final;
private:
PrintTargetCG(cairo_surface_t* aCairoSurface,
const IntSize& aSize);

View File

@ -7,6 +7,7 @@
#include "frontend/BytecodeCompiler.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/Maybe.h"
#include "jscntxt.h"
#include "jsscript.h"
@ -28,6 +29,7 @@
using namespace js;
using namespace js::frontend;
using mozilla::Maybe;
using mozilla::Nothing;
class MOZ_STACK_CLASS AutoCompilationTraceLogger
{
@ -57,24 +59,24 @@ class MOZ_STACK_CLASS BytecodeCompiler
// Call setters for optional arguments.
void maybeSetSourceCompressor(SourceCompressionTask* sourceCompressor);
void setSourceArgumentsNotIncluded();
JSScript* compileGlobalScript(ScopeKind scopeKind);
JSScript* compileEvalScript(HandleObject environment, HandleScope enclosingScope);
ModuleObject* compileModule();
bool compileFunctionBody(MutableHandleFunction fun, Handle<PropertyNameVector> formals,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind);
bool compileStandaloneFunction(MutableHandleFunction fun, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
Maybe<uint32_t> parameterListEnd);
ScriptSourceObject* sourceObjectPtr() const;
private:
JSScript* compileScript(HandleObject environment, SharedContext* sc);
bool checkLength();
bool createScriptSource();
bool createScriptSource(Maybe<uint32_t> parameterListEnd);
bool maybeCompressSource();
bool canLazilyParse();
bool createParser();
bool createSourceAndParser();
bool createSourceAndParser(Maybe<uint32_t> parameterListEnd = Nothing());
bool createScript();
bool emplaceEmitter(Maybe<BytecodeEmitter>& emitter, SharedContext* sharedContext);
bool handleParseFailure(const Directives& newDirectives);
@ -90,7 +92,6 @@ class MOZ_STACK_CLASS BytecodeCompiler
SourceBufferHolder& sourceBuffer;
RootedScope enclosingScope;
bool sourceArgumentsNotIncluded;
RootedScriptSource sourceObject;
ScriptSource* scriptSource;
@ -130,7 +131,6 @@ BytecodeCompiler::BytecodeCompiler(ExclusiveContext* cx,
options(options),
sourceBuffer(sourceBuffer),
enclosingScope(cx, enclosingScope),
sourceArgumentsNotIncluded(false),
sourceObject(cx),
scriptSource(nullptr),
sourceCompressor(nullptr),
@ -147,12 +147,6 @@ BytecodeCompiler::maybeSetSourceCompressor(SourceCompressionTask* sourceCompress
this->sourceCompressor = sourceCompressor;
}
void
BytecodeCompiler::setSourceArgumentsNotIncluded()
{
sourceArgumentsNotIncluded = true;
}
bool
BytecodeCompiler::checkLength()
{
@ -169,12 +163,12 @@ BytecodeCompiler::checkLength()
}
bool
BytecodeCompiler::createScriptSource()
BytecodeCompiler::createScriptSource(Maybe<uint32_t> parameterListEnd)
{
if (!checkLength())
return false;
sourceObject = CreateScriptSourceObject(cx, options);
sourceObject = CreateScriptSourceObject(cx, options, parameterListEnd);
if (!sourceObject)
return false;
@ -193,9 +187,7 @@ BytecodeCompiler::maybeCompressSource()
if (!cx->compartment()->behaviors().discardSource()) {
if (options.sourceIsLazy) {
scriptSource->setSourceRetrievable();
} else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceArgumentsNotIncluded,
sourceCompressor))
{
} else if (!scriptSource->setSourceCopy(cx, sourceBuffer, sourceCompressor)) {
return false;
}
}
@ -242,9 +234,9 @@ BytecodeCompiler::createParser()
}
bool
BytecodeCompiler::createSourceAndParser()
BytecodeCompiler::createSourceAndParser(Maybe<uint32_t> parameterListEnd /* = Nothing() */)
{
return createScriptSource() &&
return createScriptSource(parameterListEnd) &&
maybeCompressSource() &&
createParser();
}
@ -432,18 +424,19 @@ BytecodeCompiler::compileModule()
return module;
}
// Compile a standalone JS function, which might appear as the value of an
// event handler attribute in an HTML <INPUT> tag, or in a Function()
// constructor.
bool
BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
Handle<PropertyNameVector> formals,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind)
BytecodeCompiler::compileStandaloneFunction(MutableHandleFunction fun,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
Maybe<uint32_t> parameterListEnd)
{
MOZ_ASSERT(fun);
MOZ_ASSERT(fun->isTenured());
fun->setArgCount(formals.length());
if (!createSourceAndParser())
if (!createSourceAndParser(parameterListEnd))
return false;
// Speculatively parse using the default directives implied by the context.
@ -454,8 +447,8 @@ BytecodeCompiler::compileFunctionBody(MutableHandleFunction fun,
ParseNode* fn;
do {
Directives newDirectives = directives;
fn = parser->standaloneFunctionBody(fun, enclosingScope, formals, generatorKind, asyncKind,
directives, &newDirectives);
fn = parser->standaloneFunction(fun, enclosingScope, parameterListEnd, generatorKind,
asyncKind, directives, &newDirectives);
if (!fn && !handleParseFailure(newDirectives))
return false;
} while (!fn);
@ -492,14 +485,15 @@ BytecodeCompiler::sourceObjectPtr() const
}
ScriptSourceObject*
frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
frontend::CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
Maybe<uint32_t> parameterListEnd /* = Nothing() */)
{
ScriptSource* ss = cx->new_<ScriptSource>();
if (!ss)
return nullptr;
ScriptSourceHolder ssHolder(ss);
if (!ss->initFromOptions(cx, options))
if (!ss->initFromOptions(cx, options, parameterListEnd))
return nullptr;
RootedScriptSource sso(cx, ScriptSourceObject::create(cx, ss));
@ -676,63 +670,44 @@ frontend::CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const cha
return bce.emitFunctionScript(pn->pn_body);
}
// Compile a JS function body, which might appear as the value of an event
// handler attribute in an HTML <INPUT> tag, or in a Function() constructor.
static bool
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun, const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, SourceBufferHolder& srcBuf,
HandleScope enclosingScope, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind)
bool
frontend::CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
JS::SourceBufferHolder& srcBuf,
Maybe<uint32_t> parameterListEnd,
HandleScope enclosingScope /* = nullptr */)
{
MOZ_ASSERT(!options.isRunOnce);
RootedScope scope(cx, enclosingScope);
if (!scope)
scope = &cx->global()->emptyGlobalScope();
// FIXME: make Function pass in two strings and parse them as arguments and
// ProgramElements respectively.
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, enclosingScope,
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, scope,
TraceLogger_ParserCompileFunction);
compiler.setSourceArgumentsNotIncluded();
return compiler.compileFunctionBody(fun, formals, generatorKind, asyncKind);
return compiler.compileStandaloneFunction(fun, NotGenerator, SyncFunction, parameterListEnd);
}
bool
frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
HandleScope enclosingScope)
{
return CompileFunctionBody(cx, fun, options, formals, srcBuf, enclosingScope, NotGenerator,
SyncFunction);
}
bool
frontend::CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf)
frontend::CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
JS::SourceBufferHolder& srcBuf,
Maybe<uint32_t> parameterListEnd)
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
NotGenerator, SyncFunction);
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
TraceLogger_ParserCompileFunction);
return compiler.compileStandaloneFunction(fun, StarGenerator, SyncFunction, parameterListEnd);
}
bool
frontend::CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals,
JS::SourceBufferHolder& srcBuf)
frontend::CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
JS::SourceBufferHolder& srcBuf,
Maybe<uint32_t> parameterListEnd)
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
StarGenerator, SyncFunction);
}
bool
frontend::CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals,
JS::SourceBufferHolder& srcBuf)
{
RootedScope emptyGlobalScope(cx, &cx->global()->emptyGlobalScope());
return CompileFunctionBody(cx, fun, options, formals, srcBuf, emptyGlobalScope,
StarGenerator, AsyncFunction);
BytecodeCompiler compiler(cx, cx->tempLifoAlloc(), options, srcBuf, emptyGlobalScope,
TraceLogger_ParserCompileFunction);
return compiler.compileStandaloneFunction(fun, StarGenerator, AsyncFunction, parameterListEnd);
}

View File

@ -7,6 +7,8 @@
#ifndef frontend_BytecodeCompiler_h
#define frontend_BytecodeCompiler_h
#include "mozilla/Maybe.h"
#include "NamespaceImports.h"
#include "vm/Scope.h"
@ -51,22 +53,36 @@ CompileModule(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
MOZ_MUST_USE bool
CompileLazyFunction(JSContext* cx, Handle<LazyScript*> lazy, const char16_t* chars, size_t length);
//
// Compile a single function. The source in srcBuf must match the ECMA-262
// FunctionExpression production.
//
// If nonzero, parameterListEnd is the offset within srcBuf where the parameter
// list is expected to end. During parsing, if we find that it ends anywhere
// else, it's a SyntaxError. This is used to implement the Function constructor;
// it's how we detect that these weird cases are SyntaxErrors:
//
// Function("/*", "*/x) {")
// Function("x){ if (3", "return x;}")
//
MOZ_MUST_USE bool
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf,
HandleScope enclosingScope);
// As above, but defaults to the global lexical scope as the enclosing scope.
MOZ_MUST_USE bool
CompileFunctionBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
CompileStandaloneFunction(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
JS::SourceBufferHolder& srcBuf,
mozilla::Maybe<uint32_t> parameterListEnd,
HandleScope enclosingScope = nullptr);
MOZ_MUST_USE bool
CompileStarGeneratorBody(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
CompileStandaloneGenerator(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
JS::SourceBufferHolder& srcBuf,
mozilla::Maybe<uint32_t> parameterListEnd);
MOZ_MUST_USE bool
CompileStandaloneAsyncFunction(JSContext* cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions& options,
JS::SourceBufferHolder& srcBuf,
mozilla::Maybe<uint32_t> parameterListEnd);
MOZ_MUST_USE bool
CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
@ -74,7 +90,8 @@ CompileAsyncFunctionBody(JSContext* cx, MutableHandleFunction fun,
Handle<PropertyNameVector> formals, JS::SourceBufferHolder& srcBuf);
ScriptSourceObject*
CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options);
CreateScriptSourceObject(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
/*
* True if str consists of an IdentifierStart character, followed by one or

View File

@ -2279,13 +2279,13 @@ GetYieldHandling(GeneratorKind generatorKind, FunctionAsyncKind asyncKind)
template <>
ParseNode*
Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
HandleScope enclosingScope,
Handle<PropertyNameVector> formals,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
Directives inheritedDirectives,
Directives* newDirectives)
Parser<FullParseHandler>::standaloneFunction(HandleFunction fun,
HandleScope enclosingScope,
Maybe<uint32_t> parameterListEnd,
GeneratorKind generatorKind,
FunctionAsyncKind asyncKind,
Directives inheritedDirectives,
Directives* newDirectives)
{
MOZ_ASSERT(checkOptionsCalled);
@ -2308,25 +2308,14 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
if (!funpc.init())
return null();
funpc.setIsStandaloneFunctionBody();
funpc.functionScope().useAsVarScope(&funpc);
if (formals.length() >= ARGNO_LIMIT) {
error(JSMSG_TOO_MANY_FUN_ARGS);
return null();
}
bool duplicatedParam = false;
for (uint32_t i = 0; i < formals.length(); i++) {
if (!notePositionalFormalParameter(fn, formals[i], false, &duplicatedParam))
return null();
}
funbox->hasDuplicateParameters = duplicatedParam;
YieldHandling yieldHandling = GetYieldHandling(generatorKind, asyncKind);
AutoAwaitIsKeyword awaitIsKeyword(&tokenStream, asyncKind == AsyncFunction);
ParseNode* pn = functionBody(InAllowed, yieldHandling, Statement, StatementListBody);
if (!pn)
if (!functionFormalParametersAndBody(InAllowed, yieldHandling, fn, Statement,
parameterListEnd))
{
return null();
}
TokenKind tt;
if (!tokenStream.getToken(&tt, TokenStream::Operand))
@ -2336,15 +2325,7 @@ Parser<FullParseHandler>::standaloneFunctionBody(HandleFunction fun,
return null();
}
if (!FoldConstants(context, &pn, this))
return null();
fn->pn_pos.end = pos().end;
MOZ_ASSERT(fn->pn_body->isKind(PNK_PARAMSBODY));
fn->pn_body->append(pn);
if (!finishFunction())
if (!FoldConstants(context, &fn, this))
return null();
return fn;
@ -3396,7 +3377,8 @@ template <typename ParseHandler>
bool
Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
YieldHandling yieldHandling,
Node pn, FunctionSyntaxKind kind)
Node pn, FunctionSyntaxKind kind,
Maybe<uint32_t> parameterListEnd /* = Nothing() */)
{
// Given a properly initialized parse context, try to parse an actual
// function without concern for conversion to strict mode, use of lazy
@ -3428,6 +3410,13 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
}
}
// When parsing something for new Function() we have to make sure to
// only treat a certain part of the source as a parameter list.
if (parameterListEnd.isSome() && parameterListEnd.value() != pos().begin) {
error(JSMSG_UNEXPECTED_PARAMLIST_END);
return false;
}
// Parse the function body.
FunctionBodyType bodyType = StatementListBody;
TokenKind tt;
@ -3483,7 +3472,7 @@ Parser<ParseHandler>::functionFormalParametersAndBody(InHandling inHandling,
error(JSMSG_CURLY_AFTER_BODY);
return false;
}
funbox->bufEnd = pos().begin + 1;
funbox->bufEnd = pos().end;
} else {
#if !JS_HAS_EXPR_CLOSURES
MOZ_ASSERT(kind == Arrow);

View File

@ -1050,12 +1050,12 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Parse a module.
Node moduleBody(ModuleSharedContext* modulesc);
// Parse a function, given only its body. Used for the Function and
// Generator constructors.
Node standaloneFunctionBody(HandleFunction fun, HandleScope enclosingScope,
Handle<PropertyNameVector> formals,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
Directives inheritedDirectives, Directives* newDirectives);
// Parse a function, used for the Function, GeneratorFunction, and
// AsyncFunction constructors.
Node standaloneFunction(HandleFunction fun, HandleScope enclosingScope,
mozilla::Maybe<uint32_t> parameterListEnd,
GeneratorKind generatorKind, FunctionAsyncKind asyncKind,
Directives inheritedDirectives, Directives* newDirectives);
// Parse a function, given only its arguments and body. Used for lazily
// parsed functions.
@ -1071,7 +1071,8 @@ class Parser final : private JS::AutoGCRooter, public StrictModeGetter
// Parse a function's formal parameters and its body assuming its function
// ParseContext is already on the stack.
bool functionFormalParametersAndBody(InHandling inHandling, YieldHandling yieldHandling,
Node pn, FunctionSyntaxKind kind);
Node pn, FunctionSyntaxKind kind,
mozilla::Maybe<uint32_t> parameterListEnd = mozilla::Nothing());
// Determine whether |yield| is a valid name in the current context, or
// whether it's prohibited due to strictness, JS version, or occurrence

View File

@ -947,7 +947,8 @@ class GCRuntime
void requestMajorGC(JS::gcreason::Reason reason);
SliceBudget defaultBudget(JS::gcreason::Reason reason, int64_t millis);
void budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& lock);
void budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget,
AutoLockForExclusiveAccess& lock);
void resetIncrementalGC(AbortReason reason, AutoLockForExclusiveAccess& lock);
// Assert if the system state is such that we should never
@ -962,6 +963,7 @@ class GCRuntime
void collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason) JS_HAZ_GC_CALL;
MOZ_MUST_USE bool gcCycle(bool nonincrementalByAPI, SliceBudget& budget,
JS::gcreason::Reason reason);
bool shouldRepeatForDeadZone(JS::gcreason::Reason reason);
void incrementalCollectSlice(SliceBudget& budget, JS::gcreason::Reason reason,
AutoLockForExclusiveAccess& lock);

View File

@ -84,10 +84,7 @@ function testArgumentFunction(pattern, input) {
'return [a, b, c, d, e, f];'
)(input);
}
// XXX: ES6 requires the `Function` constructor to accept arbitrary
// `BindingElement`s as formal parameters. See Bug 1037939.
// Once fixed, please update the assertions below.
assertThrowsInstanceOf(() => testAll(testArgumentFunction), SyntaxError);
testAll(testArgumentFunction);
function testThrow(pattern, input) {
return new Function('input',

View File

@ -132,10 +132,9 @@ function testArgumentFunction(pattern, input, binding) {
'return ' + binding
)(input);
}
// XXX: ES6 requires the `Function` constructor to accept arbitrary
// `BindingElement`s as formal parameters. See Bug 1037939.
// Once fixed, please update the assertions below.
assertThrowsInstanceOf(() => testDeclaration(testArgumentFunction), SyntaxError);
// ES6 requires the `Function` constructor to accept arbitrary
// `BindingElement`s as formal parameters.
testDeclaration(testArgumentFunction);
function testThrow(pattern, input, binding) {
binding = binding || 'rest';

View File

@ -4,6 +4,14 @@ const prototypes = [
WeakMap.prototype,
WeakSet.prototype,
Date.prototype,
Error.prototype,
InternalError.prototype,
EvalError.prototype,
RangeError.prototype,
ReferenceError.prototype,
SyntaxError.prototype,
TypeError.prototype,
URIError.prototype,
];
for (const prototype of prototypes) {

View File

@ -10,5 +10,5 @@ assertEq(arr.length, 10);
gc();
for (var i = 0; i < arr.length; i++)
assertEq(arr[i].lineCount, 1);
assertEq(arr[i].lineCount, 3);

View File

@ -10,6 +10,6 @@ assertEq(arr.length, 100);
gc(g);
for (var i = 0; i < arr.length; i++)
assertEq(arr[i].lineCount, 1);
assertEq(arr[i].lineCount, 3);
gc();

View File

@ -20,6 +20,6 @@ function test(string, range) {
}
test("eval('2 * 3')", [0, 5]);
test("new Function('2 * 3')", [0, 5]);
test("new Function('x', 'x * x')", [0, 5]);
test("new Function('2 * 3')", [0, 12]);
test("new Function('x', 'x * x')", [0, 13]);
assertEq(count, 6);

View File

@ -92,9 +92,11 @@ var e = wasmEvalText('(module (func $i2v (param i32)) (export "i2v" $i2v) (func
var i2vm = new Module(wasmTextToBinary('(module (import "a" "b" (param i32)))'));
var f2vm = new Module(wasmTextToBinary('(module (import "a" "b" (param f32)))'));
assertEq(new Instance(i2vm, {a:{b:e.i2v}}) instanceof Instance, true);
assertErrorMessage(() => new Instance(i2vm, {a:{b:e.f2v}}), TypeError, /imported function signature mismatch/);
assertErrorMessage(() => new Instance(f2vm, {a:{b:e.i2v}}), TypeError, /imported function signature mismatch/);
assertErrorMessage(() => new Instance(i2vm, {a:{b:e.f2v}}), TypeError, /imported function 'a.b' signature mismatch/);
assertErrorMessage(() => new Instance(f2vm, {a:{b:e.i2v}}), TypeError, /imported function 'a.b' signature mismatch/);
assertEq(new Instance(f2vm, {a:{b:e.f2v}}) instanceof Instance, true);
var l2vm = new Module(wasmTextToBinary('(module (import "x" "y" (memory 1)) (import "c" "d" (param i64)))'));
assertErrorMessage(() => new Instance(l2vm, {x:{y:mem1Page}, c:{d:e.i2v}}), TypeError, /imported function 'c.d' signature mismatch/);
// Import order:

View File

@ -3112,6 +3112,11 @@ MBinaryArithInstruction::constantDoubleResult(TempAllocator& alloc)
MDefinition*
MRsh::foldsTo(TempAllocator& alloc)
{
MDefinition* f = MBinaryBitwiseInstruction::foldsTo(alloc);
if (f != this)
return f;
MDefinition* lhs = getOperand(0);
MDefinition* rhs = getOperand(1);

View File

@ -332,6 +332,7 @@ MSG_DEF(JSMSG_TOO_MANY_LOCALS, 0, JSEXN_SYNTAXERR, "too many local varia
MSG_DEF(JSMSG_TOO_MANY_YIELDS, 0, JSEXN_SYNTAXERR, "too many yield expressions")
MSG_DEF(JSMSG_TOUGH_BREAK, 0, JSEXN_SYNTAXERR, "unlabeled break must be inside loop or switch")
MSG_DEF(JSMSG_UNEXPECTED_TOKEN, 2, JSEXN_SYNTAXERR, "expected {0}, got {1}")
MSG_DEF(JSMSG_UNEXPECTED_PARAMLIST_END,0, JSEXN_SYNTAXERR, "unexpected end of function parameter list")
MSG_DEF(JSMSG_UNNAMED_CLASS_STMT, 0, JSEXN_SYNTAXERR, "class statement requires a name")
MSG_DEF(JSMSG_UNNAMED_FUNCTION_STMT, 0, JSEXN_SYNTAXERR, "function statement requires a name")
MSG_DEF(JSMSG_UNTERMINATED_COMMENT, 0, JSEXN_SYNTAXERR, "unterminated comment")
@ -377,7 +378,7 @@ MSG_DEF(JSMSG_WASM_BAD_IMP_MAX, 1, JSEXN_TYPEERR, "imported {0} with
MSG_DEF(JSMSG_WASM_BAD_ELEMENT, 0, JSEXN_TYPEERR, "\"element\" property of table descriptor must be \"anyfunc\"")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_ARG, 0, JSEXN_TYPEERR, "second argument must be an object")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_FIELD, 2, JSEXN_TYPEERR, "import object field '{0}' is not {1}")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG, 0, JSEXN_TYPEERR, "imported function signature mismatch")
MSG_DEF(JSMSG_WASM_BAD_IMPORT_SIG, 2, JSEXN_TYPEERR, "imported function '{0}.{1}' signature mismatch")
MSG_DEF(JSMSG_WASM_BAD_TABLE_VALUE, 0, JSEXN_TYPEERR, "can only assign WebAssembly exported functions to Table")
MSG_DEF(JSMSG_WASM_BAD_I64, 0, JSEXN_TYPEERR, "cannot pass i64 to or from JS")
MSG_DEF(JSMSG_WASM_NO_TRANSFER, 0, JSEXN_TYPEERR, "cannot transfer WebAssembly/asm.js ArrayBuffer")

View File

@ -11,6 +11,7 @@
#include "jsapi.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Sprintf.h"
@ -107,6 +108,7 @@ using namespace js::gc;
using mozilla::Maybe;
using mozilla::PodCopy;
using mozilla::PodZero;
using mozilla::Some;
using JS::AutoGCRooter;
using JS::ToInt32;
@ -4205,15 +4207,15 @@ JS_GetFunctionScript(JSContext* cx, HandleFunction fun)
}
/*
* enclosingScope is a static enclosing scope, if any (e.g. a WithScope). If
* the enclosing scope is the global scope, this must be null.
* enclosingScope is a scope, if any (e.g. a WithScope). If the scope is the
* global scope, this must be null.
*
* enclosingDynamicScope is a dynamic scope to use, if it's not the global.
* enclosingEnv is an environment to use, if it's not the global.
*/
static bool
CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
const char* name, unsigned nargs, const char* const* argnames,
SourceBufferHolder& srcBuf,
const char* name,
SourceBufferHolder& srcBuf, uint32_t parameterListEnd,
HandleObject enclosingEnv, HandleScope enclosingScope,
MutableHandleFunction fun)
{
@ -4229,13 +4231,6 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
return false;
}
Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
for (unsigned i = 0; i < nargs; i++) {
RootedAtom argAtom(cx, Atomize(cx, argnames[i], strlen(argnames[i])));
if (!argAtom || !formals.append(argAtom->asPropertyName()))
return false;
}
fun.set(NewScriptedFunction(cx, 0, JSFunction::INTERPRETED_NORMAL, funAtom,
/* proto = */ nullptr,
gc::AllocKind::FUNCTION, TenuredObject,
@ -4248,7 +4243,45 @@ CompileFunction(JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(enclosingEnv),
enclosingScope->hasOnChain(ScopeKind::NonSyntactic));
if (!frontend::CompileFunctionBody(cx, fun, optionsArg, formals, srcBuf, enclosingScope))
if (!frontend::CompileStandaloneFunction(cx, fun, optionsArg, srcBuf,
Some(parameterListEnd), enclosingScope))
{
return false;
}
return true;
}
static MOZ_MUST_USE bool
BuildFunctionString(unsigned nargs, const char* const* argnames,
const SourceBufferHolder& srcBuf, StringBuffer* out,
uint32_t* parameterListEnd)
{
MOZ_ASSERT(out);
MOZ_ASSERT(parameterListEnd);
if (!out->ensureTwoByteChars())
return false;
if (!out->append("("))
return false;
for (unsigned i = 0; i < nargs; i++) {
if (i != 0) {
if (!out->append(", "))
return false;
}
if (!out->append(argnames[i], strlen(argnames[i])))
return false;
}
// Remember the position of ")".
*parameterListEnd = out->length();
MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
if (!out->append(FunctionConstructorMedialSigils))
return false;
if (!out->append(srcBuf.get(), srcBuf.length()))
return false;
if (!out->append(FunctionConstructorFinalBrace))
return false;
return true;
@ -4264,7 +4297,16 @@ JS::CompileFunction(JSContext* cx, AutoObjectVector& envChain,
RootedScope scope(cx);
if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env, &scope))
return false;
return CompileFunction(cx, options, name, nargs, argnames, srcBuf, env, scope, fun);
uint32_t parameterListEnd;
StringBuffer funStr(cx);
if (!BuildFunctionString(nargs, argnames, srcBuf, &funStr, &parameterListEnd))
return false;
size_t newLen = funStr.length();
SourceBufferHolder newSrcBuf(funStr.stealChars(), newLen, SourceBufferHolder::GiveOwnership);
return CompileFunction(cx, options, name, newSrcBuf, parameterListEnd, env, scope, fun);
}
JS_PUBLIC_API(bool)

View File

@ -650,7 +650,8 @@ typedef enum JSExnType {
JSEXN_DEBUGGEEWOULDRUN,
JSEXN_WASMCOMPILEERROR,
JSEXN_WASMRUNTIMEERROR,
JSEXN_WARN,
JSEXN_ERROR_LIMIT,
JSEXN_WARN = JSEXN_ERROR_LIMIT,
JSEXN_LIMIT
} JSExnType;

View File

@ -48,18 +48,35 @@ using mozilla::PodArrayZero;
static void
exn_finalize(FreeOp* fop, JSObject* obj);
bool
Error(JSContext* cx, unsigned argc, Value* vp);
static bool
exn_toSource(JSContext* cx, unsigned argc, Value* vp);
static const JSPropertySpec exception_properties[] = {
JS_PSGS("stack", ErrorObject::getStack, ErrorObject::setStack, 0),
JS_PS_END
#define IMPLEMENT_ERROR_PROTO_CLASS(name) \
{ \
js_Object_str, \
JSCLASS_HAS_CACHED_PROTO(JSProto_##name), \
JS_NULL_CLASS_OPS, \
&ErrorObject::classSpecs[JSProto_##name - JSProto_Error] \
}
const Class
ErrorObject::protoClasses[JSEXN_ERROR_LIMIT] = {
IMPLEMENT_ERROR_PROTO_CLASS(Error),
IMPLEMENT_ERROR_PROTO_CLASS(InternalError),
IMPLEMENT_ERROR_PROTO_CLASS(EvalError),
IMPLEMENT_ERROR_PROTO_CLASS(RangeError),
IMPLEMENT_ERROR_PROTO_CLASS(ReferenceError),
IMPLEMENT_ERROR_PROTO_CLASS(SyntaxError),
IMPLEMENT_ERROR_PROTO_CLASS(TypeError),
IMPLEMENT_ERROR_PROTO_CLASS(URIError),
IMPLEMENT_ERROR_PROTO_CLASS(DebuggeeWouldRun),
IMPLEMENT_ERROR_PROTO_CLASS(CompileError),
IMPLEMENT_ERROR_PROTO_CLASS(RuntimeError)
};
static const JSFunctionSpec exception_methods[] = {
static const JSFunctionSpec error_methods[] = {
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, exn_toSource, 0, 0),
#endif
@ -67,6 +84,92 @@ static const JSFunctionSpec exception_methods[] = {
JS_FS_END
};
static const JSPropertySpec error_properties[] = {
JS_STRING_PS("message", "", 0),
JS_STRING_PS("name", "Error", 0),
// Only Error.prototype has .stack!
JS_PSGS("stack", ErrorObject::getStack, ErrorObject::setStack, 0),
JS_PS_END
};
#define IMPLEMENT_ERROR_PROPERTIES(name) \
{ \
JS_STRING_PS("message", "", 0), \
JS_STRING_PS("name", #name, 0), \
JS_PS_END \
}
static const JSPropertySpec other_error_properties[JSEXN_ERROR_LIMIT - 1][3] = {
IMPLEMENT_ERROR_PROPERTIES(InternalError),
IMPLEMENT_ERROR_PROPERTIES(EvalError),
IMPLEMENT_ERROR_PROPERTIES(RangeError),
IMPLEMENT_ERROR_PROPERTIES(ReferenceError),
IMPLEMENT_ERROR_PROPERTIES(SyntaxError),
IMPLEMENT_ERROR_PROPERTIES(TypeError),
IMPLEMENT_ERROR_PROPERTIES(URIError),
IMPLEMENT_ERROR_PROPERTIES(DebuggeeWouldRun),
IMPLEMENT_ERROR_PROPERTIES(CompileError),
IMPLEMENT_ERROR_PROPERTIES(RuntimeError)
};
#define IMPLEMENT_NATIVE_ERROR_SPEC(name) \
{ \
ErrorObject::createConstructor, \
ErrorObject::createProto, \
nullptr, \
nullptr, \
nullptr, \
other_error_properties[JSProto_##name - JSProto_Error - 1], \
nullptr, \
JSProto_Error \
}
#define IMPLEMENT_NONGLOBAL_ERROR_SPEC(name) \
{ \
ErrorObject::createConstructor, \
ErrorObject::createProto, \
nullptr, \
nullptr, \
nullptr, \
other_error_properties[JSProto_##name - JSProto_Error - 1], \
nullptr, \
JSProto_Error | ClassSpec::DontDefineConstructor \
}
const ClassSpec
ErrorObject::classSpecs[JSEXN_ERROR_LIMIT] = {
{
ErrorObject::createConstructor,
ErrorObject::createProto,
nullptr,
nullptr,
error_methods,
error_properties
},
IMPLEMENT_NATIVE_ERROR_SPEC(InternalError),
IMPLEMENT_NATIVE_ERROR_SPEC(EvalError),
IMPLEMENT_NATIVE_ERROR_SPEC(RangeError),
IMPLEMENT_NATIVE_ERROR_SPEC(ReferenceError),
IMPLEMENT_NATIVE_ERROR_SPEC(SyntaxError),
IMPLEMENT_NATIVE_ERROR_SPEC(TypeError),
IMPLEMENT_NATIVE_ERROR_SPEC(URIError),
IMPLEMENT_NONGLOBAL_ERROR_SPEC(DebuggeeWouldRun),
IMPLEMENT_NONGLOBAL_ERROR_SPEC(CompileError),
IMPLEMENT_NONGLOBAL_ERROR_SPEC(RuntimeError)
};
#define IMPLEMENT_ERROR_CLASS(name) \
{ \
js_Error_str, /* yes, really */ \
JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS) | \
JSCLASS_BACKGROUND_FINALIZE, \
&ErrorObjectClassOps, \
&ErrorObject::classSpecs[JSProto_##name - JSProto_Error ] \
}
static const ClassOps ErrorObjectClassOps = {
nullptr, /* addProperty */
nullptr, /* delProperty */
@ -82,67 +185,20 @@ static const ClassOps ErrorObjectClassOps = {
nullptr, /* trace */
};
#define IMPLEMENT_ERROR_CLASS(name, classSpecPtr) \
{ \
js_Error_str, /* yes, really */ \
JSCLASS_HAS_CACHED_PROTO(JSProto_##name) | \
JSCLASS_HAS_RESERVED_SLOTS(ErrorObject::RESERVED_SLOTS) | \
JSCLASS_BACKGROUND_FINALIZE, \
&ErrorObjectClassOps, \
classSpecPtr \
}
const ClassSpec
ErrorObject::errorClassSpec_ = {
ErrorObject::createConstructor,
ErrorObject::createProto,
nullptr,
nullptr,
exception_methods,
exception_properties,
nullptr,
0
};
const ClassSpec
ErrorObject::subErrorClassSpec_ = {
ErrorObject::createConstructor,
ErrorObject::createProto,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr,
JSProto_Error
};
const ClassSpec
ErrorObject::nonGlobalErrorClassSpec_ = {
ErrorObject::createConstructor,
ErrorObject::createProto,
nullptr,
nullptr,
exception_methods,
exception_properties,
nullptr,
JSProto_Error | ClassSpec::DontDefineConstructor
};
const Class
ErrorObject::classes[JSEXN_LIMIT] = {
IMPLEMENT_ERROR_CLASS(Error, &ErrorObject::errorClassSpec_),
IMPLEMENT_ERROR_CLASS(InternalError, &ErrorObject::subErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(EvalError, &ErrorObject::subErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(RangeError, &ErrorObject::subErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(ReferenceError, &ErrorObject::subErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(SyntaxError, &ErrorObject::subErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(TypeError, &ErrorObject::subErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(URIError, &ErrorObject::subErrorClassSpec_),
ErrorObject::classes[JSEXN_ERROR_LIMIT] = {
IMPLEMENT_ERROR_CLASS(Error),
IMPLEMENT_ERROR_CLASS(InternalError),
IMPLEMENT_ERROR_CLASS(EvalError),
IMPLEMENT_ERROR_CLASS(RangeError),
IMPLEMENT_ERROR_CLASS(ReferenceError),
IMPLEMENT_ERROR_CLASS(SyntaxError),
IMPLEMENT_ERROR_CLASS(TypeError),
IMPLEMENT_ERROR_CLASS(URIError),
// These Error subclasses are not accessible via the global object:
IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun, &ErrorObject::nonGlobalErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(CompileError, &ErrorObject::nonGlobalErrorClassSpec_),
IMPLEMENT_ERROR_CLASS(RuntimeError, &ErrorObject::nonGlobalErrorClassSpec_)
IMPLEMENT_ERROR_CLASS(DebuggeeWouldRun),
IMPLEMENT_ERROR_CLASS(CompileError),
IMPLEMENT_ERROR_CLASS(RuntimeError)
};
JSErrorReport*
@ -454,35 +510,40 @@ exn_toSource(JSContext* cx, unsigned argc, Value* vp)
/* static */ JSObject*
ErrorObject::createProto(JSContext* cx, JSProtoKey key)
{
RootedObject errorProto(cx, GenericCreatePrototype(cx, key));
if (!errorProto)
return nullptr;
Rooted<ErrorObject*> err(cx, &errorProto->as<ErrorObject>());
RootedString emptyStr(cx, cx->names().empty);
JSExnType type = ExnTypeFromProtoKey(key);
if (!ErrorObject::init(cx, err, type, nullptr, emptyStr, nullptr, 0, 0, emptyStr))
if (type == JSEXN_ERR)
return cx->global()->createBlankPrototype(cx, &ErrorObject::protoClasses[JSEXN_ERR]);
RootedObject protoProto(cx, GlobalObject::getOrCreateErrorPrototype(cx, cx->global()));
if (!protoProto)
return nullptr;
// The various prototypes also have .name in addition to the normal error
// instance properties.
RootedPropertyName name(cx, ClassName(key, cx));
RootedValue nameValue(cx, StringValue(name));
if (!DefineProperty(cx, err, cx->names().name, nameValue, nullptr, nullptr, 0))
return nullptr;
return errorProto;
return cx->global()->createBlankPrototypeInheriting(cx, &ErrorObject::protoClasses[type],
protoProto);
}
/* static */ JSObject*
ErrorObject::createConstructor(JSContext* cx, JSProtoKey key)
{
JSExnType type = ExnTypeFromProtoKey(key);
RootedObject ctor(cx);
ctor = GenericCreateConstructor<Error, 1, gc::AllocKind::FUNCTION_EXTENDED>(cx, key);
if (type == JSEXN_ERR) {
ctor = GenericCreateConstructor<Error, 1, gc::AllocKind::FUNCTION_EXTENDED>(cx, key);
} else {
RootedFunction proto(cx, GlobalObject::getOrCreateErrorConstructor(cx, cx->global()));
if (!proto)
return nullptr;
ctor = NewFunctionWithProto(cx, Error, 1, JSFunction::NATIVE_CTOR, nullptr,
ClassName(key, cx), proto, gc::AllocKind::FUNCTION_EXTENDED);
}
if (!ctor)
return nullptr;
ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(ExnTypeFromProtoKey(key)));
ctor->as<JSFunction>().setExtendedSlot(0, Int32Value(type));
return ctor;
}

View File

@ -85,10 +85,17 @@ ExnTypeFromProtoKey(JSProtoKey key)
{
JSExnType type = static_cast<JSExnType>(key - JSProto_Error);
MOZ_ASSERT(type >= JSEXN_ERR);
MOZ_ASSERT(type < JSEXN_WARN);
MOZ_ASSERT(type < JSEXN_ERROR_LIMIT);
return type;
}
static inline bool
IsErrorProtoKey(JSProtoKey key)
{
JSExnType type = static_cast<JSExnType>(key - JSProto_Error);
return type >= JSEXN_ERR && type < JSEXN_ERROR_LIMIT;
}
class AutoClearPendingException
{
JSContext* cx;

View File

@ -12,6 +12,7 @@
#include "mozilla/ArrayUtils.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/Maybe.h"
#include "mozilla/PodOperations.h"
#include "mozilla/Range.h"
@ -60,8 +61,10 @@ using namespace js::gc;
using namespace js::frontend;
using mozilla::ArrayLength;
using mozilla::Maybe;
using mozilla::PodCopy;
using mozilla::RangedPtr;
using mozilla::Some;
static bool
fun_enumerate(JSContext* cx, HandleObject obj)
@ -933,19 +936,19 @@ const Class JSFunction::class_ = {
const Class* const js::FunctionClassPtr = &JSFunction::class_;
JSString*
js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
js::FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPrint)
{
if (fun->isInterpretedLazy() && !fun->getOrCreateScript(cx))
return nullptr;
if (IsAsmJSModule(fun))
return AsmJSModuleToString(cx, fun, !lambdaParen);
return AsmJSModuleToString(cx, fun, !prettyPrint);
if (IsAsmJSFunction(fun))
return AsmJSFunctionToString(cx, fun);
if (IsWrappedAsyncFunction(fun)) {
RootedFunction unwrapped(cx, GetUnwrappedAsyncFunction(fun));
return FunctionToString(cx, unwrapped, lambdaParen);
return FunctionToString(cx, unwrapped, prettyPrint);
}
StringBuffer out(cx);
@ -971,11 +974,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
bool funIsMethodOrNonArrowLambda = (fun->isLambda() && !fun->isArrow()) || fun->isMethod() ||
fun->isGetter() || fun->isSetter();
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
// If we're not in pretty mode, put parentheses around lambda functions and methods.
if (fun->isInterpreted() && !lambdaParen && funIsMethodOrNonArrowLambda &&
!fun->isSelfHostedBuiltin())
{
if (haveSource && !prettyPrint && funIsMethodOrNonArrowLambda) {
if (!out.append("("))
return nullptr;
}
@ -993,7 +995,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
return nullptr;
}
bool haveSource = fun->isInterpreted() && !fun->isSelfHostedBuiltin();
if (haveSource && !script->scriptSource()->hasSourceData() &&
!JSScript::loadSource(cx, script->scriptSource(), &haveSource))
{
@ -1004,54 +1005,10 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
if (!src)
return nullptr;
// The source data for functions created by calling the Function
// constructor is only the function's body. This depends on the fact,
// asserted below, that in Function("function f() {}"), the inner
// function's sourceStart points to the '(', not the 'f'.
bool funCon = !fun->isArrow() &&
script->sourceStart() == 0 &&
script->sourceEnd() == script->scriptSource()->length() &&
script->scriptSource()->argumentsNotIncluded();
// Functions created with the constructor can't be arrow functions or
// expression closures.
MOZ_ASSERT_IF(funCon, !fun->isArrow());
MOZ_ASSERT_IF(funCon, !fun->isExprBody());
MOZ_ASSERT_IF(!funCon && !fun->isArrow(),
src->length() > 0 && src->latin1OrTwoByteChar(0) == '(');
bool buildBody = funCon;
if (buildBody) {
// This function was created with the Function constructor. We don't
// have source for the arguments, so we have to generate that. Part
// of bug 755821 should be cobbling the arguments passed into the
// Function constructor into the source string.
if (!out.append("("))
return nullptr;
// Fish out the argument names.
MOZ_ASSERT(script->numArgs() == fun->nargs());
BindingIter bi(script);
for (unsigned i = 0; i < fun->nargs(); i++, bi++) {
MOZ_ASSERT(bi.argumentSlot() == i);
if (i && !out.append(", "))
return nullptr;
if (i == unsigned(fun->nargs() - 1) && fun->hasRest() && !out.append("..."))
return nullptr;
if (!out.append(bi.name()))
return nullptr;
}
if (!out.append(") {\n"))
return nullptr;
}
if (!out.append(src))
return nullptr;
if (buildBody) {
if (!out.append("\n}"))
return nullptr;
}
if (!lambdaParen && funIsMethodOrNonArrowLambda) {
if (!prettyPrint && funIsMethodOrNonArrowLambda) {
if (!out.append(")"))
return nullptr;
}
@ -1062,8 +1019,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen)
{
return nullptr;
}
if (!lambdaParen && fun->isLambda() && !fun->isArrow() && !out.append(")"))
return nullptr;
} else {
MOZ_ASSERT(!fun->isExprBody());
@ -1605,17 +1560,6 @@ fun_isGenerator(JSContext* cx, unsigned argc, Value* vp)
return true;
}
/*
* Report "malformed formal parameter" iff no illegal char or similar scanner
* error was already reported.
*/
static bool
OnBadFormal(JSContext* cx)
{
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_BAD_FORMAL);
return false;
}
const JSFunctionSpec js::function_methods[] = {
#if JS_HAS_TOSOURCE
JS_FN(js_toSource_str, fun_toSource, 0,0),
@ -1629,11 +1573,12 @@ const JSFunctionSpec js::function_methods[] = {
JS_FS_END
};
// ES 2017 draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077 19.2.1.1.1.
static bool
FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generatorKind,
FunctionAsyncKind asyncKind)
{
/* Block this call if security callbacks forbid it. */
// Block this call if security callbacks forbid it.
Rooted<GlobalObject*> global(cx, &args.callee().global());
if (!GlobalObject::isRuntimeCodeGenEnabled(cx, global)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_CSP_BLOCKED_FUNCTION);
@ -1665,83 +1610,66 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
introducerFilename = maybeScript->scriptSource()->introducerFilename();
CompileOptions options(cx);
// Use line 0 to make the function body starts from line 1.
options.setMutedErrors(mutedErrors)
.setFileAndLine(filename, 1)
.setFileAndLine(filename, 0)
.setNoScriptRval(false)
.setIntroductionInfo(introducerFilename, introductionType, lineno, maybeScript, pcOffset);
Vector<char16_t> paramStr(cx);
RootedString bodyText(cx);
StringBuffer sb(cx);
if (args.length() == 0) {
bodyText = cx->names().empty;
} else {
// Collect the function-argument arguments into one string, separated
// by commas, then make a tokenstream from that string, and scan it to
// get the arguments. We need to throw the full scanner at the
// problem because the argument string may contain comments, newlines,
// destructuring arguments, and similar manner of insanities. ("I have
// a feeling we're not in simple-comma-separated-parameters land any
// more, Toto....")
//
// XXX It'd be better if the parser provided utility methods to parse
// an argument list, and to parse a function body given a parameter
// list. But our parser provides no such pleasant interface now.
if (!sb.append('('))
return false;
if (args.length() > 1) {
RootedString str(cx);
// Steps 5-6, 9.
unsigned n = args.length() - 1;
// Convert the parameters-related arguments to strings, and determine
// the length of the string containing the overall parameter list.
mozilla::CheckedInt<uint32_t> paramStrLen = 0;
RootedString str(cx);
for (unsigned i = 0; i < n; i++) {
// Steps 9.a-b, 9.d.i-ii.
str = ToString<CanGC>(cx, args[i]);
if (!str)
return false;
args[i].setString(str);
paramStrLen += str->length();
// Steps 9.b, 9.d.iii.
if (!sb.append(str))
return false;
if (i < args.length() - 2) {
// Step 9.d.iii.
if (!sb.append(", "))
return false;
}
}
// Tack in space for any combining commas.
if (n > 0)
paramStrLen += n - 1;
// Check for integer and string-size overflow.
if (!paramStrLen.isValid() || paramStrLen.value() > JSString::MAX_LENGTH) {
ReportAllocationOverflow(cx);
return false;
}
uint32_t paramsLen = paramStrLen.value();
// Fill a vector with the comma-joined arguments. Careful! This
// string is *not* null-terminated!
MOZ_ASSERT(paramStr.length() == 0);
if (!paramStr.growBy(paramsLen)) {
ReportOutOfMemory(cx);
return false;
}
char16_t* cp = paramStr.begin();
for (unsigned i = 0; i < n; i++) {
JSLinearString* argLinear = args[i].toString()->ensureLinear(cx);
if (!argLinear)
return false;
CopyChars(cp, *argLinear);
cp += argLinear->length();
if (i + 1 < n)
*cp++ = ',';
}
MOZ_ASSERT(cp == paramStr.end());
bodyText = ToString(cx, args[n]);
if (!bodyText)
return false;
}
// Remember the position of ")".
Maybe<uint32_t> parameterListEnd = Some(uint32_t(sb.length()));
MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
if (!sb.append(FunctionConstructorMedialSigils))
return false;
if (args.length() > 0) {
// Steps 7-8, 10.
RootedString body(cx, ToString<CanGC>(cx, args[args.length() - 1]));
if (!body || !sb.append(body))
return false;
}
if (!sb.append(FunctionConstructorFinalBrace))
return false;
// The parser only accepts two byte strings.
if (!sb.ensureTwoByteChars())
return false;
RootedString functionText(cx, sb.finishString());
if (!functionText)
return false;
/*
* NB: (new Function) is not lexically closed by its caller, it's just an
* anonymous function in the top-level scope that its constructor inhabits.
@ -1750,24 +1678,22 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
*/
RootedAtom anonymousAtom(cx, cx->names().anonymous);
// ES2017, draft rev 0f10dba4ad18de92d47d421f378233a2eae8f077
// 19.2.1.1.1 Runtime Semantics: CreateDynamicFunction, step 24.
// Step 24.
RootedObject proto(cx);
if (!isAsync) {
if (!GetPrototypeFromCallableConstructor(cx, args, &proto))
return false;
}
// 19.2.1.1.1, step 4.d, use %Generator% as the fallback prototype.
// Step 4.d, use %Generator% as the fallback prototype.
// Also use %Generator% for the unwrapped function of async functions.
if (!proto && isStarGenerator) {
// Unwrapped function of async function should use GeneratorFunction,
// while wrapped function isn't generator.
proto = GlobalObject::getOrCreateStarGeneratorFunctionPrototype(cx, global);
if (!proto)
return false;
}
// Step 25-32 (reordered).
RootedObject globalLexical(cx, &global->lexicalEnvironment());
AllocKind allocKind = isAsync ? AllocKind::FUNCTION_EXTENDED : AllocKind::FUNCTION;
RootedFunction fun(cx, NewFunctionWithProto(cx, nullptr, 0,
@ -1780,81 +1706,11 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
if (!JSFunction::setTypeForScriptedFunction(cx, fun))
return false;
// Steps 2.a-b, 3.a-b, 4.a-b, 11-23.
AutoStableStringChars stableChars(cx);
if (!stableChars.initTwoByte(cx, bodyText))
if (!stableChars.initTwoByte(cx, functionText))
return false;
bool hasRest = false;
Rooted<PropertyNameVector> formals(cx, PropertyNameVector(cx));
if (args.length() > 1) {
// Initialize a tokenstream to parse the new function's arguments. No
// StrictModeGetter is needed because this TokenStream won't report any
// strict mode errors. Strict mode errors that might be reported here
// (duplicate argument names, etc.) will be detected when we compile
// the function body.
//
// XXX Bug! We have to parse the body first to determine strictness.
// We have to know strictness to parse arguments correctly, in case
// arguments contains a strict mode violation. And we should be
// using full-fledged arguments parsing here, in order to handle
// destructuring and other exotic syntaxes.
AutoKeepAtoms keepAtoms(cx->perThreadData);
TokenStream ts(cx, options, paramStr.begin(), paramStr.length(),
/* strictModeGetter = */ nullptr);
bool yieldIsValidName = ts.versionNumber() < JSVERSION_1_7 && !isStarGenerator;
// The argument string may be empty or contain no tokens.
TokenKind tt;
if (!ts.getToken(&tt))
return false;
if (tt != TOK_EOF) {
while (true) {
// Check that it's a name.
if (hasRest) {
ts.reportError(JSMSG_PARAMETER_AFTER_REST);
return false;
}
if (tt == TOK_YIELD && yieldIsValidName)
tt = TOK_NAME;
if (tt != TOK_NAME) {
if (tt == TOK_TRIPLEDOT) {
hasRest = true;
if (!ts.getToken(&tt))
return false;
if (tt == TOK_YIELD && yieldIsValidName)
tt = TOK_NAME;
if (tt != TOK_NAME) {
ts.reportError(JSMSG_NO_REST_NAME);
return false;
}
} else {
return OnBadFormal(cx);
}
}
if (!formals.append(ts.currentName()))
return false;
// Get the next token. Stop on end of stream. Otherwise
// insist on a comma, get another name, and iterate.
if (!ts.getToken(&tt))
return false;
if (tt == TOK_EOF)
break;
if (tt != TOK_COMMA)
return OnBadFormal(cx);
if (!ts.getToken(&tt))
return false;
}
}
}
if (hasRest)
fun->setHasRest();
mozilla::Range<const char16_t> chars = stableChars.twoByteRange();
SourceBufferHolder::Ownership ownership = stableChars.maybeGiveOwnershipToCaller()
? SourceBufferHolder::GiveOwnership
@ -1862,11 +1718,13 @@ FunctionConstructor(JSContext* cx, const CallArgs& args, GeneratorKind generator
bool ok;
SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), ownership);
if (isAsync)
ok = frontend::CompileAsyncFunctionBody(cx, &fun, options, formals, srcBuf);
ok = frontend::CompileStandaloneAsyncFunction(cx, &fun, options, srcBuf, parameterListEnd);
else if (isStarGenerator)
ok = frontend::CompileStarGeneratorBody(cx, &fun, options, formals, srcBuf);
ok = frontend::CompileStandaloneGenerator(cx, &fun, options, srcBuf, parameterListEnd);
else
ok = frontend::CompileFunctionBody(cx, &fun, options, formals, srcBuf);
ok = frontend::CompileStandaloneFunction(cx, &fun, options, srcBuf, parameterListEnd);
// Step 33.
args.rval().setObject(*fun);
return ok;
}

View File

@ -28,6 +28,9 @@ static const uint32_t JSSLOT_BOUND_FUNCTION_TARGET = 2;
static const uint32_t JSSLOT_BOUND_FUNCTION_THIS = 3;
static const uint32_t JSSLOT_BOUND_FUNCTION_ARGS = 4;
static const char FunctionConstructorMedialSigils[] = ") {\n";
static const char FunctionConstructorFinalBrace[] = "\n}";
class JSFunction : public js::NativeObject
{
public:
@ -812,7 +815,7 @@ JSFunction::getExtendedSlot(size_t which) const
namespace js {
JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen);
JSString* FunctionToString(JSContext* cx, HandleFunction fun, bool prettyPring);
template<XDRMode mode>
bool

View File

@ -1689,20 +1689,11 @@ GCMarker::delayMarkingChildren(const void* thing)
}
inline void
ArenaLists::prepareForIncrementalGC(JSRuntime* rt)
ArenaLists::prepareForIncrementalGC()
{
for (auto i : AllAllocKinds()) {
FreeSpan* span = freeLists[i];
if (span != &placeholder) {
if (!span->isEmpty()) {
Arena* arena = span->getArena();
arena->allocatedDuringIncremental = true;
rt->gc.marker.delayMarkingArena(arena);
} else {
freeLists[i] = &placeholder;
}
}
}
purge();
for (auto i : AllAllocKinds())
arenaLists[i].moveCursorToEnd();
}
/* Compacting GC */
@ -3760,6 +3751,23 @@ RelazifyFunctions(Zone* zone, AllocKind kind)
}
}
static bool
ShouldCollectZone(Zone* zone, JS::gcreason::Reason reason)
{
// Normally we collect all scheduled zones.
if (reason != JS::gcreason::COMPARTMENT_REVIVED)
return zone->isGCScheduled();
// If we are repeating a GC becuase we noticed dead compartments haven't
// been collected, then only collect zones contianing those compartments.
for (CompartmentsInZoneIter comp(zone); !comp.done(); comp.next()) {
if (comp->scheduledForDestruction)
return true;
}
return false;
}
bool
GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAccess& lock)
{
@ -3783,7 +3791,7 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
#endif
/* Set up which zones will be collected. */
if (zone->isGCScheduled()) {
if (ShouldCollectZone(zone, reason)) {
if (!zone->isAtomsZone()) {
any = true;
zone->setGCState(Zone::Mark);
@ -3832,15 +3840,12 @@ GCRuntime::beginMarkPhase(JS::gcreason::Reason reason, AutoLockForExclusiveAcces
return false;
/*
* At the end of each incremental slice, we call prepareForIncrementalGC,
* which marks objects in all arenas that we're currently allocating
* into. This can cause leaks if unreachable objects are in these
* arenas. This purge call ensures that we only mark arenas that have had
* allocations after the incremental GC started.
* Ensure that after the start of a collection we don't allocate into any
* existing arenas, as this can cause unreachable things to be marked.
*/
if (isIncremental) {
for (GCZonesIter zone(rt); !zone.done(); zone.next())
zone->arenas.purge();
zone->arenas.prepareForIncrementalGC();
}
MemProfiler::MarkTenuredStart(rt);
@ -5759,7 +5764,7 @@ AutoGCSlice::~AutoGCSlice()
for (ZonesIter zone(runtime, WithAtoms); !zone.done(); zone.next()) {
if (zone->isGCMarking()) {
zone->setNeedsIncrementalBarrier(true, Zone::UpdateJit);
zone->arenas.prepareForIncrementalGC(runtime);
zone->arenas.purge();
} else {
zone->setNeedsIncrementalBarrier(false, Zone::UpdateJit);
}
@ -5999,9 +6004,17 @@ gc::IsIncrementalGCUnsafe(JSRuntime* rt)
}
void
GCRuntime::budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess& lock)
GCRuntime::budgetIncrementalGC(JS::gcreason::Reason reason, SliceBudget& budget,
AutoLockForExclusiveAccess& lock)
{
AbortReason unsafeReason = IsIncrementalGCUnsafe(rt);
if (unsafeReason == AbortReason::None) {
if (reason == JS::gcreason::COMPARTMENT_REVIVED)
unsafeReason = gc::AbortReason::CompartmentRevived;
else if (mode != JSGC_MODE_INCREMENTAL)
unsafeReason = gc::AbortReason::ModeChange;
}
if (unsafeReason != AbortReason::None) {
resetIncrementalGC(unsafeReason, lock);
budget.makeUnlimited();
@ -6009,13 +6022,6 @@ GCRuntime::budgetIncrementalGC(SliceBudget& budget, AutoLockForExclusiveAccess&
return;
}
if (mode != JSGC_MODE_INCREMENTAL) {
resetIncrementalGC(AbortReason::ModeChange, lock);
budget.makeUnlimited();
stats.nonincremental(AbortReason::ModeChange);
return;
}
if (isTooMuchMalloc()) {
budget.makeUnlimited();
stats.nonincremental(AbortReason::MallocBytesTrigger);
@ -6173,7 +6179,7 @@ GCRuntime::gcCycle(bool nonincrementalByAPI, SliceBudget& budget, JS::gcreason::
stats.nonincremental(gc::AbortReason::NonIncrementalRequested);
budget.makeUnlimited();
} else {
budgetIncrementalGC(budget, session.lock);
budgetIncrementalGC(reason, budget, session.lock);
}
/* The GC was reset, so we need a do-over. */
@ -6292,6 +6298,22 @@ GCRuntime::checkIfGCAllowedInCurrentState(JS::gcreason::Reason reason)
return true;
}
bool
GCRuntime::shouldRepeatForDeadZone(JS::gcreason::Reason reason)
{
MOZ_ASSERT_IF(reason == JS::gcreason::COMPARTMENT_REVIVED, !isIncremental);
if (!isIncremental || isIncrementalGCInProgress())
return false;
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
if (c->scheduledForDestruction)
return true;
}
return false;
}
void
GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::Reason reason)
{
@ -6322,25 +6344,18 @@ GCRuntime::collect(bool nonincrementalByAPI, SliceBudget budget, JS::gcreason::R
poked = false;
bool wasReset = gcCycle(nonincrementalByAPI, budget, reason);
/* Need to re-schedule all zones for GC. */
if (poked && cleanUpEverything)
JS::PrepareForFullGC(rt->contextFromMainThread());
/*
* This code makes an extra effort to collect compartments that we
* thought were dead at the start of the GC. See the large comment in
* beginMarkPhase.
*/
bool repeatForDeadZone = false;
if (!nonincrementalByAPI && !isIncrementalGCInProgress()) {
for (CompartmentsIter c(rt, SkipAtoms); !c.done(); c.next()) {
if (c->scheduledForDestruction) {
nonincrementalByAPI = true;
repeatForDeadZone = true;
reason = JS::gcreason::COMPARTMENT_REVIVED;
c->zone()->scheduleGC();
}
}
if (poked && cleanUpEverything) {
/* Need to re-schedule all zones for GC. */
JS::PrepareForFullGC(rt->contextFromMainThread());
} else if (shouldRepeatForDeadZone(reason) && !wasReset) {
/*
* This code makes an extra effort to collect compartments that we
* thought were dead at the start of the GC. See the large comment
* in beginMarkPhase.
*/
repeatForDeadZone = true;
reason = JS::gcreason::COMPARTMENT_REVIVED;
}
/*

View File

@ -60,7 +60,8 @@ enum class State {
D(ModeChange) \
D(MallocBytesTrigger) \
D(GCBytesTrigger) \
D(ZoneChange)
D(ZoneChange) \
D(CompartmentRevived)
enum class AbortReason {
#define MAKE_REASON(name) name,
GC_ABORT_REASONS(MAKE_REASON)
@ -449,6 +450,11 @@ class ArenaList {
return !*cursorp_;
}
void moveCursorToEnd() {
while (!isCursorAtEnd())
cursorp_ = &(*cursorp_)->next;
}
// This can return nullptr.
Arena* arenaAfterCursor() const {
check();
@ -734,7 +740,7 @@ class ArenaLists
freeLists[i] = &placeholder;
}
inline void prepareForIncrementalGC(JSRuntime* rt);
inline void prepareForIncrementalGC();
/* Check if this arena is in use. */
bool arenaIsInUse(Arena* arena, AllocKind kind) const {

View File

@ -470,7 +470,7 @@ js::SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level)
// Steps 8-9, loosely interpreted.
if (obj->isNative() && !obj->as<NativeObject>().inDictionaryMode() &&
!obj->is<TypedArrayObject>())
!obj->is<TypedArrayObject>() && !obj->is<MappedArgumentsObject>())
{
HandleNativeObject nobj = obj.as<NativeObject>();

View File

@ -1675,6 +1675,16 @@ ScriptSource::substringDontDeflate(JSContext* cx, size_t start, size_t stop)
return NewStringCopyNDontDeflate<CanGC>(cx, chars, len);
}
JSFlatString*
ScriptSource::functionBodyString(JSContext* cx)
{
MOZ_ASSERT(isFunctionBody());
size_t start = parameterListEnd_ + (sizeof(FunctionConstructorMedialSigils) - 1);
size_t stop = length() - (sizeof(FunctionConstructorFinalBrace) - 1);
return substring(cx, start, stop);
}
MOZ_MUST_USE bool
ScriptSource::setSource(ExclusiveContext* cx,
mozilla::UniquePtr<char16_t[], JS::FreePolicy>&& source,
@ -1726,10 +1736,9 @@ ScriptSource::setCompressedSource(SharedImmutableString&& raw, size_t uncompress
bool
ScriptSource::setSourceCopy(ExclusiveContext* cx, SourceBufferHolder& srcBuf,
bool argumentsNotIncluded, SourceCompressionTask* task)
SourceCompressionTask* task)
{
MOZ_ASSERT(!hasSourceData());
argumentsNotIncluded_ = argumentsNotIncluded;
auto& cache = cx->zone()->runtimeFromAnyThread()->sharedImmutableStrings();
auto deduped = cache.getOrCreate(srcBuf.get(), srcBuf.length(), [&]() {
@ -1926,16 +1935,6 @@ ScriptSource::performXDR(XDRState<mode>* xdr)
if (!xdr->codeUint32(&compressedLength))
return false;
{
uint8_t argumentsNotIncluded;
if (mode == XDR_ENCODE)
argumentsNotIncluded = argumentsNotIncluded_;
if (!xdr->codeUint8(&argumentsNotIncluded))
return false;
if (mode == XDR_DECODE)
argumentsNotIncluded_ = argumentsNotIncluded;
}
size_t byteLen = compressedLength ? compressedLength : (len * sizeof(char16_t));
if (mode == XDR_DECODE) {
uint8_t* p = xdr->cx()->template pod_malloc<uint8_t>(Max<size_t>(byteLen, 1));
@ -2060,7 +2059,8 @@ FormatIntroducedFilename(ExclusiveContext* cx, const char* filename, unsigned li
}
bool
ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options)
ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions& options,
Maybe<uint32_t> parameterListEnd)
{
MOZ_ASSERT(!filename_);
MOZ_ASSERT(!introducerFilename_);
@ -2069,6 +2069,7 @@ ScriptSource::initFromOptions(ExclusiveContext* cx, const ReadOnlyCompileOptions
introductionType_ = options.introductionType;
setIntroductionOffset(options.introductionOffset);
parameterListEnd_ = parameterListEnd.isSome() ? parameterListEnd.value() : 0;
if (options.hasIntroductionInfo) {
MOZ_ASSERT(options.introductionType != nullptr);

Some files were not shown because too many files have changed in this diff Show More