mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 05:41:12 +00:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
14e0b51ace
@ -106,7 +106,7 @@ public:
|
||||
bool HasAccessible(nsIDOMNode* aDOMNode);
|
||||
|
||||
/**
|
||||
* Get a string equivalent for an accessilbe role value.
|
||||
* Get a string equivalent for an accessible role value.
|
||||
*/
|
||||
void GetStringRole(uint32_t aRole, nsAString& aString);
|
||||
|
||||
|
@ -2135,7 +2135,8 @@ Accessible::RemoveChild(Accessible* aChild)
|
||||
MOZ_DIAGNOSTIC_ASSERT(aChild->mParent, "No parent");
|
||||
MOZ_DIAGNOSTIC_ASSERT(aChild->mParent == this, "Wrong parent");
|
||||
MOZ_DIAGNOSTIC_ASSERT(aChild->mIndexInParent != -1, "Unbound child was given");
|
||||
MOZ_DIAGNOSTIC_ASSERT((mStateFlags & eKidsMutating) || aChild->IsDefunct() || aChild->IsDoc(),
|
||||
MOZ_DIAGNOSTIC_ASSERT((mStateFlags & eKidsMutating) || aChild->IsDefunct() ||
|
||||
aChild->IsDoc() || IsApplication(),
|
||||
"Illicit children change");
|
||||
|
||||
int32_t index = static_cast<uint32_t>(aChild->mIndexInParent);
|
||||
|
@ -288,7 +288,7 @@ this.EventManager.prototype = {
|
||||
{
|
||||
let position = this.contentControl.vc.position;
|
||||
// Check if position is in the subtree of the DOCUMENT_LOAD_COMPLETE
|
||||
// event's dialog accesible or accessible document
|
||||
// event's dialog accessible or accessible document
|
||||
let subtreeRoot = aEvent.accessible.role === Roles.DIALOG ?
|
||||
aEvent.accessible : aEvent.accessibleDocument;
|
||||
if (aEvent.accessible === aEvent.accessibleDocument ||
|
||||
|
@ -133,7 +133,7 @@ function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
|
||||
var startOffset = { value: -1 };
|
||||
var endOffset = { value: -1 };
|
||||
|
||||
// do not include attributes exposed on hyper text accessbile
|
||||
// do not include attributes exposed on hyper text accessible
|
||||
var attrs = getTextAttributes(aID, accessible, false, aOffset,
|
||||
startOffset, endOffset);
|
||||
|
||||
@ -147,7 +147,7 @@ function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
|
||||
|
||||
compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs);
|
||||
|
||||
// include attributes exposed on hyper text accessbile
|
||||
// include attributes exposed on hyper text accessible
|
||||
var expectedAttrs = {};
|
||||
for (var name in aAttrs)
|
||||
expectedAttrs[name] = aAttrs[name];
|
||||
|
@ -72,7 +72,7 @@
|
||||
Initially 'markup' element holds markup for all rules specified by 'ruleset'
|
||||
attribute. This allows us to check if the sequence of name computation rules
|
||||
is correct. Here 'ruleset' element defines two rules. We get the first rule
|
||||
which means accesible name is computed from value of 'aria-label' attribute.
|
||||
which means accessible name is computed from value of 'aria-label' attribute.
|
||||
Then we check accessible name for the test element and remove 'aria-label'
|
||||
attribute. After we get the second rule which means we should get IDs from
|
||||
'aria-labelledby' attribute and compose accessible name from values of
|
||||
|
@ -162,7 +162,7 @@ function testStates(aAccOrElmOrID, aState, aExtraState, aAbsentState,
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests an acessible and its sub tree for the passed in state bits.
|
||||
* Tests an accessible and its sub tree for the passed in state bits.
|
||||
* Used to make sure that states are propagated to descendants, for example the
|
||||
* STATE_UNAVAILABLE from a container to its children.
|
||||
*
|
||||
|
@ -102,7 +102,7 @@ function emitOnObject(target, type, thisArg, ...args) {
|
||||
let count = listenerCount;
|
||||
for (let [listener, added] of listeners)
|
||||
try {
|
||||
// Since our contract unfortuantely requires that we not dispatch to
|
||||
// Since our contract unfortunately requires that we not dispatch to
|
||||
// this event to listeners that were either added or removed during this
|
||||
// dispatch, we need to check when each listener was added.
|
||||
if (added >= count)
|
||||
|
@ -1149,8 +1149,6 @@
|
||||
}
|
||||
|
||||
if (!this._previewMode) {
|
||||
this._recordTabAccess(this.mCurrentTab);
|
||||
|
||||
this.mCurrentTab.updateLastAccessed();
|
||||
this.mCurrentTab.removeAttribute("unread");
|
||||
oldTab.updateLastAccessed();
|
||||
@ -1344,45 +1342,6 @@
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
This function assumes we have an LRU cache of tabs (either
|
||||
images of tab content or their layers). The goal is to find
|
||||
out how far into the cache we need to look in order to find
|
||||
aTab. We record this number in telemetry and also move aTab to
|
||||
the front of the cache.
|
||||
|
||||
A newly created tab has position Infinity in the cache.
|
||||
If a tab is closed, it has no effect on the position of other
|
||||
tabs in the cache since we assume that closing a tab doesn't
|
||||
cause us to load in any other tabs.
|
||||
|
||||
We ignore the effect of dragging tabs between windows.
|
||||
-->
|
||||
<method name="_recordTabAccess">
|
||||
<parameter name="aTab"/>
|
||||
<body><![CDATA[
|
||||
if (!Services.telemetry.canRecordExtended) {
|
||||
return;
|
||||
}
|
||||
|
||||
let tabs = Array.from(this.visibleTabs);
|
||||
|
||||
let pos = aTab.cachePosition;
|
||||
for (let i = 0; i < tabs.length; i++) {
|
||||
// If aTab is moving to the front, everything that was
|
||||
// previously in front of it is bumped up one position.
|
||||
if (tabs[i].cachePosition < pos) {
|
||||
tabs[i].cachePosition++;
|
||||
}
|
||||
}
|
||||
aTab.cachePosition = 0;
|
||||
|
||||
if (isFinite(pos)) {
|
||||
Services.telemetry.getHistogramById("TAB_SWITCH_CACHE_POSITION").add(pos);
|
||||
}
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<method name="_tabAttrModified">
|
||||
<parameter name="aTab"/>
|
||||
<parameter name="aChanged"/>
|
||||
@ -5198,7 +5157,6 @@
|
||||
this.mCurrentTab.permanentKey = this.mCurrentBrowser.permanentKey;
|
||||
this.mCurrentTab._tPos = 0;
|
||||
this.mCurrentTab._fullyOpen = true;
|
||||
this.mCurrentTab.cachePosition = 0;
|
||||
this.mCurrentTab.linkedBrowser = this.mCurrentBrowser;
|
||||
this._tabForBrowser.set(this.mCurrentBrowser, this.mCurrentTab);
|
||||
|
||||
@ -7256,8 +7214,6 @@
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
<field name="cachePosition">Infinity</field>
|
||||
|
||||
<property name="creationTime">
|
||||
<getter>
|
||||
return this._creationTime;
|
||||
|
@ -28,7 +28,7 @@ let testCasesForBothSuccessAndAbort = [
|
||||
|
||||
/**
|
||||
* A portal is detected when multiple browser windows are open but none
|
||||
* have focus. A brower window is focused, then the portal is freed.
|
||||
* have focus. A browser window is focused, then the portal is freed.
|
||||
* The portal tab should be added and focused when the window is
|
||||
* focused, and closed automatically when the success event is fired.
|
||||
* The captive portal notification should be shown in all windows upon
|
||||
|
@ -18,6 +18,7 @@ support-files =
|
||||
|
||||
[browser_extension_sideloading.js]
|
||||
[browser_extension_update_background.js]
|
||||
[browser_extension_update_background_noprompt.js]
|
||||
[browser_permissions_addons_search.js]
|
||||
[browser_permissions_installTrigger.js]
|
||||
[browser_permissions_local_file.js]
|
||||
|
@ -186,55 +186,3 @@ function checkNonDefaultIcon(icon) {
|
||||
|
||||
add_task(() => backgroundUpdateTest(`${BASE}/browser_webext_update_icon1.xpi`,
|
||||
ID_ICON, checkNonDefaultIcon));
|
||||
|
||||
// Helper function to test an upgrade that should not show a prompt
|
||||
async function testNoPrompt(origUrl, id) {
|
||||
await SpecialPowers.pushPrefEnv({set: [
|
||||
// Turn on background updates
|
||||
["extensions.update.enabled", true],
|
||||
|
||||
// Point updates to the local mochitest server
|
||||
["extensions.update.background.url", `${BASE}/browser_webext_update.json`],
|
||||
]});
|
||||
|
||||
// Install version 1.0 of the test extension
|
||||
let addon = await promiseInstallAddon(origUrl);
|
||||
|
||||
ok(addon, "Addon was installed");
|
||||
|
||||
let sawPopup = false;
|
||||
PopupNotifications.panel.addEventListener("popupshown",
|
||||
() => sawPopup = true,
|
||||
{once: true});
|
||||
|
||||
// Trigger an update check and wait for the update to be applied.
|
||||
let updatePromise = waitForUpdate(addon);
|
||||
AddonManagerPrivate.backgroundUpdateCheck();
|
||||
await updatePromise;
|
||||
|
||||
// There should be no notifications about the update
|
||||
is(getBadgeStatus(), "", "Should not have addon alert badge");
|
||||
|
||||
await PanelUI.show();
|
||||
let addons = document.getElementById("PanelUI-footer-addons");
|
||||
is(addons.children.length, 0, "Have 0 updates in the PanelUI menu");
|
||||
await PanelUI.hide();
|
||||
|
||||
ok(!sawPopup, "Should not have seen permissions notification");
|
||||
|
||||
addon = await AddonManager.getAddonByID(id);
|
||||
is(addon.version, "2.0", "Update should have applied");
|
||||
|
||||
addon.uninstall();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
}
|
||||
|
||||
// Test that an update that adds new non-promptable permissions is just
|
||||
// applied without showing a notification dialog.
|
||||
add_task(() => testNoPrompt(`${BASE}/browser_webext_update_perms1.xpi`,
|
||||
ID_PERMS));
|
||||
|
||||
// Test that an update from a legacy extension to a webextension
|
||||
// doesn't show a prompt even when the webextension uses
|
||||
// promptable required permissions.
|
||||
add_task(() => testNoPrompt(`${BASE}/browser_legacy.xpi`, ID_LEGACY));
|
||||
|
@ -0,0 +1,83 @@
|
||||
const {AddonManagerPrivate} = Cu.import("resource://gre/modules/AddonManager.jsm", {});
|
||||
|
||||
const ID_PERMS = "update_perms@tests.mozilla.org";
|
||||
const ID_LEGACY = "legacy_update@tests.mozilla.org";
|
||||
|
||||
function getBadgeStatus() {
|
||||
let menuButton = document.getElementById("PanelUI-menu-button");
|
||||
return menuButton.getAttribute("badge-status");
|
||||
}
|
||||
|
||||
// Set some prefs that apply to all the tests in this file
|
||||
add_task(function* setup() {
|
||||
yield SpecialPowers.pushPrefEnv({set: [
|
||||
// We don't have pre-pinned certificates for the local mochitest server
|
||||
["extensions.install.requireBuiltInCerts", false],
|
||||
["extensions.update.requireBuiltInCerts", false],
|
||||
]});
|
||||
|
||||
// Navigate away from the initial page so that about:addons always
|
||||
// opens in a new tab during tests
|
||||
gBrowser.selectedBrowser.loadURI("about:robots");
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
|
||||
registerCleanupFunction(function*() {
|
||||
// Return to about:blank when we're done
|
||||
gBrowser.selectedBrowser.loadURI("about:blank");
|
||||
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
});
|
||||
});
|
||||
|
||||
hookExtensionsTelemetry();
|
||||
|
||||
// Helper function to test an upgrade that should not show a prompt
|
||||
async function testNoPrompt(origUrl, id) {
|
||||
await SpecialPowers.pushPrefEnv({set: [
|
||||
// Turn on background updates
|
||||
["extensions.update.enabled", true],
|
||||
|
||||
// Point updates to the local mochitest server
|
||||
["extensions.update.background.url", `${BASE}/browser_webext_update.json`],
|
||||
]});
|
||||
|
||||
// Install version 1.0 of the test extension
|
||||
let addon = await promiseInstallAddon(origUrl);
|
||||
|
||||
ok(addon, "Addon was installed");
|
||||
|
||||
let sawPopup = false;
|
||||
PopupNotifications.panel.addEventListener("popupshown",
|
||||
() => sawPopup = true,
|
||||
{once: true});
|
||||
|
||||
// Trigger an update check and wait for the update to be applied.
|
||||
let updatePromise = waitForUpdate(addon);
|
||||
AddonManagerPrivate.backgroundUpdateCheck();
|
||||
await updatePromise;
|
||||
|
||||
// There should be no notifications about the update
|
||||
is(getBadgeStatus(), "", "Should not have addon alert badge");
|
||||
|
||||
await PanelUI.show();
|
||||
let addons = document.getElementById("PanelUI-footer-addons");
|
||||
is(addons.children.length, 0, "Have 0 updates in the PanelUI menu");
|
||||
await PanelUI.hide();
|
||||
|
||||
ok(!sawPopup, "Should not have seen permissions notification");
|
||||
|
||||
addon = await AddonManager.getAddonByID(id);
|
||||
is(addon.version, "2.0", "Update should have applied");
|
||||
|
||||
addon.uninstall();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
}
|
||||
|
||||
// Test that an update that adds new non-promptable permissions is just
|
||||
// applied without showing a notification dialog.
|
||||
add_task(() => testNoPrompt(`${BASE}/browser_webext_update_perms1.xpi`,
|
||||
ID_PERMS));
|
||||
|
||||
// Test that an update from a legacy extension to a webextension
|
||||
// doesn't show a prompt even when the webextension uses
|
||||
// promptable required permissions.
|
||||
add_task(() => testNoPrompt(`${BASE}/browser_legacy.xpi`, ID_LEGACY));
|
@ -1,6 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 16.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="64px" height="64px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" xml:space="preserve">
|
||||
<circle fill="#797C80" cx="32" cy="52" r="6"/>
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.5 KiB |
@ -15,7 +15,7 @@ add_task(function* testTelemetry() {
|
||||
|
||||
// Test it can access telemetry
|
||||
const telemetry = yield environment.telemetry;
|
||||
is(typeof telemetry, "object", "Telemetry is accesible");
|
||||
is(typeof telemetry, "object", "Telemetry is accessible");
|
||||
|
||||
// Test it reads different types of telemetry
|
||||
is(telemetry.testfoo.payload.foo, 1, "value 'foo' is in mock telemetry");
|
||||
|
@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
<path d="M8,0A8,8,0,0,0,0,8a8,8,0,0,0,8,8,8,8,0,0,0,8-8A8,8,0,0,0,8,0ZM8,13A5,5,0,0,1,3,8,5,5,0,0,1,8,3a5,5,0,0,1,5,5A5,5,0,0,1,8,13Z" fill="context-fill" fill-opacity=".2"/>
|
||||
<circle cx="14.5" cy="8" r="1.5" fill="context-fill" fill-opacity=".8"/>
|
||||
|
Before Width: | Height: | Size: 495 B After Width: | Height: | Size: 396 B |
@ -1,5 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
|
||||
|
||||
<defs>
|
||||
|
Before Width: | Height: | Size: 942 B After Width: | Height: | Size: 843 B |
@ -5,7 +5,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// A helper frame-script for brower/devtools/animationinspector tests.
|
||||
// A helper frame-script for browser/devtools/animationinspector tests.
|
||||
|
||||
/**
|
||||
* Toggle (play or pause) one of the animation players of a given node.
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// A helper frame-script for brower/devtools/styleinspector tests.
|
||||
// A helper frame-script for browser/devtools/styleinspector tests.
|
||||
//
|
||||
// Most listeners in the script expect "Test:"-namespaced messages from chrome,
|
||||
// then execute code upon receiving, and immediately send back a message.
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
// A helper frame-script for brower/devtools/styleinspector tests.
|
||||
// A helper frame-script for browser/devtools/styleinspector tests.
|
||||
//
|
||||
// Most listeners in the script expect "Test:"-namespaced messages from chrome,
|
||||
// then execute code upon receiving, and immediately send back a message.
|
||||
|
@ -77,7 +77,6 @@ involved:
|
||||
* `gBrowser._callProgressListeners` with `onLocationChange`
|
||||
* `gBrowser._callProgressListeners` with `onSecurityChange`
|
||||
* `gBrowser._callProgressListeners` with `onUpdateCurrentBrowser`
|
||||
* `gBrowser._recordTabAccess`
|
||||
* `gBrowser.updateTitlebar`
|
||||
* `gBrowser._callProgressListeners` with `onStateChange`
|
||||
* `gBrowser._setCloseKeyState`
|
||||
|
@ -373,7 +373,7 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
|
||||
/*
|
||||
* The size, in CSS pixels, of the horizontal margins for the <body> of an
|
||||
* HTML document in this docshel; used to implement the marginwidth attribute
|
||||
* HTML document in this docshell; used to implement the marginwidth attribute
|
||||
* on HTML <frame>/<iframe> elements. A value smaller than zero indicates
|
||||
* that the attribute was not set.
|
||||
*/
|
||||
@ -381,7 +381,7 @@ interface nsIDocShell : nsIDocShellTreeItem
|
||||
|
||||
/*
|
||||
* The size, in CSS pixels, of the vertical margins for the <body> of an HTML
|
||||
* document in this docshel; used to implement the marginheight attribute on
|
||||
* document in this docshell; used to implement the marginheight attribute on
|
||||
* HTML <frame>/<iframe> elements. A value smaller than zero indicates that
|
||||
* the attribute was not set.
|
||||
*/
|
||||
|
@ -33,11 +33,11 @@ Instances of `ObservedDocShell` accumulate markers that are *mostly* about a par
|
||||
|
||||
Therefore, the following scenarios arise:
|
||||
|
||||
- a). creating a marker on the main thread about a particular dochsell
|
||||
- a). creating a marker on the main thread about a particular docshell
|
||||
|
||||
- b). creating a marker on the main thread without pinpointing to an affected docshell (unlikely, but allowed; in this case such a marker would have to be stored in all currently existing `ObservedDocShell` instances)
|
||||
|
||||
- c). creating a marker off the main thread about a particular dochsell (impossible; docshells can't be referenced outside the main thread, in which case some other type of identification mechanism needs to be put in place).
|
||||
- c). creating a marker off the main thread about a particular docshell (impossible; docshells can't be referenced outside the main thread, in which case some other type of identification mechanism needs to be put in place).
|
||||
|
||||
- d). creating a marker off the main thread without pinpointing to a particular docshell (same path as c. here, such a marker would have to be stored in all currently existing `ObservedDocShell` instances).
|
||||
|
||||
@ -92,6 +92,6 @@ Example: `AutoTimelineMarker marker(aTargetNode->OwnerDoc()->GetDocShell(), "Par
|
||||
|
||||
### mozilla::AutoGlobalTimelineMarker`
|
||||
|
||||
Similar to the previous RAII class, but doesn't expect a specific docshell, and the marker will be visible in all timeline consumers. This is useful for generic operations that don't involve a particular dochsell, or where a docshell isn't accessible. May also only be used on the main thread.
|
||||
Similar to the previous RAII class, but doesn't expect a specific docshell, and the marker will be visible in all timeline consumers. This is useful for generic operations that don't involve a particular docshell, or where a docshell isn't accessible. May also only be used on the main thread.
|
||||
|
||||
Example: `AutoGlobalTimelineMarker marker("Some global operation");`
|
||||
|
@ -1226,7 +1226,7 @@ Element::SetAttribute(const nsAString& aName,
|
||||
nsAutoString nameToUse;
|
||||
const nsAttrName* name = InternalGetAttrNameFromQName(aName, &nameToUse);
|
||||
if (!name) {
|
||||
nsCOMPtr<nsIAtom> nameAtom = NS_Atomize(nameToUse);
|
||||
nsCOMPtr<nsIAtom> nameAtom = NS_AtomizeMainThread(nameToUse);
|
||||
if (!nameAtom) {
|
||||
aError.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return;
|
||||
@ -1308,7 +1308,7 @@ Element::GetAttributeNS(const nsAString& aNamespaceURI,
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAtom> name = NS_Atomize(aLocalName);
|
||||
nsCOMPtr<nsIAtom> name = NS_AtomizeMainThread(aLocalName);
|
||||
bool hasAttr = GetAttr(nsid, name, aReturn);
|
||||
if (!hasAttr) {
|
||||
SetDOMStringToNull(aReturn);
|
||||
@ -1340,7 +1340,7 @@ Element::RemoveAttributeNS(const nsAString& aNamespaceURI,
|
||||
const nsAString& aLocalName,
|
||||
ErrorResult& aError)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> name = NS_Atomize(aLocalName);
|
||||
nsCOMPtr<nsIAtom> name = NS_AtomizeMainThread(aLocalName);
|
||||
int32_t nsid =
|
||||
nsContentUtils::NameSpaceManager()->GetNameSpaceID(aNamespaceURI,
|
||||
nsContentUtils::IsChromeDoc(OwnerDoc()));
|
||||
@ -1413,7 +1413,7 @@ Element::HasAttributeNS(const nsAString& aNamespaceURI,
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAtom> name = NS_Atomize(aLocalName);
|
||||
nsCOMPtr<nsIAtom> name = NS_AtomizeMainThread(aLocalName);
|
||||
return HasAttr(nsid, name);
|
||||
}
|
||||
|
||||
|
@ -750,7 +750,7 @@ nsAttrValue::GetAsAtom() const
|
||||
{
|
||||
switch (Type()) {
|
||||
case eString:
|
||||
return NS_Atomize(GetStringValue());
|
||||
return NS_AtomizeMainThread(GetStringValue());
|
||||
|
||||
case eAtom:
|
||||
{
|
||||
@ -762,7 +762,7 @@ nsAttrValue::GetAsAtom() const
|
||||
{
|
||||
nsAutoString val;
|
||||
ToString(val);
|
||||
return NS_Atomize(val);
|
||||
return NS_AtomizeMainThread(val);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1275,7 +1275,7 @@ nsAttrValue::ParseAtomArray(const nsAString& aValue)
|
||||
++iter;
|
||||
} while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));
|
||||
|
||||
nsCOMPtr<nsIAtom> classAtom = NS_Atomize(Substring(start, iter));
|
||||
nsCOMPtr<nsIAtom> classAtom = NS_AtomizeMainThread(Substring(start, iter));
|
||||
if (!classAtom) {
|
||||
Reset();
|
||||
return;
|
||||
@ -1316,7 +1316,7 @@ nsAttrValue::ParseAtomArray(const nsAString& aValue)
|
||||
++iter;
|
||||
} while (iter != end && !nsContentUtils::IsHTMLWhitespace(*iter));
|
||||
|
||||
classAtom = NS_Atomize(Substring(start, iter));
|
||||
classAtom = NS_AtomizeMainThread(Substring(start, iter));
|
||||
|
||||
if (!array->AppendElement(classAtom)) {
|
||||
Reset();
|
||||
@ -1767,7 +1767,7 @@ nsAttrValue::SetMiscAtomOrString(const nsAString* aValue)
|
||||
"Empty string?");
|
||||
MiscContainer* cont = GetMiscContainer();
|
||||
if (len <= NS_ATTRVALUE_MAX_STRINGLENGTH_ATOM) {
|
||||
nsCOMPtr<nsIAtom> atom = NS_Atomize(*aValue);
|
||||
nsCOMPtr<nsIAtom> atom = NS_AtomizeMainThread(*aValue);
|
||||
if (atom) {
|
||||
cont->mStringBits =
|
||||
reinterpret_cast<uintptr_t>(atom.forget().take()) | eAtomBase;
|
||||
|
@ -44,6 +44,7 @@
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/FileSystemSecurity.h"
|
||||
#include "mozilla/dom/FileBlobImpl.h"
|
||||
#include "mozilla/dom/HTMLInputElement.h"
|
||||
#include "mozilla/dom/HTMLMediaElement.h"
|
||||
#include "mozilla/dom/HTMLTemplateElement.h"
|
||||
#include "mozilla/dom/HTMLContentElement.h"
|
||||
@ -1990,6 +1991,8 @@ nsContentUtils::Shutdown()
|
||||
sModifierSeparator = nullptr;
|
||||
|
||||
NS_IF_RELEASE(sSameOriginChecker);
|
||||
|
||||
HTMLInputElement::Shutdown();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3076,11 +3079,11 @@ nsContentUtils::SplitQName(const nsIContent* aNamespaceResolver,
|
||||
if (*aNamespace == kNameSpaceID_Unknown)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
*aLocalName = NS_Atomize(Substring(colon + 1, end)).take();
|
||||
*aLocalName = NS_AtomizeMainThread(Substring(colon + 1, end)).take();
|
||||
}
|
||||
else {
|
||||
*aNamespace = kNameSpaceID_None;
|
||||
*aLocalName = NS_Atomize(aQName).take();
|
||||
*aLocalName = NS_AtomizeMainThread(aQName).take();
|
||||
}
|
||||
NS_ENSURE_TRUE(aLocalName, NS_ERROR_OUT_OF_MEMORY);
|
||||
return NS_OK;
|
||||
@ -3105,7 +3108,8 @@ nsContentUtils::GetNodeInfoFromQName(const nsAString& aNamespaceURI,
|
||||
const char16_t* end;
|
||||
qName.EndReading(end);
|
||||
|
||||
nsCOMPtr<nsIAtom> prefix = NS_Atomize(Substring(qName.get(), colon));
|
||||
nsCOMPtr<nsIAtom> prefix =
|
||||
NS_AtomizeMainThread(Substring(qName.get(), colon));
|
||||
|
||||
rv = aNodeInfoManager->GetNodeInfo(Substring(colon + 1, end), prefix,
|
||||
nsID, aNodeType, aNodeInfo);
|
||||
@ -3165,7 +3169,7 @@ nsContentUtils::SplitExpatName(const char16_t *aExpatName, nsIAtom **aPrefix,
|
||||
nameStart = (uriEnd + 1);
|
||||
if (nameEnd) {
|
||||
const char16_t *prefixStart = nameEnd + 1;
|
||||
*aPrefix = NS_Atomize(Substring(prefixStart, pos)).take();
|
||||
*aPrefix = NS_AtomizeMainThread(Substring(prefixStart, pos)).take();
|
||||
}
|
||||
else {
|
||||
nameEnd = pos;
|
||||
@ -3178,7 +3182,7 @@ nsContentUtils::SplitExpatName(const char16_t *aExpatName, nsIAtom **aPrefix,
|
||||
nameEnd = pos;
|
||||
*aPrefix = nullptr;
|
||||
}
|
||||
*aLocalName = NS_Atomize(Substring(nameStart, nameEnd)).take();
|
||||
*aLocalName = NS_AtomizeMainThread(Substring(nameStart, nameEnd)).take();
|
||||
}
|
||||
|
||||
// static
|
||||
@ -4053,7 +4057,8 @@ nsContentUtils::GetEventMessageAndAtom(const nsAString& aName,
|
||||
}
|
||||
|
||||
*aEventMessage = eUnidentifiedEvent;
|
||||
nsCOMPtr<nsIAtom> atom = NS_Atomize(NS_LITERAL_STRING("on") + aName);
|
||||
nsCOMPtr<nsIAtom> atom =
|
||||
NS_AtomizeMainThread(NS_LITERAL_STRING("on") + aName);
|
||||
sUserDefinedEvents->AppendObject(atom);
|
||||
mapping.mAtom = atom;
|
||||
mapping.mMessage = eUnidentifiedEvent;
|
||||
@ -4086,7 +4091,7 @@ nsContentUtils::GetEventMessageAndAtomForListener(const nsAString& aName,
|
||||
if (mapping.mMaybeSpecialSVGorSMILEvent) {
|
||||
// Try the atom version so that we should get the right message for
|
||||
// SVG/SMIL.
|
||||
atom = NS_Atomize(NS_LITERAL_STRING("on") + aName);
|
||||
atom = NS_AtomizeMainThread(NS_LITERAL_STRING("on") + aName);
|
||||
msg = GetEventMessage(atom);
|
||||
} else {
|
||||
atom = mapping.mAtom;
|
||||
|
@ -1048,6 +1048,28 @@ static nsresult FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget,
|
||||
const nsAString& aEventType);
|
||||
#endif
|
||||
|
||||
nsTextEditorState* HTMLInputElement::sCachedTextEditorState = nullptr;
|
||||
bool HTMLInputElement::sShutdown = false;
|
||||
|
||||
/* static */ void
|
||||
HTMLInputElement::ReleaseTextEditorState(nsTextEditorState* aState)
|
||||
{
|
||||
if (!sShutdown && !sCachedTextEditorState) {
|
||||
aState->PrepareForReuse();
|
||||
sCachedTextEditorState = aState;
|
||||
} else {
|
||||
delete aState;
|
||||
}
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
HTMLInputElement::Shutdown()
|
||||
{
|
||||
sShutdown = true;
|
||||
delete sCachedTextEditorState;
|
||||
sCachedTextEditorState = nullptr;
|
||||
}
|
||||
|
||||
//
|
||||
// construction, destruction
|
||||
//
|
||||
@ -1079,7 +1101,8 @@ HTMLInputElement::HTMLInputElement(already_AddRefed<mozilla::dom::NodeInfo>& aNo
|
||||
, mSelectionCached(true)
|
||||
{
|
||||
// We are in a type=text so we now we currenty need a nsTextEditorState.
|
||||
mInputData.mState = new nsTextEditorState(this);
|
||||
mInputData.mState =
|
||||
nsTextEditorState::Construct(this, &sCachedTextEditorState);
|
||||
|
||||
if (!gUploadLastDir)
|
||||
HTMLInputElement::InitUploadLastDir();
|
||||
@ -1112,7 +1135,7 @@ HTMLInputElement::FreeData()
|
||||
mInputData.mValue = nullptr;
|
||||
} else {
|
||||
UnbindFromFrame(nullptr);
|
||||
delete mInputData.mState;
|
||||
ReleaseTextEditorState(mInputData.mState);
|
||||
mInputData.mState = nullptr;
|
||||
}
|
||||
}
|
||||
@ -5027,7 +5050,8 @@ HTMLInputElement::HandleTypeChange(uint8_t aNewType, bool aNotify)
|
||||
|
||||
if (IsSingleLineTextControl()) {
|
||||
|
||||
mInputData.mState = new nsTextEditorState(this);
|
||||
mInputData.mState =
|
||||
nsTextEditorState::Construct(this, &sCachedTextEditorState);
|
||||
if (!sp.IsDefault()) {
|
||||
mInputData.mState->SetSelectionProperties(sp);
|
||||
}
|
||||
|
@ -858,6 +858,8 @@ public:
|
||||
|
||||
void UpdateEntries(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories);
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
protected:
|
||||
virtual ~HTMLInputElement();
|
||||
|
||||
@ -1771,6 +1773,11 @@ private:
|
||||
nsCOMPtr<nsIFilePicker> mFilePicker;
|
||||
RefPtr<HTMLInputElement> mInput;
|
||||
};
|
||||
|
||||
static void ReleaseTextEditorState(nsTextEditorState* aState);
|
||||
|
||||
static nsTextEditorState* sCachedTextEditorState;
|
||||
static bool sShutdown;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -1068,10 +1068,38 @@ nsTextEditorState::nsTextEditorState(nsITextControlElement* aOwningElement)
|
||||
, mSelectionRestoreEagerInit(false)
|
||||
, mPlaceholderVisibility(false)
|
||||
, mIsCommittingComposition(false)
|
||||
// When adding more member variable initializations here, add the same
|
||||
// also to ::Construct.
|
||||
{
|
||||
MOZ_COUNT_CTOR(nsTextEditorState);
|
||||
}
|
||||
|
||||
nsTextEditorState*
|
||||
nsTextEditorState::Construct(nsITextControlElement* aOwningElement,
|
||||
nsTextEditorState** aReusedState)
|
||||
{
|
||||
if (*aReusedState) {
|
||||
nsTextEditorState* state = *aReusedState;
|
||||
*aReusedState = nullptr;
|
||||
state->mTextCtrlElement = aOwningElement;
|
||||
state->mBoundFrame = nullptr;
|
||||
state->mSelectionProperties = SelectionProperties();
|
||||
state->mEverInited = false;
|
||||
state->mEditorInitialized = false;
|
||||
state->mInitializing = false;
|
||||
state->mValueTransferInProgress = false;
|
||||
state->mSelectionCached = true;
|
||||
state->mSelectionRestoreEagerInit = false;
|
||||
state->mPlaceholderVisibility = false;
|
||||
state->mIsCommittingComposition = false;
|
||||
// When adding more member variable initializations here, add the same
|
||||
// also to the constructor.
|
||||
return state;
|
||||
}
|
||||
|
||||
return new nsTextEditorState(aOwningElement);
|
||||
}
|
||||
|
||||
nsTextEditorState::~nsTextEditorState()
|
||||
{
|
||||
MOZ_COUNT_DTOR(nsTextEditorState);
|
||||
|
@ -135,11 +135,24 @@ class nsTextEditorState : public mozilla::SupportsWeakPtr<nsTextEditorState> {
|
||||
public:
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(nsTextEditorState)
|
||||
explicit nsTextEditorState(nsITextControlElement* aOwningElement);
|
||||
static nsTextEditorState*
|
||||
Construct(nsITextControlElement* aOwningElement,
|
||||
nsTextEditorState** aReusedState);
|
||||
~nsTextEditorState();
|
||||
|
||||
void Traverse(nsCycleCollectionTraversalCallback& cb);
|
||||
void Unlink();
|
||||
|
||||
void PrepareForReuse()
|
||||
{
|
||||
Unlink();
|
||||
mValue.reset();
|
||||
mCachedValue.Truncate();
|
||||
mValueBeingSet.Truncate();
|
||||
mTextCtrlElement = nullptr;
|
||||
MOZ_ASSERT(!mMutationObserver);
|
||||
}
|
||||
|
||||
nsIEditor* GetEditor();
|
||||
nsISelectionController* GetSelectionController() const;
|
||||
nsFrameSelection* GetConstFrameSelection();
|
||||
@ -401,7 +414,7 @@ private:
|
||||
|
||||
// The text control element owns this object, and ensures that this object
|
||||
// has a smaller lifetime.
|
||||
nsITextControlElement* const MOZ_NON_OWNING_REF mTextCtrlElement;
|
||||
nsITextControlElement* MOZ_NON_OWNING_REF mTextCtrlElement;
|
||||
// mSelCon is non-null while we have an mBoundFrame.
|
||||
RefPtr<nsTextInputSelectionImpl> mSelCon;
|
||||
RefPtr<RestoreSelectionState> mRestoringSelection;
|
||||
|
@ -3982,7 +3982,7 @@ WorkerPrivateParent<Derived>::FlushReportsToSharedWorkers(
|
||||
reportErrorToBrowserConsole = false;
|
||||
}
|
||||
|
||||
// Finally report to broswer console if there is no any window or shared
|
||||
// Finally report to browser console if there is no any window or shared
|
||||
// worker.
|
||||
if (reportErrorToBrowserConsole) {
|
||||
aReporter->FlushReportsToConsole(0);
|
||||
|
@ -18,6 +18,7 @@
|
||||
# include "mozilla/gfx/DeviceManagerDx.h"
|
||||
#endif
|
||||
#include "mozilla/ipc/CrashReporterHost.h"
|
||||
#include "mozilla/layers/LayerTreeOwnerTracker.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
#include "CrossProcessProfilerController.h"
|
||||
@ -26,6 +27,8 @@
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
|
||||
using namespace layers;
|
||||
|
||||
GPUChild::GPUChild(GPUProcessHost* aHost)
|
||||
: mHost(aHost),
|
||||
mGPUReady(false)
|
||||
@ -65,7 +68,12 @@ GPUChild::Init()
|
||||
devicePrefs.oglCompositing() = gfxConfig::GetValue(Feature::OPENGL_COMPOSITING);
|
||||
devicePrefs.useD2D1() = gfxConfig::GetValue(Feature::DIRECT2D);
|
||||
|
||||
SendInit(prefs, updates, devicePrefs);
|
||||
nsTArray<LayerTreeIdMapping> mappings;
|
||||
LayerTreeOwnerTracker::Get()->Iterate([&](uint64_t aLayersId, base::ProcessId aProcessId) {
|
||||
mappings.AppendElement(LayerTreeIdMapping(aLayersId, aProcessId));
|
||||
});
|
||||
|
||||
SendInit(prefs, updates, devicePrefs, mappings);
|
||||
|
||||
gfxVars::AddReceiver(this);
|
||||
|
||||
|
@ -147,7 +147,8 @@ GPUParent::NotifyDeviceReset()
|
||||
mozilla::ipc::IPCResult
|
||||
GPUParent::RecvInit(nsTArray<GfxPrefSetting>&& prefs,
|
||||
nsTArray<GfxVarUpdate>&& vars,
|
||||
const DevicePrefs& devicePrefs)
|
||||
const DevicePrefs& devicePrefs,
|
||||
nsTArray<LayerTreeIdMapping>&& aMappings)
|
||||
{
|
||||
const nsTArray<gfxPrefs::Pref*>& globalPrefs = gfxPrefs::all();
|
||||
for (auto& setting : prefs) {
|
||||
@ -164,6 +165,10 @@ GPUParent::RecvInit(nsTArray<GfxPrefSetting>&& prefs,
|
||||
gfxConfig::Inherit(Feature::OPENGL_COMPOSITING, devicePrefs.oglCompositing());
|
||||
gfxConfig::Inherit(Feature::DIRECT2D, devicePrefs.useD2D1());
|
||||
|
||||
for (const LayerTreeIdMapping& map : aMappings) {
|
||||
LayerTreeOwnerTracker::Get()->Map(map.layersId(), map.ownerId());
|
||||
}
|
||||
|
||||
#if defined(XP_WIN)
|
||||
if (gfxConfig::IsEnabled(Feature::D3D11_COMPOSITING)) {
|
||||
DeviceManagerDx::Get()->CreateCompositorDevices();
|
||||
@ -350,11 +355,9 @@ GPUParent::RecvNewContentVideoDecoderManager(Endpoint<PVideoDecoderManagerParent
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
GPUParent::RecvAddLayerTreeIdMapping(nsTArray<LayerTreeIdMapping>&& aMappings)
|
||||
GPUParent::RecvAddLayerTreeIdMapping(const LayerTreeIdMapping& aMapping)
|
||||
{
|
||||
for (const LayerTreeIdMapping& map : aMappings) {
|
||||
LayerTreeOwnerTracker::Get()->Map(map.layersId(), map.ownerId());
|
||||
}
|
||||
LayerTreeOwnerTracker::Get()->Map(aMapping.layersId(), aMapping.ownerId());
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,8 @@ public:
|
||||
|
||||
mozilla::ipc::IPCResult RecvInit(nsTArray<GfxPrefSetting>&& prefs,
|
||||
nsTArray<GfxVarUpdate>&& vars,
|
||||
const DevicePrefs& devicePrefs) override;
|
||||
const DevicePrefs& devicePrefs,
|
||||
nsTArray<LayerTreeIdMapping>&& mappings) override;
|
||||
mozilla::ipc::IPCResult RecvInitVsyncBridge(Endpoint<PVsyncBridgeParent>&& aVsyncEndpoint) override;
|
||||
mozilla::ipc::IPCResult RecvInitImageBridge(Endpoint<PImageBridgeParent>&& aEndpoint) override;
|
||||
mozilla::ipc::IPCResult RecvInitVRManager(Endpoint<PVRManagerParent>&& aEndpoint) override;
|
||||
@ -51,7 +52,7 @@ public:
|
||||
mozilla::ipc::IPCResult RecvNewContentVRManager(Endpoint<PVRManagerParent>&& aEndpoint) override;
|
||||
mozilla::ipc::IPCResult RecvNewContentVideoDecoderManager(Endpoint<PVideoDecoderManagerParent>&& aEndpoint) override;
|
||||
mozilla::ipc::IPCResult RecvGetDeviceStatus(GPUDeviceData* aOutStatus) override;
|
||||
mozilla::ipc::IPCResult RecvAddLayerTreeIdMapping(nsTArray<LayerTreeIdMapping>&& aMappings) override;
|
||||
mozilla::ipc::IPCResult RecvAddLayerTreeIdMapping(const LayerTreeIdMapping& aMapping) override;
|
||||
mozilla::ipc::IPCResult RecvRemoveLayerTreeIdMapping(const LayerTreeIdMapping& aMapping) override;
|
||||
mozilla::ipc::IPCResult RecvNotifyGpuObservers(const nsCString& aTopic) override;
|
||||
mozilla::ipc::IPCResult RecvStartProfiler(const ProfilerInitParams& params) override;
|
||||
|
@ -37,6 +37,10 @@
|
||||
#include "mozilla/dom/VideoDecoderManagerParent.h"
|
||||
#include "MediaPrefs.h"
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
# include "nsExceptionHandler.h"
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
#include "mozilla/widget/AndroidUiThread.h"
|
||||
#include "mozilla/layers/UiCompositorControllerChild.h"
|
||||
@ -302,11 +306,11 @@ GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost)
|
||||
mVsyncBridge = VsyncBridgeChild::Create(mVsyncIOThread, mProcessToken, Move(vsyncChild));
|
||||
mGPUChild->SendInitVsyncBridge(Move(vsyncParent));
|
||||
|
||||
nsTArray<LayerTreeIdMapping> mappings;
|
||||
LayerTreeOwnerTracker::Get()->Iterate([&](uint64_t aLayersId, base::ProcessId aProcessId) {
|
||||
mappings.AppendElement(LayerTreeIdMapping(aLayersId, aProcessId));
|
||||
});
|
||||
mGPUChild->SendAddLayerTreeIdMapping(mappings);
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
NS_LITERAL_CSTRING("GPUProcessStatus"),
|
||||
NS_LITERAL_CSTRING("Running"));
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
@ -530,6 +534,12 @@ GPUProcessManager::DestroyProcess()
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
UiCompositorControllerChild::Shutdown();
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER
|
||||
CrashReporter::AnnotateCrashReport(
|
||||
NS_LITERAL_CSTRING("GPUProcessStatus"),
|
||||
NS_LITERAL_CSTRING("Destroyed"));
|
||||
#endif
|
||||
}
|
||||
|
||||
RefPtr<CompositorSession>
|
||||
@ -822,9 +832,7 @@ GPUProcessManager::MapLayerTreeId(uint64_t aLayersId, base::ProcessId aOwningId)
|
||||
LayerTreeOwnerTracker::Get()->Map(aLayersId, aOwningId);
|
||||
|
||||
if (EnsureGPUReady()) {
|
||||
AutoTArray<LayerTreeIdMapping, 1> mappings;
|
||||
mappings.AppendElement(LayerTreeIdMapping(aLayersId, aOwningId));
|
||||
mGPUChild->SendAddLayerTreeIdMapping(mappings);
|
||||
mGPUChild->SendAddLayerTreeIdMapping(LayerTreeIdMapping(aLayersId, aOwningId));
|
||||
}
|
||||
}
|
||||
|
||||
@ -853,6 +861,31 @@ GPUProcessManager::AllocateLayerTreeId()
|
||||
return ++mNextLayerTreeId;
|
||||
}
|
||||
|
||||
bool
|
||||
GPUProcessManager::AllocateAndConnectLayerTreeId(PCompositorBridgeChild* aCompositorBridge,
|
||||
base::ProcessId aOtherPid,
|
||||
uint64_t* aOutLayersId)
|
||||
{
|
||||
uint64_t layersId = AllocateLayerTreeId();
|
||||
*aOutLayersId = layersId;
|
||||
|
||||
if (!mGPUChild || !aCompositorBridge) {
|
||||
// If we're not remoting to another process, or there is no compositor,
|
||||
// then we'll send at most one message. In this case we can just keep
|
||||
// the old behavior of making sure the mapping occurs, and maybe sending
|
||||
// a creation notification.
|
||||
MapLayerTreeId(layersId, aOtherPid);
|
||||
if (!aCompositorBridge) {
|
||||
return false;
|
||||
}
|
||||
return aCompositorBridge->SendNotifyChildCreated(layersId);
|
||||
}
|
||||
|
||||
// Use the combined message path.
|
||||
LayerTreeOwnerTracker::Get()->Map(layersId, aOtherPid);
|
||||
return aCompositorBridge->SendMapAndNotifyChildCreated(layersId, aOtherPid);
|
||||
}
|
||||
|
||||
void
|
||||
GPUProcessManager::EnsureVsyncIOThread()
|
||||
{
|
||||
|
@ -116,9 +116,18 @@ public:
|
||||
// Allocate an ID that can be used to refer to a layer tree and
|
||||
// associated resources that live only on the compositor thread.
|
||||
//
|
||||
// Must run on the content main thread.
|
||||
// Must run on the browser main thread.
|
||||
uint64_t AllocateLayerTreeId();
|
||||
|
||||
// Allocate a layers ID and connect it to a compositor. If the compositor is null,
|
||||
// the connect operation will not be performed, but an ID will still be allocated.
|
||||
// This must be called from the browser main thread.
|
||||
//
|
||||
// Note that a layer tree id is always allocated, even if this returns false.
|
||||
bool AllocateAndConnectLayerTreeId(
|
||||
PCompositorBridgeChild* aCompositorBridge,
|
||||
base::ProcessId aOtherPid,
|
||||
uint64_t* aOutLayersId);
|
||||
|
||||
void OnProcessLaunchComplete(GPUProcessHost* aHost) override;
|
||||
void OnProcessUnexpectedShutdown(GPUProcessHost* aHost) override;
|
||||
|
@ -52,7 +52,8 @@ parent:
|
||||
// Sent by the UI process to initiate core settings.
|
||||
async Init(GfxPrefSetting[] prefs,
|
||||
GfxVarUpdate[] vars,
|
||||
DevicePrefs devicePrefs);
|
||||
DevicePrefs devicePrefs,
|
||||
LayerTreeIdMapping[] mapping);
|
||||
|
||||
async InitVsyncBridge(Endpoint<PVsyncBridgeParent> endpoint);
|
||||
async InitImageBridge(Endpoint<PImageBridgeParent> endpoint);
|
||||
@ -78,7 +79,7 @@ parent:
|
||||
async NewContentVideoDecoderManager(Endpoint<PVideoDecoderManagerParent> endpoint);
|
||||
|
||||
// Called to notify the GPU process of who owns a layersId.
|
||||
sync AddLayerTreeIdMapping(LayerTreeIdMapping[] mapping);
|
||||
sync AddLayerTreeIdMapping(LayerTreeIdMapping mapping);
|
||||
async RemoveLayerTreeIdMapping(LayerTreeIdMapping mapping);
|
||||
|
||||
// Request the current DeviceStatus from the GPU process. This blocks until
|
||||
|
@ -1554,6 +1554,20 @@ CompositorBridgeParent::NotifyChildCreated(uint64_t aChild)
|
||||
sIndirectLayerTrees[aChild].mLayerManager = mLayerManager;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
CompositorBridgeParent::RecvMapAndNotifyChildCreated(const uint64_t& aChild, const base::ProcessId& aOwnerPid)
|
||||
{
|
||||
// We only use this message when the remote compositor is in the GPU process.
|
||||
// It is harmless to call it, though.
|
||||
MOZ_ASSERT(XRE_IsGPUProcess());
|
||||
|
||||
LayerTreeOwnerTracker::Get()->Map(aChild, aOwnerPid);
|
||||
|
||||
MonitorAutoLock lock(*sIndirectLayerTreesLock);
|
||||
NotifyChildCreated(aChild);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
CompositorBridgeParent::RecvAdoptChild(const uint64_t& child)
|
||||
{
|
||||
|
@ -189,6 +189,7 @@ public:
|
||||
virtual mozilla::ipc::IPCResult RecvPause() override;
|
||||
virtual mozilla::ipc::IPCResult RecvResume() override;
|
||||
virtual mozilla::ipc::IPCResult RecvNotifyChildCreated(const uint64_t& child) override;
|
||||
virtual mozilla::ipc::IPCResult RecvMapAndNotifyChildCreated(const uint64_t& child, const base::ProcessId& pid) override;
|
||||
virtual mozilla::ipc::IPCResult RecvNotifyChildRecreated(const uint64_t& child) override;
|
||||
virtual mozilla::ipc::IPCResult RecvAdoptChild(const uint64_t& child) override;
|
||||
virtual mozilla::ipc::IPCResult RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
|
||||
|
@ -264,6 +264,14 @@ CrossProcessCompositorBridgeParent::RecvNotifyChildCreated(const uint64_t& child
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
CrossProcessCompositorBridgeParent::RecvMapAndNotifyChildCreated(const uint64_t& child, const base::ProcessId& pid)
|
||||
{
|
||||
// This can only be called from the browser process, as the mapping
|
||||
// ensures proper window ownership of layer trees.
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
void
|
||||
CrossProcessCompositorBridgeParent::ShadowLayersUpdated(
|
||||
LayerTransactionParent* aLayerTree,
|
||||
|
@ -56,6 +56,7 @@ public:
|
||||
virtual mozilla::ipc::IPCResult RecvResume() override { return IPC_OK(); }
|
||||
virtual mozilla::ipc::IPCResult RecvForceIsFirstPaint() override { return IPC_OK(); }
|
||||
virtual mozilla::ipc::IPCResult RecvNotifyChildCreated(const uint64_t& child) override;
|
||||
virtual mozilla::ipc::IPCResult RecvMapAndNotifyChildCreated(const uint64_t& child, const base::ProcessId& pid) override;
|
||||
virtual mozilla::ipc::IPCResult RecvNotifyChildRecreated(const uint64_t& child) override { return IPC_FAIL_NO_REASON(this); }
|
||||
virtual mozilla::ipc::IPCResult RecvAdoptChild(const uint64_t& child) override { return IPC_FAIL_NO_REASON(this); }
|
||||
virtual mozilla::ipc::IPCResult RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
|
||||
|
@ -36,6 +36,7 @@ using class mozilla::layers::FrameUniformityData from "mozilla/layers/FrameUnifo
|
||||
using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h";
|
||||
using mozilla::layers::CompositorOptions from "mozilla/layers/CompositorOptions.h";
|
||||
using mozilla::wr::PipelineId from "mozilla/webrender/WebRenderTypes.h";
|
||||
using base::ProcessId from "base/process.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
@ -175,6 +176,12 @@ parent:
|
||||
// there are ordering issues with SendPLayerTransactionConstructor.
|
||||
sync NotifyChildCreated(uint64_t id);
|
||||
|
||||
// This version of NotifyChildCreated also performs a layer tree mapping.
|
||||
//
|
||||
// See bug 1316632 comment #33 for why this has to be sync. Otherwise,
|
||||
// there are ordering issues with SendPLayerTransactionConstructor.
|
||||
sync MapAndNotifyChildCreated(uint64_t id, ProcessId owner);
|
||||
|
||||
async AdoptChild(uint64_t id);
|
||||
|
||||
// Same as NotifyChildCreated, but used when child processes need to
|
||||
|
@ -89,7 +89,7 @@ struct gfxFontStyle {
|
||||
RefPtr<nsIAtom> language;
|
||||
|
||||
// Features are composed of (1) features from style rules (2) features
|
||||
// from feature setttings rules and (3) family-specific features. (1) and
|
||||
// from feature settings rules and (3) family-specific features. (1) and
|
||||
// (3) are guaranteed to be mutually exclusive
|
||||
|
||||
// custom opentype feature settings
|
||||
|
@ -992,6 +992,8 @@ description =
|
||||
description =
|
||||
[PCompositorBridge::NotifyChildCreated]
|
||||
description =
|
||||
[PCompositorBridge::MapAndNotifyChildCreated]
|
||||
description = bug 1350660
|
||||
[PCompositorBridge::NotifyChildRecreated]
|
||||
description =
|
||||
[PCompositorBridge::MakeSnapshot]
|
||||
|
@ -508,7 +508,7 @@ class GCSchedulingTunables
|
||||
* to complement MAYBEGC triggers. We track this by counting malloced
|
||||
* bytes; the counter gets reset at every GC since we do not always have a
|
||||
* size at the time we call free. Because of this, the malloc heuristic
|
||||
* is, unfortunatly, not usefully able to augment our other GC heap
|
||||
* is, unfortunately, not usefully able to augment our other GC heap
|
||||
* triggers and is limited to this singular heuristic.
|
||||
*
|
||||
* Assumptions:
|
||||
|
@ -468,13 +468,18 @@ IsInlinableFallback(ICFallbackStub* icEntry)
|
||||
static inline void*
|
||||
GetStubReturnAddress(JSContext* cx, jsbytecode* pc)
|
||||
{
|
||||
JitCompartment* jitComp = cx->compartment()->jitCompartment();
|
||||
|
||||
if (IsGetPropPC(pc))
|
||||
return cx->compartment()->jitCompartment()->baselineGetPropReturnAddr();
|
||||
return jitComp->bailoutReturnAddr(BailoutReturnStub::GetProp);
|
||||
if (IsSetPropPC(pc))
|
||||
return cx->compartment()->jitCompartment()->baselineSetPropReturnAddr();
|
||||
return jitComp->bailoutReturnAddr(BailoutReturnStub::SetProp);
|
||||
|
||||
// This should be a call op of some kind, now.
|
||||
MOZ_ASSERT(IsCallPC(pc) && !IsSpreadCallPC(pc));
|
||||
return cx->compartment()->jitCompartment()->baselineCallReturnAddr(IsConstructorCallPC(pc));
|
||||
if (IsConstructorCallPC(pc))
|
||||
return jitComp->bailoutReturnAddr(BailoutReturnStub::New);
|
||||
return jitComp->bailoutReturnAddr(BailoutReturnStub::Call);
|
||||
}
|
||||
|
||||
static inline jsbytecode*
|
||||
|
@ -1641,19 +1641,11 @@ ICSetProp_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
if (!tailCallVM(DoSetPropFallbackInfo, masm))
|
||||
return false;
|
||||
|
||||
// Even though the fallback frame doesn't enter a stub frame, the CallScripted
|
||||
// frame that we are emulating does. Again, we lie.
|
||||
#ifdef DEBUG
|
||||
EmitRepushTailCallReg(masm);
|
||||
EmitStowICValues(masm, 1);
|
||||
enterStubFrame(masm, R1.scratchReg());
|
||||
#else
|
||||
inStubFrame_ = true;
|
||||
#endif
|
||||
|
||||
// What follows is bailout-only code for inlined script getters.
|
||||
// The return address pointed to by the baseline stack points here.
|
||||
returnOffset_ = masm.currentOffset();
|
||||
// This is the resume point used when bailout rewrites call stack to undo
|
||||
// Ion inlined frames. The return address pushed onto reconstructed stack
|
||||
// will point here.
|
||||
assumeStubFrame(masm);
|
||||
bailoutReturnOffset_.bind(masm.currentOffset());
|
||||
|
||||
leaveStubFrame(masm, true);
|
||||
EmitReturnFromIC(masm);
|
||||
@ -1664,7 +1656,9 @@ ICSetProp_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
void
|
||||
ICSetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm, Handle<JitCode*> code)
|
||||
{
|
||||
cx->compartment()->jitCompartment()->initBaselineSetPropReturnAddr(code->raw() + returnOffset_);
|
||||
BailoutReturnStub kind = BailoutReturnStub::SetProp;
|
||||
void* address = code->raw() + bailoutReturnOffset_.offset();
|
||||
cx->compartment()->jitCompartment()->initBailoutReturnAddr(address, getKey(), kind);
|
||||
}
|
||||
|
||||
//
|
||||
@ -1920,6 +1914,11 @@ GetTemplateObjectForNative(JSContext* cx, HandleFunction target, const CallArgs&
|
||||
return !!res;
|
||||
}
|
||||
|
||||
if (native == js::intrinsic_NewArrayIterator) {
|
||||
res.set(NewArrayIteratorObject(cx, TenuredObject));
|
||||
return !!res;
|
||||
}
|
||||
|
||||
if (JitSupportsSimd() && GetTemplateObjectForSimd(cx, target, res))
|
||||
return !!res;
|
||||
|
||||
@ -2818,18 +2817,14 @@ ICCall_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
if (!callVM(DoCallFallbackInfo, masm))
|
||||
return false;
|
||||
|
||||
uint32_t framePushed = masm.framePushed();
|
||||
leaveStubFrame(masm);
|
||||
EmitReturnFromIC(masm);
|
||||
|
||||
// The following asmcode is only used when an Ion inlined frame bails out
|
||||
// into into baseline jitcode. The return address pushed onto the
|
||||
// reconstructed baseline stack points here.
|
||||
returnOffset_ = masm.currentOffset();
|
||||
|
||||
// Here we are again in a stub frame. Marking as so.
|
||||
inStubFrame_ = true;
|
||||
masm.setFramePushed(framePushed);
|
||||
// This is the resume point used when bailout rewrites call stack to undo
|
||||
// Ion inlined frames. The return address pushed onto reconstructed stack
|
||||
// will point here.
|
||||
assumeStubFrame(masm);
|
||||
bailoutReturnOffset_.bind(masm.currentOffset());
|
||||
|
||||
// Load passed-in ThisV into R1 just in case it's needed. Need to do this before
|
||||
// we leave the stub frame since that info will be lost.
|
||||
@ -2870,8 +2865,10 @@ ICCall_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm, Handle<Jit
|
||||
if (MOZ_UNLIKELY(isSpread_))
|
||||
return;
|
||||
|
||||
cx->compartment()->jitCompartment()->initBaselineCallReturnAddr(code->raw() + returnOffset_,
|
||||
isConstructing_);
|
||||
void* address = code->raw() + bailoutReturnOffset_.offset();
|
||||
BailoutReturnStub kind = isConstructing_ ? BailoutReturnStub::New
|
||||
: BailoutReturnStub::Call;
|
||||
cx->compartment()->jitCompartment()->initBailoutReturnAddr(address, getKey(), kind);
|
||||
}
|
||||
|
||||
typedef bool (*CreateThisFn)(JSContext* cx, HandleObject callee, HandleObject newTarget,
|
||||
@ -3153,8 +3150,8 @@ ICCallScriptedCompiler::generateStubCode(MacroAssembler& masm)
|
||||
EmitEnterTypeMonitorIC(masm);
|
||||
|
||||
// Leave stub frame and restore argc for the next stub.
|
||||
assumeStubFrame(masm);
|
||||
masm.bind(&failureLeaveStubFrame);
|
||||
inStubFrame_ = true;
|
||||
leaveStubFrame(masm, false);
|
||||
if (argcReg != R0.scratchReg())
|
||||
masm.movePtr(argcReg, R0.scratchReg());
|
||||
|
@ -628,13 +628,8 @@ class ICSetProp_Fallback : public ICFallbackStub
|
||||
}
|
||||
|
||||
class Compiler : public ICStubCompiler {
|
||||
public:
|
||||
static const int32_t BASELINE_KEY =
|
||||
(static_cast<int32_t>(Engine::Baseline)) |
|
||||
(static_cast<int32_t>(ICStub::SetProp_Fallback) << 1);
|
||||
|
||||
protected:
|
||||
uint32_t returnOffset_;
|
||||
CodeOffset bailoutReturnOffset_;
|
||||
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
|
||||
void postGenerateStubCode(MacroAssembler& masm, Handle<JitCode*> code);
|
||||
|
||||
@ -725,22 +720,10 @@ class ICCall_Fallback : public ICMonitoredFallbackStub
|
||||
|
||||
// Compiler for this stub kind.
|
||||
class Compiler : public ICCallStubCompiler {
|
||||
public:
|
||||
static const int32_t BASELINE_CALL_KEY =
|
||||
(static_cast<int32_t>(Engine::Baseline)) |
|
||||
(static_cast<int32_t>(ICStub::Call_Fallback) << 1) |
|
||||
(0 << 17) | // spread
|
||||
(0 << 18); // constructing
|
||||
static const int32_t BASELINE_CONSTRUCT_KEY =
|
||||
(static_cast<int32_t>(Engine::Baseline)) |
|
||||
(static_cast<int32_t>(ICStub::Call_Fallback) << 1) |
|
||||
(0 << 17) | // spread
|
||||
(1 << 18); // constructing
|
||||
|
||||
protected:
|
||||
bool isConstructing_;
|
||||
bool isSpread_;
|
||||
uint32_t returnOffset_;
|
||||
CodeOffset bailoutReturnOffset_;
|
||||
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
|
||||
void postGenerateStubCode(MacroAssembler& masm, Handle<JitCode*> code);
|
||||
|
||||
|
@ -5635,6 +5635,26 @@ CodeGenerator::visitNewArrayDynamicLength(LNewArrayDynamicLength* lir)
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
typedef ArrayIteratorObject* (*NewArrayIteratorObjectFn)(JSContext*, NewObjectKind);
|
||||
static const VMFunction NewArrayIteratorObjectInfo =
|
||||
FunctionInfo<NewArrayIteratorObjectFn>(NewArrayIteratorObject, "NewArrayIteratorObject");
|
||||
|
||||
void
|
||||
CodeGenerator::visitNewArrayIterator(LNewArrayIterator* lir)
|
||||
{
|
||||
Register objReg = ToRegister(lir->output());
|
||||
Register tempReg = ToRegister(lir->temp());
|
||||
JSObject* templateObject = lir->mir()->templateObject();
|
||||
|
||||
OutOfLineCode* ool = oolCallVM(NewArrayIteratorObjectInfo, lir,
|
||||
ArgList(Imm32(GenericObject)),
|
||||
StoreRegisterTo(objReg));
|
||||
|
||||
masm.createGCObject(objReg, tempReg, templateObject, gc::DefaultHeap, ool->entry());
|
||||
|
||||
masm.bind(ool->rejoin());
|
||||
}
|
||||
|
||||
typedef TypedArrayObject* (*TypedArrayConstructorOneArgFn)(JSContext*, HandleObject, int32_t length);
|
||||
static const VMFunction TypedArrayConstructorOneArgInfo =
|
||||
FunctionInfo<TypedArrayConstructorOneArgFn>(TypedArrayCreateWithTemplate,
|
||||
|
@ -198,6 +198,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
|
||||
void visitOutOfLineNewArray(OutOfLineNewArray* ool);
|
||||
void visitNewArrayCopyOnWrite(LNewArrayCopyOnWrite* lir);
|
||||
void visitNewArrayDynamicLength(LNewArrayDynamicLength* lir);
|
||||
void visitNewArrayIterator(LNewArrayIterator* lir);
|
||||
void visitNewTypedArray(LNewTypedArray* lir);
|
||||
void visitNewTypedArrayDynamicLength(LNewTypedArrayDynamicLength* lir);
|
||||
void visitNewObjectVMCall(LNewObject* lir);
|
||||
|
@ -129,6 +129,8 @@
|
||||
\
|
||||
_(IntrinsicGetNextSetEntryForIterator) \
|
||||
\
|
||||
_(IntrinsicNewArrayIterator) \
|
||||
\
|
||||
_(IntrinsicArrayBufferByteLength) \
|
||||
_(IntrinsicPossiblyWrappedArrayBufferByteLength) \
|
||||
\
|
||||
|
@ -416,14 +416,11 @@ JitZoneGroup::JitZoneGroup(ZoneGroup* group)
|
||||
JitCompartment::JitCompartment()
|
||||
: stubCodes_(nullptr),
|
||||
cacheIRStubCodes_(nullptr),
|
||||
baselineGetPropReturnAddr_(nullptr),
|
||||
baselineSetPropReturnAddr_(nullptr),
|
||||
stringConcatStub_(nullptr),
|
||||
regExpMatcherStub_(nullptr),
|
||||
regExpSearcherStub_(nullptr),
|
||||
regExpTesterStub_(nullptr)
|
||||
{
|
||||
baselineCallReturnAddrs_[0] = baselineCallReturnAddrs_[1] = nullptr;
|
||||
}
|
||||
|
||||
JitCompartment::~JitCompartment()
|
||||
@ -647,17 +644,11 @@ JitCompartment::sweep(FreeOp* fop, JSCompartment* compartment)
|
||||
stubCodes_->sweep();
|
||||
cacheIRStubCodes_->sweep();
|
||||
|
||||
// If the sweep removed the ICCall_Fallback stub, nullptr the baselineCallReturnAddr_ field.
|
||||
if (!stubCodes_->lookup(ICCall_Fallback::Compiler::BASELINE_CALL_KEY))
|
||||
baselineCallReturnAddrs_[0] = nullptr;
|
||||
if (!stubCodes_->lookup(ICCall_Fallback::Compiler::BASELINE_CONSTRUCT_KEY))
|
||||
baselineCallReturnAddrs_[1] = nullptr;
|
||||
|
||||
// Similarly for the ICGetProp_Fallback stub.
|
||||
if (!stubCodes_->lookup(ICGetProp_Fallback::Compiler::BASELINE_KEY))
|
||||
baselineGetPropReturnAddr_ = nullptr;
|
||||
if (!stubCodes_->lookup(ICSetProp_Fallback::Compiler::BASELINE_KEY))
|
||||
baselineSetPropReturnAddr_ = nullptr;
|
||||
// If the sweep removed a bailout Fallback stub, nullptr the corresponding return addr.
|
||||
for (auto& it : bailoutReturnStubInfo_) {
|
||||
if (!stubCodes_->lookup(it.key))
|
||||
it = BailoutReturnStubInfo();
|
||||
}
|
||||
|
||||
JSRuntime* rt = fop->runtime();
|
||||
if (stringConcatStub_ && !IsMarkedUnbarriered(rt, &stringConcatStub_))
|
||||
|
@ -632,6 +632,9 @@ class IonBuilder
|
||||
InliningResult inlineArraySlice(CallInfo& callInfo);
|
||||
InliningResult inlineArrayJoin(CallInfo& callInfo);
|
||||
|
||||
// Array intrinsics.
|
||||
InliningResult inlineNewArrayIterator(CallInfo& callInfo);
|
||||
|
||||
// Math natives.
|
||||
InliningResult inlineMathAbs(CallInfo& callInfo);
|
||||
InliningResult inlineMathFloor(CallInfo& callInfo);
|
||||
|
@ -432,6 +432,14 @@ class JitZone
|
||||
}
|
||||
};
|
||||
|
||||
enum class BailoutReturnStub {
|
||||
GetProp,
|
||||
SetProp,
|
||||
Call,
|
||||
New,
|
||||
Count
|
||||
};
|
||||
|
||||
class JitCompartment
|
||||
{
|
||||
friend class JitActivation;
|
||||
@ -461,9 +469,17 @@ class JitCompartment
|
||||
|
||||
// Keep track of offset into various baseline stubs' code at return
|
||||
// point from called script.
|
||||
void* baselineCallReturnAddrs_[2];
|
||||
void* baselineGetPropReturnAddr_;
|
||||
void* baselineSetPropReturnAddr_;
|
||||
struct BailoutReturnStubInfo
|
||||
{
|
||||
void* addr;
|
||||
uint32_t key;
|
||||
|
||||
BailoutReturnStubInfo() : addr(nullptr), key(0) { }
|
||||
BailoutReturnStubInfo(void* addr_, uint32_t key_) : addr(addr_), key(key_) { }
|
||||
};
|
||||
mozilla::EnumeratedArray<BailoutReturnStub,
|
||||
BailoutReturnStub::Count,
|
||||
BailoutReturnStubInfo> bailoutReturnStubInfo_;
|
||||
|
||||
// Stubs to concatenate two strings inline, or perform RegExp calls inline.
|
||||
// These bake in zone and compartment specific pointers and can't be stored
|
||||
@ -509,7 +525,7 @@ class JitCompartment
|
||||
}
|
||||
|
||||
JitCode* getStubCode(uint32_t key) {
|
||||
ICStubCodeMap::AddPtr p = stubCodes_->lookupForAdd(key);
|
||||
ICStubCodeMap::Ptr p = stubCodes_->lookup(key);
|
||||
if (p)
|
||||
return p->value();
|
||||
return nullptr;
|
||||
@ -538,29 +554,13 @@ class JitCompartment
|
||||
MOZ_ASSERT(!p);
|
||||
return cacheIRStubCodes_->add(p, Move(key), stubCode);
|
||||
}
|
||||
void initBaselineCallReturnAddr(void* addr, bool constructing) {
|
||||
MOZ_ASSERT(baselineCallReturnAddrs_[constructing] == nullptr);
|
||||
baselineCallReturnAddrs_[constructing] = addr;
|
||||
void initBailoutReturnAddr(void* addr, uint32_t key, BailoutReturnStub kind) {
|
||||
MOZ_ASSERT(bailoutReturnStubInfo_[kind].addr == nullptr);
|
||||
bailoutReturnStubInfo_[kind] = BailoutReturnStubInfo { addr, key };
|
||||
}
|
||||
void* baselineCallReturnAddr(bool constructing) {
|
||||
MOZ_ASSERT(baselineCallReturnAddrs_[constructing] != nullptr);
|
||||
return baselineCallReturnAddrs_[constructing];
|
||||
}
|
||||
void initBaselineGetPropReturnAddr(void* addr) {
|
||||
MOZ_ASSERT(baselineGetPropReturnAddr_ == nullptr);
|
||||
baselineGetPropReturnAddr_ = addr;
|
||||
}
|
||||
void* baselineGetPropReturnAddr() {
|
||||
MOZ_ASSERT(baselineGetPropReturnAddr_ != nullptr);
|
||||
return baselineGetPropReturnAddr_;
|
||||
}
|
||||
void initBaselineSetPropReturnAddr(void* addr) {
|
||||
MOZ_ASSERT(baselineSetPropReturnAddr_ == nullptr);
|
||||
baselineSetPropReturnAddr_ = addr;
|
||||
}
|
||||
void* baselineSetPropReturnAddr() {
|
||||
MOZ_ASSERT(baselineSetPropReturnAddr_ != nullptr);
|
||||
return baselineSetPropReturnAddr_;
|
||||
void* bailoutReturnAddr(BailoutReturnStub kind) {
|
||||
MOZ_ASSERT(bailoutReturnStubInfo_[kind].addr);
|
||||
return bailoutReturnStubInfo_[kind].addr;
|
||||
}
|
||||
|
||||
void toggleBarriers(bool enabled);
|
||||
|
@ -243,6 +243,14 @@ LIRGenerator::visitNewArrayDynamicLength(MNewArrayDynamicLength* ins)
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitNewArrayIterator(MNewArrayIterator* ins)
|
||||
{
|
||||
LNewArrayIterator* lir = new(alloc()) LNewArrayIterator(temp());
|
||||
define(lir, ins);
|
||||
assignSafepoint(lir, ins);
|
||||
}
|
||||
|
||||
void
|
||||
LIRGenerator::visitNewTypedArray(MNewTypedArray* ins)
|
||||
{
|
||||
|
@ -78,6 +78,7 @@ class LIRGenerator : public LIRGeneratorSpecific
|
||||
void visitNewArray(MNewArray* ins);
|
||||
void visitNewArrayCopyOnWrite(MNewArrayCopyOnWrite* ins);
|
||||
void visitNewArrayDynamicLength(MNewArrayDynamicLength* ins);
|
||||
void visitNewArrayIterator(MNewArrayIterator* ins);
|
||||
void visitNewTypedArray(MNewTypedArray* ins);
|
||||
void visitNewTypedArrayDynamicLength(MNewTypedArrayDynamicLength* ins);
|
||||
void visitNewObject(MNewObject* ins);
|
||||
|
@ -88,6 +88,10 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
|
||||
case InlinableNative::ArraySlice:
|
||||
return inlineArraySlice(callInfo);
|
||||
|
||||
// Array intrinsics.
|
||||
case InlinableNative::IntrinsicNewArrayIterator:
|
||||
return inlineNewArrayIterator(callInfo);
|
||||
|
||||
// Atomic natives.
|
||||
case InlinableNative::AtomicsCompareExchange:
|
||||
return inlineAtomicsCompareExchange(callInfo);
|
||||
@ -886,6 +890,32 @@ IonBuilder::inlineArraySlice(CallInfo& callInfo)
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineNewArrayIterator(CallInfo& callInfo)
|
||||
{
|
||||
if (callInfo.argc() != 0 || callInfo.constructing()) {
|
||||
trackOptimizationOutcome(TrackedOutcome::CantInlineNativeBadForm);
|
||||
return InliningStatus_NotInlined;
|
||||
}
|
||||
|
||||
JSObject* templateObject = inspector->getTemplateObjectForNative(pc, js::intrinsic_NewArrayIterator);
|
||||
if (!templateObject)
|
||||
return InliningStatus_NotInlined;
|
||||
MOZ_ASSERT(templateObject->is<ArrayIteratorObject>());
|
||||
|
||||
callInfo.setImplicitlyUsedUnchecked();
|
||||
|
||||
MConstant* templateConst = MConstant::NewConstraintlessObject(alloc(), templateObject);
|
||||
current->add(templateConst);
|
||||
|
||||
MNewArrayIterator* ins = MNewArrayIterator::New(alloc(), constraints(), templateConst);
|
||||
current->add(ins);
|
||||
current->push(ins);
|
||||
|
||||
MOZ_TRY(resumeAfter(ins));
|
||||
return InliningStatus_Inlined;
|
||||
}
|
||||
|
||||
IonBuilder::InliningResult
|
||||
IonBuilder::inlineMathAbs(CallInfo& callInfo)
|
||||
{
|
||||
|
@ -3532,6 +3532,33 @@ class MNewObject
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MNewArrayIterator
|
||||
: public MUnaryInstruction,
|
||||
public NoTypePolicy::Data
|
||||
{
|
||||
explicit MNewArrayIterator(CompilerConstraintList* constraints, MConstant* templateConst)
|
||||
: MUnaryInstruction(templateConst)
|
||||
{
|
||||
setResultType(MIRType::Object);
|
||||
setResultTypeSet(MakeSingletonTypeSet(constraints, templateObject()));
|
||||
templateConst->setEmittedAtUses();
|
||||
}
|
||||
|
||||
public:
|
||||
INSTRUCTION_HEADER(NewArrayIterator)
|
||||
TRIVIAL_NEW_WRAPPERS
|
||||
|
||||
JSObject* templateObject() {
|
||||
return getOperand(0)->toConstant()->toObjectOrNull();
|
||||
}
|
||||
|
||||
AliasSet getAliasSet() const override {
|
||||
return AliasSet::None();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class MNewTypedObject : public MNullaryInstruction
|
||||
{
|
||||
CompilerGCPointer<InlineTypedObject*> templateObject_;
|
||||
|
@ -133,6 +133,7 @@ namespace jit {
|
||||
_(NewArray) \
|
||||
_(NewArrayCopyOnWrite) \
|
||||
_(NewArrayDynamicLength) \
|
||||
_(NewArrayIterator) \
|
||||
_(NewTypedArray) \
|
||||
_(NewTypedArrayDynamicLength) \
|
||||
_(NewObject) \
|
||||
|
@ -580,6 +580,21 @@ ICStubCompiler::enterStubFrame(MacroAssembler& masm, Register scratch)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ICStubCompiler::assumeStubFrame(MacroAssembler& masm)
|
||||
{
|
||||
MOZ_ASSERT(!inStubFrame_);
|
||||
inStubFrame_ = true;
|
||||
|
||||
#ifdef DEBUG
|
||||
entersStubFrame_ = true;
|
||||
|
||||
// |framePushed| isn't tracked precisely in ICStubs, so simply assume it to
|
||||
// be STUB_FRAME_SIZE so that assertions don't fail in leaveStubFrame.
|
||||
framePushedAtEnterStubFrame_ = STUB_FRAME_SIZE;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ICStubCompiler::leaveStubFrame(MacroAssembler& masm, bool calledIntoIon)
|
||||
{
|
||||
@ -2077,18 +2092,11 @@ ICGetProp_Fallback::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
if (!tailCallVM(DoGetPropFallbackInfo, masm))
|
||||
return false;
|
||||
|
||||
// Even though the fallback frame doesn't enter a stub frame, the CallScripted
|
||||
// frame that we are emulating does. Again, we lie.
|
||||
#ifdef DEBUG
|
||||
EmitRepushTailCallReg(masm);
|
||||
enterStubFrame(masm, R0.scratchReg());
|
||||
#else
|
||||
inStubFrame_ = true;
|
||||
#endif
|
||||
|
||||
// What follows is bailout for inlined scripted getters.
|
||||
// The return address pointed to by the baseline stack points here.
|
||||
returnOffset_ = masm.currentOffset();
|
||||
// This is the resume point used when bailout rewrites call stack to undo
|
||||
// Ion inlined frames. The return address pushed onto reconstructed stack
|
||||
// will point here.
|
||||
assumeStubFrame(masm);
|
||||
bailoutReturnOffset_.bind(masm.currentOffset());
|
||||
|
||||
leaveStubFrame(masm, true);
|
||||
|
||||
@ -2106,8 +2114,9 @@ void
|
||||
ICGetProp_Fallback::Compiler::postGenerateStubCode(MacroAssembler& masm, Handle<JitCode*> code)
|
||||
{
|
||||
if (engine_ == Engine::Baseline) {
|
||||
void* address = code->raw() + returnOffset_;
|
||||
cx->compartment()->jitCompartment()->initBaselineGetPropReturnAddr(address);
|
||||
BailoutReturnStub kind = BailoutReturnStub::GetProp;
|
||||
void* address = code->raw() + bailoutReturnOffset_.offset();
|
||||
cx->compartment()->jitCompartment()->initBailoutReturnAddr(address, getKey(), kind);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1073,6 +1073,7 @@ class ICStubCompiler
|
||||
// performing a tail call. This is required for the return address
|
||||
// to pc mapping to work.
|
||||
void enterStubFrame(MacroAssembler& masm, Register scratch);
|
||||
void assumeStubFrame(MacroAssembler& masm);
|
||||
void leaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false);
|
||||
|
||||
// Some stubs need to emit Gecko Profiler updates. This emits the guarding
|
||||
@ -2346,13 +2347,8 @@ class ICGetProp_Fallback : public ICMonitoredFallbackStub
|
||||
}
|
||||
|
||||
class Compiler : public ICStubCompiler {
|
||||
public:
|
||||
static const int32_t BASELINE_KEY =
|
||||
(static_cast<int32_t>(Engine::Baseline)) |
|
||||
(static_cast<int32_t>(ICStub::GetProp_Fallback) << 1);
|
||||
|
||||
protected:
|
||||
uint32_t returnOffset_;
|
||||
CodeOffset bailoutReturnOffset_;
|
||||
MOZ_MUST_USE bool generateStubCode(MacroAssembler& masm);
|
||||
void postGenerateStubCode(MacroAssembler& masm, Handle<JitCode*> code);
|
||||
|
||||
|
@ -282,6 +282,7 @@ template <> struct TypeToDataType<NamedLambdaObject*> { static const DataType re
|
||||
template <> struct TypeToDataType<LexicalEnvironmentObject*> { static const DataType result = Type_Object; };
|
||||
template <> struct TypeToDataType<ArrayObject*> { static const DataType result = Type_Object; };
|
||||
template <> struct TypeToDataType<TypedArrayObject*> { static const DataType result = Type_Object; };
|
||||
template <> struct TypeToDataType<ArrayIteratorObject*> { static const DataType result = Type_Object; };
|
||||
template <> struct TypeToDataType<JSString*> { static const DataType result = Type_Object; };
|
||||
template <> struct TypeToDataType<JSFlatString*> { static const DataType result = Type_Object; };
|
||||
template <> struct TypeToDataType<HandleObject> { static const DataType result = Type_Handle; };
|
||||
|
@ -1062,6 +1062,24 @@ class LNewArrayDynamicLength : public LInstructionHelper<1, 1, 1>
|
||||
}
|
||||
};
|
||||
|
||||
class LNewArrayIterator : public LInstructionHelper<1, 0, 1>
|
||||
{
|
||||
public:
|
||||
LIR_HEADER(NewArrayIterator)
|
||||
|
||||
explicit LNewArrayIterator(const LDefinition& temp) {
|
||||
setTemp(0, temp);
|
||||
}
|
||||
|
||||
const LDefinition* temp() {
|
||||
return getTemp(0);
|
||||
}
|
||||
|
||||
MNewArrayIterator* mir() const {
|
||||
return mir_->toNewArrayIterator();
|
||||
}
|
||||
};
|
||||
|
||||
class LNewTypedArray : public LInstructionHelper<1, 0, 2>
|
||||
{
|
||||
public:
|
||||
|
@ -67,6 +67,7 @@
|
||||
_(NewArray) \
|
||||
_(NewArrayCopyOnWrite) \
|
||||
_(NewArrayDynamicLength) \
|
||||
_(NewArrayIterator) \
|
||||
_(NewTypedArray) \
|
||||
_(NewTypedArrayDynamicLength) \
|
||||
_(NewObject) \
|
||||
|
@ -1499,6 +1499,15 @@ JS_NewExternalString(JSContext* cx, const char16_t* chars, size_t length,
|
||||
return s;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSString*)
|
||||
JS_NewMaybeExternalString(JSContext* cx, const char16_t* chars, size_t length,
|
||||
const JSStringFinalizer* fin, bool* isExternal)
|
||||
{
|
||||
AssertHeapIsIdle();
|
||||
CHECK_REQUEST(cx);
|
||||
return NewMaybeExternalString(cx, chars, length, fin, isExternal);
|
||||
}
|
||||
|
||||
extern JS_PUBLIC_API(bool)
|
||||
JS_IsExternalString(JSString* str)
|
||||
{
|
||||
|
@ -1854,6 +1854,17 @@ extern JS_PUBLIC_API(JSString*)
|
||||
JS_NewExternalString(JSContext* cx, const char16_t* chars, size_t length,
|
||||
const JSStringFinalizer* fin);
|
||||
|
||||
/**
|
||||
* Create a new JSString whose chars member may refer to external memory.
|
||||
* If the returned string refers to the external memory, |*isExternal| is set
|
||||
* to true. Otherwise the returned string is not an external string and
|
||||
* |*isExternal| is set to false. If |*isExternal| is false, |fin| won't be
|
||||
* called.
|
||||
*/
|
||||
extern JS_PUBLIC_API(JSString*)
|
||||
JS_NewMaybeExternalString(JSContext* cx, const char16_t* chars, size_t length,
|
||||
const JSStringFinalizer* fin, bool* isExternal);
|
||||
|
||||
/**
|
||||
* Return whether 'str' was created with JS_NewExternalString or
|
||||
* JS_NewExternalStringWithClosure.
|
||||
|
@ -1134,6 +1134,17 @@ const Class ArrayIteratorObject::class_ = {
|
||||
JSCLASS_HAS_RESERVED_SLOTS(ArrayIteratorSlotCount)
|
||||
};
|
||||
|
||||
|
||||
ArrayIteratorObject*
|
||||
js::NewArrayIteratorObject(JSContext* cx, NewObjectKind newKind)
|
||||
{
|
||||
RootedObject proto(cx, GlobalObject::getOrCreateArrayIteratorPrototype(cx, cx->global()));
|
||||
if (!proto)
|
||||
return nullptr;
|
||||
|
||||
return NewObjectWithGivenProto<ArrayIteratorObject>(cx, proto, newKind);
|
||||
}
|
||||
|
||||
static const JSFunctionSpec array_iterator_methods[] = {
|
||||
JS_SELF_HOSTED_FN("next", "ArrayIteratorNext", 0, 0),
|
||||
JS_FS_END
|
||||
|
@ -145,6 +145,9 @@ class ArrayIteratorObject : public JSObject
|
||||
static const Class class_;
|
||||
};
|
||||
|
||||
ArrayIteratorObject*
|
||||
NewArrayIteratorObject(JSContext* cx, NewObjectKind newKind = GenericObject);
|
||||
|
||||
class StringIteratorObject : public JSObject
|
||||
{
|
||||
public:
|
||||
|
@ -68,6 +68,19 @@
|
||||
# define GETRANDOM_NR 355
|
||||
# elif defined(__arm__)
|
||||
# define GETRANDOM_NR 384
|
||||
// Added other architectures:
|
||||
# elif defined(__ppc64le__)
|
||||
# define GETRANDOM_NR 359
|
||||
# elif defined(__PPC64LE__)
|
||||
# define GETRANDOM_NR 359
|
||||
# elif defined(__ppc64__)
|
||||
# define GETRANDOM_NR 359
|
||||
# elif defined(__PPC64__)
|
||||
# define GETRANDOM_NR 359
|
||||
# elif defined(__s390x__)
|
||||
# define GETRANDOM_NR 349
|
||||
# elif defined(__s390__)
|
||||
# define GETRANDOM_NR 349
|
||||
# endif
|
||||
|
||||
# if defined(SYS_getrandom)
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include "jsfriendapi.h"
|
||||
#include "jsfun.h"
|
||||
#include "jshashutil.h"
|
||||
#include "jsiter.h"
|
||||
#include "jsstr.h"
|
||||
#include "jsweakmap.h"
|
||||
#include "jswrapper.h"
|
||||
@ -754,17 +755,13 @@ intrinsic_GetIteratorPrototype(JSContext* cx, unsigned argc, Value* vp)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, Value* vp)
|
||||
bool
|
||||
js::intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
MOZ_ASSERT(args.length() == 0);
|
||||
|
||||
RootedObject proto(cx, GlobalObject::getOrCreateArrayIteratorPrototype(cx, cx->global()));
|
||||
if (!proto)
|
||||
return false;
|
||||
|
||||
JSObject* obj = NewObjectWithGivenProto(cx, &ArrayIteratorObject::class_, proto);
|
||||
JSObject* obj = NewArrayIteratorObject(cx);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
||||
@ -2441,7 +2438,9 @@ static const JSFunctionSpec intrinsic_functions[] = {
|
||||
|
||||
JS_FN("GetIteratorPrototype", intrinsic_GetIteratorPrototype, 0,0),
|
||||
|
||||
JS_FN("NewArrayIterator", intrinsic_NewArrayIterator, 0,0),
|
||||
JS_INLINABLE_FN("NewArrayIterator", intrinsic_NewArrayIterator, 0,0,
|
||||
IntrinsicNewArrayIterator),
|
||||
|
||||
JS_FN("CallArrayIteratorMethodIfWrapped",
|
||||
CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2,0),
|
||||
|
||||
|
@ -47,6 +47,9 @@ CallSelfHostedFunction(JSContext* cx, HandlePropertyName name, HandleValue thisv
|
||||
bool
|
||||
intrinsic_StringSplitString(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
bool
|
||||
intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, JS::Value* vp);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#endif /* vm_SelfHosting_h_ */
|
||||
|
@ -1413,6 +1413,19 @@ NewStringCopyUTF8N(JSContext* cx, const JS::UTF8Chars utf8)
|
||||
template JSFlatString*
|
||||
NewStringCopyUTF8N<CanGC>(JSContext* cx, const JS::UTF8Chars utf8);
|
||||
|
||||
JSString*
|
||||
NewMaybeExternalString(JSContext* cx, const char16_t* s, size_t n, const JSStringFinalizer* fin,
|
||||
bool* isExternal)
|
||||
{
|
||||
if (JSString* str = TryEmptyOrStaticString(cx, s, n)) {
|
||||
*isExternal = false;
|
||||
return str;
|
||||
}
|
||||
|
||||
*isExternal = true;
|
||||
return JSExternalString::new_(cx, s, n, fin);
|
||||
}
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -1313,6 +1313,10 @@ NewStringCopyUTF8Z(JSContext* cx, const JS::ConstUTF8CharsZ utf8)
|
||||
return NewStringCopyUTF8N<allowGC>(cx, JS::UTF8Chars(utf8.c_str(), strlen(utf8.c_str())));
|
||||
}
|
||||
|
||||
JSString*
|
||||
NewMaybeExternalString(JSContext* cx, const char16_t* s, size_t n, const JSStringFinalizer* fin,
|
||||
bool* isExternal);
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(HashNumber) == 4);
|
||||
|
||||
} /* namespace js */
|
||||
|
@ -16,7 +16,6 @@
|
||||
#include "threading/Mutex.h"
|
||||
#include "vm/MutexIDs.h"
|
||||
#include "vm/Shape.h"
|
||||
#include "wasm/WasmCode.h"
|
||||
|
||||
#ifdef MOZ_VTUNE
|
||||
|
||||
@ -133,13 +132,13 @@ MarkScript(const js::jit::JitCode* code, const JSScript* script, const char* mod
|
||||
}
|
||||
|
||||
void
|
||||
MarkWasm(const js::wasm::CodeSegment& cs, const char* name, void* start, uintptr_t size)
|
||||
MarkWasm(unsigned methodId, const char* name, void* start, uintptr_t size)
|
||||
{
|
||||
if (!IsProfilingActive())
|
||||
return;
|
||||
|
||||
iJIT_Method_Load_V2 method = {0};
|
||||
method.method_id = cs.vtune_method_id_;
|
||||
method.method_id = methodId;
|
||||
method.method_name = const_cast<char*>(name);
|
||||
method.method_load_address = start;
|
||||
method.method_size = (unsigned)size;
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "jit/IonCode.h"
|
||||
#include "wasm/WasmCode.h"
|
||||
|
||||
namespace js {
|
||||
namespace vtune {
|
||||
@ -38,7 +37,7 @@ void MarkScript(const js::jit::JitCode* code,
|
||||
const JSScript* script,
|
||||
const char* module);
|
||||
|
||||
void MarkWasm(const js::wasm::CodeSegment& cs,
|
||||
void MarkWasm(unsigned methodId,
|
||||
const char* name,
|
||||
void* start,
|
||||
uintptr_t size);
|
||||
|
@ -159,10 +159,8 @@ SendCodeRangesToProfiler(CodeSegment& cs, const Bytes& bytecode, const Metadata&
|
||||
}
|
||||
#endif
|
||||
#ifdef MOZ_VTUNE
|
||||
if (vtune::IsProfilingActive()) {
|
||||
cs.vtune_method_id_ = vtune::GenerateUniqueMethodID();
|
||||
vtune::MarkWasm(cs, name.begin(), (void*)start, size);
|
||||
}
|
||||
if (vtune::IsProfilingActive())
|
||||
vtune::MarkWasm(vtune::GenerateUniqueMethodID(), name.begin(), (void*)start, size);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -57,11 +57,6 @@ class CodeSegment
|
||||
uint8_t* outOfBoundsCode_;
|
||||
uint8_t* unalignedAccessCode_;
|
||||
|
||||
public:
|
||||
#ifdef MOZ_VTUNE
|
||||
unsigned vtune_method_id_; // Zero if unset.
|
||||
#endif
|
||||
|
||||
protected:
|
||||
CodeSegment() { PodZero(this); }
|
||||
template <class> friend struct js::MallocProvider;
|
||||
|
@ -96,9 +96,10 @@ XPCStringConvert::ReadableToJSVal(JSContext* cx,
|
||||
uint32_t length = readable.Length();
|
||||
|
||||
if (readable.IsLiteral()) {
|
||||
JSString* str = JS_NewExternalString(cx,
|
||||
static_cast<const char16_t*>(readable.BeginReading()),
|
||||
length, &sLiteralFinalizer);
|
||||
bool ignored;
|
||||
JSString* str = JS_NewMaybeExternalString(cx,
|
||||
static_cast<const char16_t*>(readable.BeginReading()),
|
||||
length, &sLiteralFinalizer, &ignored);
|
||||
if (!str)
|
||||
return false;
|
||||
vp.setString(str);
|
||||
|
@ -267,13 +267,22 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
JSString* str = JS_NewExternalString(cx,
|
||||
static_cast<char16_t*>(buf->Data()),
|
||||
length, &sDOMStringFinalizer);
|
||||
bool isExternal;
|
||||
JSString* str = JS_NewMaybeExternalString(cx,
|
||||
static_cast<char16_t*>(buf->Data()),
|
||||
length, &sDOMStringFinalizer, &isExternal);
|
||||
if (!str) {
|
||||
return false;
|
||||
}
|
||||
rval.setString(str);
|
||||
|
||||
// If JS_NewMaybeExternalString returns non-external string, finalizer
|
||||
// won't be called. Do not store it to cache.
|
||||
if (!isExternal) {
|
||||
*sharedBuffer = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!cache) {
|
||||
cache = new ZoneStringCache();
|
||||
JS_SetZoneUserData(zone, cache);
|
||||
|
@ -936,12 +936,6 @@ NS_IMPL_ISUPPORTS(VsyncChildCreateCallback, nsIIPCBackgroundChildCreateCallback)
|
||||
static RefreshDriverTimer* sRegularRateTimer;
|
||||
static InactiveRefreshDriverTimer* sThrottledRateTimer;
|
||||
|
||||
#ifdef XP_WIN
|
||||
static int32_t sHighPrecisionTimerRequests = 0;
|
||||
// a bare pointer to avoid introducing a static constructor
|
||||
static nsITimer *sDisableHighPrecisionTimersTimer = nullptr;
|
||||
#endif
|
||||
|
||||
static void
|
||||
CreateContentVsyncRefreshTimer(void*)
|
||||
{
|
||||
@ -1021,16 +1015,6 @@ nsRefreshDriver::Shutdown()
|
||||
|
||||
sRegularRateTimer = nullptr;
|
||||
sThrottledRateTimer = nullptr;
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (sDisableHighPrecisionTimersTimer) {
|
||||
sDisableHighPrecisionTimersTimer->Cancel();
|
||||
NS_RELEASE(sDisableHighPrecisionTimersTimer);
|
||||
timeEndPeriod(1);
|
||||
} else if (sHighPrecisionTimerRequests) {
|
||||
timeEndPeriod(1);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* static */ int32_t
|
||||
@ -1134,7 +1118,6 @@ nsRefreshDriver::nsRefreshDriver(nsPresContext* aPresContext)
|
||||
mNeedToRecomputeVisibility(false),
|
||||
mTestControllingRefreshes(false),
|
||||
mViewManagerFlushIsPending(false),
|
||||
mRequestedHighPrecision(false),
|
||||
mInRefresh(false),
|
||||
mWaitingForTransaction(false),
|
||||
mSkippedPaints(false),
|
||||
@ -1374,89 +1357,6 @@ nsRefreshDriver::StopTimer()
|
||||
|
||||
mActiveTimer->RemoveRefreshDriver(this);
|
||||
mActiveTimer = nullptr;
|
||||
|
||||
if (mRequestedHighPrecision) {
|
||||
SetHighPrecisionTimersEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
static void
|
||||
DisableHighPrecisionTimersCallback(nsITimer *aTimer, void *aClosure)
|
||||
{
|
||||
timeEndPeriod(1);
|
||||
NS_RELEASE(sDisableHighPrecisionTimersTimer);
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
nsRefreshDriver::ConfigureHighPrecision()
|
||||
{
|
||||
bool haveUnthrottledFrameRequestCallbacks =
|
||||
mFrameRequestCallbackDocs.Length() > 0;
|
||||
|
||||
// if the only change that's needed is that we need high precision,
|
||||
// then just set that
|
||||
if (!mThrottled && !mRequestedHighPrecision &&
|
||||
haveUnthrottledFrameRequestCallbacks) {
|
||||
SetHighPrecisionTimersEnabled(true);
|
||||
} else if (mRequestedHighPrecision && !haveUnthrottledFrameRequestCallbacks) {
|
||||
SetHighPrecisionTimersEnabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsRefreshDriver::SetHighPrecisionTimersEnabled(bool aEnable)
|
||||
{
|
||||
LOG("[%p] SetHighPrecisionTimersEnabled (%s)", this, aEnable ? "true" : "false");
|
||||
|
||||
if (aEnable) {
|
||||
NS_ASSERTION(!mRequestedHighPrecision, "SetHighPrecisionTimersEnabled(true) called when already requested!");
|
||||
#ifdef XP_WIN
|
||||
if (++sHighPrecisionTimerRequests == 1) {
|
||||
// If we had a timer scheduled to disable it, that means that it's already
|
||||
// enabled; just cancel the timer. Otherwise, really enable it.
|
||||
if (sDisableHighPrecisionTimersTimer) {
|
||||
sDisableHighPrecisionTimersTimer->Cancel();
|
||||
NS_RELEASE(sDisableHighPrecisionTimersTimer);
|
||||
} else {
|
||||
timeBeginPeriod(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
mRequestedHighPrecision = true;
|
||||
} else {
|
||||
NS_ASSERTION(mRequestedHighPrecision, "SetHighPrecisionTimersEnabled(false) called when not requested!");
|
||||
#ifdef XP_WIN
|
||||
if (--sHighPrecisionTimerRequests == 0) {
|
||||
// Don't jerk us around between high precision and low precision
|
||||
// timers; instead, only allow leaving high precision timers
|
||||
// after 90 seconds. This is arbitrary, but hopefully good
|
||||
// enough.
|
||||
NS_ASSERTION(!sDisableHighPrecisionTimersTimer, "We shouldn't have an outstanding disable-high-precision timer !");
|
||||
|
||||
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
|
||||
if (timer) {
|
||||
if (nsPresContext* pc = GetPresContext()) {
|
||||
timer->SetTarget(
|
||||
pc->Document()->EventTargetFor(TaskCategory::Other));
|
||||
}
|
||||
timer.forget(&sDisableHighPrecisionTimersTimer);
|
||||
sDisableHighPrecisionTimersTimer->
|
||||
InitWithNamedFuncCallback(DisableHighPrecisionTimersCallback,
|
||||
nullptr,
|
||||
90 * 1000,
|
||||
nsITimer::TYPE_ONE_SHOT,
|
||||
"DisableHighPrecisionTimersCallback");
|
||||
} else {
|
||||
// might happen if we're shutting down XPCOM; just drop the time period down
|
||||
// immediately
|
||||
timeEndPeriod(1);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
mRequestedHighPrecision = false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
@ -2058,8 +1958,6 @@ nsRefreshDriver::Tick(int64_t aNowEpoch, TimeStamp aNowTime)
|
||||
observer->DidRefresh();
|
||||
}
|
||||
|
||||
ConfigureHighPrecision();
|
||||
|
||||
NS_ASSERTION(mInRefresh, "Still in refresh");
|
||||
|
||||
if (mPresContext->IsRoot() && XRE_IsContentProcess() && gfxPrefs::AlwaysPaint()) {
|
||||
@ -2335,7 +2233,6 @@ nsRefreshDriver::ScheduleFrameRequestCallbacks(nsIDocument* aDocument)
|
||||
}
|
||||
|
||||
// make sure that the timer is running
|
||||
ConfigureHighPrecision();
|
||||
EnsureTimerStarted();
|
||||
}
|
||||
|
||||
@ -2344,7 +2241,6 @@ nsRefreshDriver::RevokeFrameRequestCallbacks(nsIDocument* aDocument)
|
||||
{
|
||||
mFrameRequestCallbackDocs.RemoveElement(aDocument);
|
||||
mThrottledFrameRequestCallbackDocs.RemoveElement(aDocument);
|
||||
ConfigureHighPrecision();
|
||||
// No need to worry about restarting our timer in slack mode if it's already
|
||||
// running; that will happen automatically when it fires.
|
||||
}
|
||||
|
@ -438,7 +438,6 @@ private:
|
||||
bool mNeedToRecomputeVisibility;
|
||||
bool mTestControllingRefreshes;
|
||||
bool mViewManagerFlushIsPending;
|
||||
bool mRequestedHighPrecision;
|
||||
bool mInRefresh;
|
||||
|
||||
// True if the refresh driver is suspended waiting for transaction
|
||||
@ -488,10 +487,6 @@ private:
|
||||
|
||||
friend class mozilla::RefreshDriverTimer;
|
||||
|
||||
// turn on or turn off high precision based on various factors
|
||||
void ConfigureHighPrecision();
|
||||
void SetHighPrecisionTimersEnabled(bool aEnable);
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
// `true` if we are currently in jank-critical mode.
|
||||
|
@ -114,12 +114,18 @@ RenderFrameParent::Init(nsFrameLoader* aFrameLoader)
|
||||
|
||||
TabParent* browser = TabParent::GetFrom(mFrameLoader);
|
||||
if (XRE_IsParentProcess()) {
|
||||
PCompositorBridgeChild* compositor = nullptr;
|
||||
if (lm) {
|
||||
compositor = lm->GetCompositorBridgeChild();
|
||||
}
|
||||
|
||||
// Our remote frame will push layers updates to the compositor,
|
||||
// and we'll keep an indirect reference to that tree.
|
||||
browser->Manager()->AsContentParent()->AllocateLayerTreeId(browser, &mLayersId);
|
||||
if (lm && lm->GetCompositorBridgeChild()) {
|
||||
mLayersConnected = lm->GetCompositorBridgeChild()->SendNotifyChildCreated(mLayersId);
|
||||
}
|
||||
GPUProcessManager* gpm = GPUProcessManager::Get();
|
||||
mLayersConnected = gpm->AllocateAndConnectLayerTreeId(
|
||||
compositor,
|
||||
browser->Manager()->AsContentParent()->OtherPid(),
|
||||
&mLayersId);
|
||||
} else if (XRE_IsContentProcess()) {
|
||||
ContentChild::GetSingleton()->SendAllocateLayerTreeId(browser->Manager()->ChildID(), browser->GetTabId(), &mLayersId);
|
||||
mLayersConnected = CompositorBridgeChild::Get()->SendNotifyChildCreated(mLayersId);
|
||||
|
@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
|
||||
|
||||
The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
|
||||
|
||||
The git commit ID used was 4ab4577699fb42931f0fbd39826fa085dace4589 (2017-03-15 13:48:03 +0100)
|
||||
The git commit ID used was 04826edb13c23a2b53732d63b09b24e05ca83d87 (2017-03-31 09:05:07 -0700)
|
||||
|
@ -28,28 +28,28 @@ std::atomic<bool> load_callback{ false };
|
||||
long data_cb(cubeb_stream * stream, void * user, const void * inputbuffer, void * outputbuffer, long nframes)
|
||||
{
|
||||
if (load_callback) {
|
||||
printf("Sleeping...\n");
|
||||
fprintf(stderr, "Sleeping...\n");
|
||||
delay(100000);
|
||||
printf("Sleeping done\n");
|
||||
fprintf(stderr, "Sleeping done\n");
|
||||
}
|
||||
return nframes;
|
||||
}
|
||||
|
||||
void state_cb(cubeb_stream * stream, void * /*user*/, cubeb_state state)
|
||||
{
|
||||
assert(stream);
|
||||
ASSERT_TRUE(!!stream);
|
||||
|
||||
switch (state) {
|
||||
case CUBEB_STATE_STARTED:
|
||||
printf("stream started\n"); break;
|
||||
fprintf(stderr, "stream started\n"); break;
|
||||
case CUBEB_STATE_STOPPED:
|
||||
printf("stream stopped\n"); break;
|
||||
fprintf(stderr, "stream stopped\n"); break;
|
||||
case CUBEB_STATE_DRAINED:
|
||||
assert(false && "this test is not supposed to drain"); break;
|
||||
FAIL() << "this test is not supposed to drain"; break;
|
||||
case CUBEB_STATE_ERROR:
|
||||
printf("stream error\n"); break;
|
||||
fprintf(stderr, "stream error\n"); break;
|
||||
default:
|
||||
assert(false && "this test is not supposed to have a weird state"); break;
|
||||
FAIL() << "this test is not supposed to have a weird state"; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,6 +25,9 @@ struct cubeb_stream {
|
||||
#if defined(USE_PULSE)
|
||||
int pulse_init(cubeb ** context, char const * context_name);
|
||||
#endif
|
||||
#if defined(USE_PULSE_RUST)
|
||||
int pulse_rust_init(cubeb ** contet, char const * context_name);
|
||||
#endif
|
||||
#if defined(USE_JACK)
|
||||
int jack_init (cubeb ** context, char const * context_name);
|
||||
#endif
|
||||
@ -111,6 +114,10 @@ cubeb_init(cubeb ** context, char const * context_name, char const * backend_nam
|
||||
if (!strcmp(backend_name, "pulse")) {
|
||||
#if defined(USE_PULSE)
|
||||
init_oneshot = pulse_init;
|
||||
#endif
|
||||
} else if (!strcmp(backend_name, "pulse-rust")) {
|
||||
#if defined(USE_PULSE_RUST)
|
||||
init_oneshot = pulse_rust_init;
|
||||
#endif
|
||||
} else if (!strcmp(backend_name, "jack")) {
|
||||
#if defined(USE_JACK)
|
||||
|
@ -158,9 +158,9 @@ struct mixing_wrapper {
|
||||
template <typename T>
|
||||
struct mixing_impl : public mixing_wrapper {
|
||||
|
||||
typedef std::function<void(T * const, long, T *,
|
||||
unsigned int, unsigned int,
|
||||
cubeb_channel_layout, cubeb_channel_layout)> downmix_func;
|
||||
typedef void (*downmix_func)(T * const, long, T *,
|
||||
unsigned int, unsigned int,
|
||||
cubeb_channel_layout, cubeb_channel_layout);
|
||||
|
||||
mixing_impl(downmix_func dmfunc) {
|
||||
downmix_wrapper = dmfunc;
|
||||
@ -1224,12 +1224,13 @@ audiounit_get_preferred_channel_layout(cubeb * ctx, cubeb_channel_layout * layou
|
||||
// If we already have at least one cubeb stream, then the current channel
|
||||
// layout must be updated. We can return it directly.
|
||||
if (ctx->active_streams) {
|
||||
return ctx->layout;
|
||||
*layout = ctx->layout;
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
// If there is no existed stream, then we create a default ouput unit and
|
||||
// use it to get the current used channel layout.
|
||||
AudioUnit output_unit;
|
||||
AudioUnit output_unit = nullptr;
|
||||
audiounit_create_unit(&output_unit, OUTPUT, 0);
|
||||
*layout = audiounit_get_current_channel_layout(output_unit);
|
||||
}
|
||||
@ -1823,11 +1824,10 @@ audiounit_create_unit(AudioUnit * unit, io_side side, AudioDeviceID device)
|
||||
OSStatus rv;
|
||||
int r;
|
||||
|
||||
if (*unit == nullptr) {
|
||||
int r = audiounit_new_unit_instance(unit, side, device);
|
||||
if (r != CUBEB_OK) {
|
||||
return r;
|
||||
}
|
||||
assert(*unit == nullptr);
|
||||
r = audiounit_new_unit_instance(unit, side, device);
|
||||
if (r != CUBEB_OK) {
|
||||
return r;
|
||||
}
|
||||
assert(*unit);
|
||||
|
||||
|
@ -47,7 +47,7 @@ public:
|
||||
return;
|
||||
}
|
||||
PodCopy(storage, str, length);
|
||||
storage[length + 1] = '\0';
|
||||
storage[length] = '\0';
|
||||
}
|
||||
char const * get() {
|
||||
return storage;
|
||||
|
@ -142,7 +142,11 @@ sink_info_callback(pa_context * context, const pa_sink_info * info, int eol, voi
|
||||
static void
|
||||
server_info_callback(pa_context * context, const pa_server_info * info, void * u)
|
||||
{
|
||||
WRAP(pa_context_get_sink_info_by_name)(context, info->default_sink_name, sink_info_callback, u);
|
||||
pa_operation * o;
|
||||
o = WRAP(pa_context_get_sink_info_by_name)(context, info->default_sink_name, sink_info_callback, u);
|
||||
if (o) {
|
||||
WRAP(pa_operation_unref)(o);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
@ -576,6 +580,7 @@ pulse_init(cubeb ** context, char const * context_name)
|
||||
{
|
||||
void * libpulse = NULL;
|
||||
cubeb * ctx;
|
||||
pa_operation * o;
|
||||
|
||||
*context = NULL;
|
||||
|
||||
@ -614,9 +619,17 @@ pulse_init(cubeb ** context, char const * context_name)
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
/* server_info_callback performs a second async query, which is
|
||||
responsible for initializing default_sink_info and signalling the
|
||||
mainloop to end the wait. */
|
||||
WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
|
||||
WRAP(pa_context_get_server_info)(ctx->context, server_info_callback, ctx);
|
||||
o = WRAP(pa_context_get_server_info)(ctx->context, server_info_callback, ctx);
|
||||
if (o) {
|
||||
operation_wait(ctx, NULL, o);
|
||||
WRAP(pa_operation_unref)(o);
|
||||
}
|
||||
WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
|
||||
assert(ctx->default_sink_info);
|
||||
|
||||
*context = ctx;
|
||||
|
||||
@ -636,12 +649,6 @@ pulse_get_max_channel_count(cubeb * ctx, uint32_t * max_channels)
|
||||
(void)ctx;
|
||||
assert(ctx && max_channels);
|
||||
|
||||
WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
|
||||
while (!ctx->default_sink_info) {
|
||||
WRAP(pa_threaded_mainloop_wait)(ctx->mainloop);
|
||||
}
|
||||
WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
|
||||
|
||||
*max_channels = ctx->default_sink_info->channel_map.channels;
|
||||
|
||||
return CUBEB_OK;
|
||||
@ -653,12 +660,6 @@ pulse_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate)
|
||||
assert(ctx && rate);
|
||||
(void)ctx;
|
||||
|
||||
WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
|
||||
while (!ctx->default_sink_info) {
|
||||
WRAP(pa_threaded_mainloop_wait)(ctx->mainloop);
|
||||
}
|
||||
WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
|
||||
|
||||
*rate = ctx->default_sink_info->sample_spec.rate;
|
||||
|
||||
return CUBEB_OK;
|
||||
@ -670,12 +671,6 @@ pulse_get_preferred_channel_layout(cubeb * ctx, cubeb_channel_layout * layout)
|
||||
assert(ctx && layout);
|
||||
(void)ctx;
|
||||
|
||||
WRAP(pa_threaded_mainloop_lock)(ctx->mainloop);
|
||||
while (!ctx->default_sink_info) {
|
||||
WRAP(pa_threaded_mainloop_wait)(ctx->mainloop);
|
||||
}
|
||||
WRAP(pa_threaded_mainloop_unlock)(ctx->mainloop);
|
||||
|
||||
*layout = channel_map_to_layout(&ctx->default_sink_info->channel_map);
|
||||
|
||||
return CUBEB_OK;
|
||||
@ -711,9 +706,7 @@ pulse_context_destroy(cubeb * ctx)
|
||||
static void
|
||||
pulse_destroy(cubeb * ctx)
|
||||
{
|
||||
if (ctx->context_name) {
|
||||
free(ctx->context_name);
|
||||
}
|
||||
free(ctx->context_name);
|
||||
if (ctx->context) {
|
||||
pulse_context_destroy(ctx);
|
||||
}
|
||||
@ -726,9 +719,7 @@ pulse_destroy(cubeb * ctx)
|
||||
if (ctx->libpulse) {
|
||||
dlclose(ctx->libpulse);
|
||||
}
|
||||
if (ctx->default_sink_info) {
|
||||
free(ctx->default_sink_info);
|
||||
}
|
||||
free(ctx->default_sink_info);
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
@ -1059,10 +1050,6 @@ pulse_stream_set_volume(cubeb_stream * stm, float volume)
|
||||
|
||||
WRAP(pa_threaded_mainloop_lock)(stm->context->mainloop);
|
||||
|
||||
while (!stm->context->default_sink_info) {
|
||||
WRAP(pa_threaded_mainloop_wait)(stm->context->mainloop);
|
||||
}
|
||||
|
||||
/* if the pulse daemon is configured to use flat volumes,
|
||||
* apply our own gain instead of changing the input volume on the sink. */
|
||||
if (stm->context->default_sink_info->flags & PA_SINK_FLAT_VOLUME) {
|
||||
|
@ -15,40 +15,6 @@
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
|
||||
/* This enum allows choosing the behaviour of the queue. */
|
||||
enum ThreadSafety
|
||||
{
|
||||
/* No attempt to synchronize the queue is made. The queue is only safe when
|
||||
* used on a single thread. */
|
||||
Unsafe,
|
||||
/** Atomics are used to synchronize read and write. The queue is safe when
|
||||
* used from two thread: one producer, one consumer. */
|
||||
Safe
|
||||
};
|
||||
|
||||
/** Policy to enable thread safety on the queue. */
|
||||
template<ThreadSafety>
|
||||
struct ThreadSafePolicy;
|
||||
|
||||
typedef int RingBufferIndex;
|
||||
|
||||
/** Policy for thread-safe internal index for the queue. */
|
||||
template<>
|
||||
struct ThreadSafePolicy<Safe>
|
||||
{
|
||||
typedef std::atomic<RingBufferIndex> IndexType;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is the version with a simple `int` for index, for use when only a single
|
||||
* thread is producing and releasing data.
|
||||
*/
|
||||
template<>
|
||||
struct ThreadSafePolicy<Unsafe>
|
||||
{
|
||||
typedef RingBufferIndex IndexType;
|
||||
};
|
||||
|
||||
/**
|
||||
* Single producer single consumer lock-free and wait-free ring buffer.
|
||||
*
|
||||
@ -82,8 +48,7 @@ struct ThreadSafePolicy<Unsafe>
|
||||
* providing an external buffer to copy into is an easy way to have linear
|
||||
* data for further processing.
|
||||
*/
|
||||
template <typename T,
|
||||
ThreadSafety Safety = ThreadSafety::Safe>
|
||||
template <typename T>
|
||||
class ring_buffer_base
|
||||
{
|
||||
public:
|
||||
@ -95,12 +60,12 @@ public:
|
||||
*
|
||||
* @param capacity The maximum number of element this ring buffer will hold.
|
||||
*/
|
||||
ring_buffer_base(RingBufferIndex capacity)
|
||||
ring_buffer_base(int capacity)
|
||||
/* One more element to distinguish from empty and full buffer. */
|
||||
: capacity_(capacity + 1)
|
||||
{
|
||||
assert(storage_capacity() <
|
||||
std::numeric_limits<RingBufferIndex>::max() / 2 &&
|
||||
std::numeric_limits<int>::max() / 2 &&
|
||||
"buffer too large for the type of index used.");
|
||||
assert(capacity_ > 0);
|
||||
|
||||
@ -119,7 +84,7 @@ public:
|
||||
* @param count The number of elements to enqueue.
|
||||
* @return The number of element enqueued.
|
||||
*/
|
||||
RingBufferIndex enqueue_default(RingBufferIndex count)
|
||||
int enqueue_default(int count)
|
||||
{
|
||||
return enqueue(nullptr, count);
|
||||
}
|
||||
@ -132,7 +97,7 @@ public:
|
||||
*
|
||||
* @return 1 if the element was inserted, 0 otherwise.
|
||||
*/
|
||||
RingBufferIndex enqueue(T& element)
|
||||
int enqueue(T& element)
|
||||
{
|
||||
return enqueue(&element, 1);
|
||||
}
|
||||
@ -147,27 +112,27 @@ public:
|
||||
* @return The number of elements successfully coped from `elements` and inserted
|
||||
* into the ring buffer.
|
||||
*/
|
||||
RingBufferIndex enqueue(T * elements, RingBufferIndex count)
|
||||
int enqueue(T * elements, int count)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
assert_correct_thread(producer_id);
|
||||
#endif
|
||||
|
||||
RingBufferIndex rd_idx = read_index_;
|
||||
RingBufferIndex wr_idx = write_index_;
|
||||
int rd_idx = read_index_.load(std::memory_order::memory_order_relaxed);
|
||||
int wr_idx = write_index_.load(std::memory_order::memory_order_relaxed);
|
||||
|
||||
if (full_internal(rd_idx, wr_idx)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
RingBufferIndex to_write =
|
||||
int to_write =
|
||||
std::min(available_write_internal(rd_idx, wr_idx), count);
|
||||
|
||||
/* First part, from the write index to the end of the array. */
|
||||
RingBufferIndex first_part = std::min(storage_capacity() - wr_idx,
|
||||
int first_part = std::min(storage_capacity() - wr_idx,
|
||||
to_write);
|
||||
/* Second part, from the beginning of the array */
|
||||
RingBufferIndex second_part = to_write - first_part;
|
||||
int second_part = to_write - first_part;
|
||||
|
||||
if (elements) {
|
||||
Copy(data_.get() + wr_idx, elements, first_part);
|
||||
@ -177,7 +142,7 @@ public:
|
||||
ConstructDefault(data_.get(), second_part);
|
||||
}
|
||||
|
||||
write_index_ = increment_index(wr_idx, to_write);
|
||||
write_index_.store(increment_index(wr_idx, to_write), std::memory_order::memory_order_release);
|
||||
|
||||
return to_write;
|
||||
}
|
||||
@ -192,31 +157,31 @@ public:
|
||||
* @param count The maximum number of elements to dequeue.
|
||||
* @return The number of elements written to `elements`.
|
||||
*/
|
||||
RingBufferIndex dequeue(T * elements, RingBufferIndex count)
|
||||
int dequeue(T * elements, int count)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
assert_correct_thread(consumer_id);
|
||||
#endif
|
||||
|
||||
RingBufferIndex wr_idx = write_index_;
|
||||
RingBufferIndex rd_idx = read_index_;
|
||||
int wr_idx = write_index_.load(std::memory_order::memory_order_acquire);
|
||||
int rd_idx = read_index_.load(std::memory_order::memory_order_relaxed);
|
||||
|
||||
if (empty_internal(rd_idx, wr_idx)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
RingBufferIndex to_read =
|
||||
int to_read =
|
||||
std::min(available_read_internal(rd_idx, wr_idx), count);
|
||||
|
||||
RingBufferIndex first_part = std::min(storage_capacity() - rd_idx, to_read);
|
||||
RingBufferIndex second_part = to_read - first_part;
|
||||
int first_part = std::min(storage_capacity() - rd_idx, to_read);
|
||||
int second_part = to_read - first_part;
|
||||
|
||||
if (elements) {
|
||||
Copy(elements, data_.get() + rd_idx, first_part);
|
||||
Copy(elements + first_part, data_.get(), second_part);
|
||||
}
|
||||
|
||||
read_index_ = increment_index(rd_idx, to_read);
|
||||
read_index_.store(increment_index(rd_idx, to_read), std::memory_order::memory_order_relaxed);
|
||||
|
||||
return to_read;
|
||||
}
|
||||
@ -227,12 +192,13 @@ public:
|
||||
*
|
||||
* @return The number of available elements for reading.
|
||||
*/
|
||||
RingBufferIndex available_read() const
|
||||
int available_read() const
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
assert_correct_thread(consumer_id);
|
||||
#endif
|
||||
return available_read_internal(read_index_, write_index_);
|
||||
return available_read_internal(read_index_.load(std::memory_order::memory_order_relaxed),
|
||||
write_index_.load(std::memory_order::memory_order_relaxed));
|
||||
}
|
||||
/**
|
||||
* Get the number of available elements for consuming.
|
||||
@ -241,12 +207,13 @@ public:
|
||||
*
|
||||
* @return The number of empty slots in the buffer, available for writing.
|
||||
*/
|
||||
RingBufferIndex available_write() const
|
||||
int available_write() const
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
assert_correct_thread(producer_id);
|
||||
#endif
|
||||
return available_write_internal(read_index_, write_index_);
|
||||
return available_write_internal(read_index_.load(std::memory_order::memory_order_relaxed),
|
||||
write_index_.load(std::memory_order::memory_order_relaxed));
|
||||
}
|
||||
/**
|
||||
* Get the total capacity, for this ring buffer.
|
||||
@ -255,7 +222,7 @@ public:
|
||||
*
|
||||
* @return The maximum capacity of this ring buffer.
|
||||
*/
|
||||
RingBufferIndex capacity() const
|
||||
int capacity() const
|
||||
{
|
||||
return storage_capacity() - 1;
|
||||
}
|
||||
@ -266,8 +233,8 @@ private:
|
||||
* @param write_index the write index to consider
|
||||
* @return true if the ring buffer is empty, false otherwise.
|
||||
**/
|
||||
bool empty_internal(RingBufferIndex read_index,
|
||||
RingBufferIndex write_index) const
|
||||
bool empty_internal(int read_index,
|
||||
int write_index) const
|
||||
{
|
||||
return write_index == read_index;
|
||||
}
|
||||
@ -280,8 +247,8 @@ private:
|
||||
* @param write_index the write index to consider
|
||||
* @return true if the ring buffer is full, false otherwise.
|
||||
**/
|
||||
bool full_internal(RingBufferIndex read_index,
|
||||
RingBufferIndex write_index) const
|
||||
bool full_internal(int read_index,
|
||||
int write_index) const
|
||||
{
|
||||
return (write_index + 1) % storage_capacity() == read_index;
|
||||
}
|
||||
@ -300,9 +267,9 @@ private:
|
||||
*
|
||||
* @return the number of available elements for reading.
|
||||
*/
|
||||
RingBufferIndex
|
||||
available_read_internal(RingBufferIndex read_index,
|
||||
RingBufferIndex write_index) const
|
||||
int
|
||||
available_read_internal(int read_index,
|
||||
int write_index) const
|
||||
{
|
||||
if (write_index >= read_index) {
|
||||
return write_index - read_index;
|
||||
@ -315,9 +282,9 @@ private:
|
||||
*
|
||||
* @return the number of elements that can be written into the array.
|
||||
*/
|
||||
RingBufferIndex
|
||||
available_write_internal(RingBufferIndex read_index,
|
||||
RingBufferIndex write_index) const
|
||||
int
|
||||
available_write_internal(int read_index,
|
||||
int write_index) const
|
||||
{
|
||||
/* We substract one element here to always keep at least one sample
|
||||
* free in the buffer, to distinguish between full and empty array. */
|
||||
@ -334,8 +301,8 @@ private:
|
||||
* @param increment the number by which `index` is incremented.
|
||||
* @return the new index.
|
||||
*/
|
||||
RingBufferIndex
|
||||
increment_index(RingBufferIndex index, RingBufferIndex increment) const
|
||||
int
|
||||
increment_index(int index, int increment) const
|
||||
{
|
||||
assert(increment >= 0);
|
||||
return (index + increment) % storage_capacity();
|
||||
@ -357,10 +324,10 @@ private:
|
||||
}
|
||||
#endif
|
||||
/** Index at which the oldest element is at, in samples. */
|
||||
typename ThreadSafePolicy<Safety>::IndexType read_index_;
|
||||
std::atomic<int> read_index_;
|
||||
/** Index at which to write new elements. `write_index` is always at
|
||||
* least one element ahead of `read_index_`. */
|
||||
typename ThreadSafePolicy<Safety>::IndexType write_index_;
|
||||
std::atomic<int> write_index_;
|
||||
/** Maximum number of elements that can be stored in the ring buffer. */
|
||||
const int capacity_;
|
||||
/** Data storage */
|
||||
@ -376,8 +343,7 @@ private:
|
||||
/**
|
||||
* Adapter for `ring_buffer_base` that exposes an interface in frames.
|
||||
*/
|
||||
template <typename T,
|
||||
ThreadSafety Safety = ThreadSafety::Safe>
|
||||
template <typename T>
|
||||
class audio_ring_buffer_base
|
||||
{
|
||||
public:
|
||||
@ -407,7 +373,7 @@ public:
|
||||
}
|
||||
/**
|
||||
* @brief Enqueue `frames_count` frames of audio.
|
||||
*
|
||||
*
|
||||
* Only safely called from the producer thread.
|
||||
*
|
||||
* @param [in] frames If non-null, the frames to enqueue.
|
||||
@ -497,7 +463,7 @@ private:
|
||||
/** Number of channels of audio that will stream through this ring buffer. */
|
||||
int channel_count;
|
||||
/** The underlying ring buffer that is used to store the data. */
|
||||
ring_buffer_base<T, Safety> ring_buffer;
|
||||
ring_buffer_base<T> ring_buffer;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -506,27 +472,13 @@ private:
|
||||
* without explicit synchronization.
|
||||
*/
|
||||
template<typename T>
|
||||
using lock_free_queue = ring_buffer_base<T, Safe>;
|
||||
/**
|
||||
* An instantiation of the `ring_buffer_base` type, to be used on a single
|
||||
* thread: it is not safe to use from multiple threads without explicit external
|
||||
* synchronization.
|
||||
*/
|
||||
template<typename T>
|
||||
using queue = ring_buffer_base<T, Unsafe>;
|
||||
using lock_free_queue = ring_buffer_base<T>;
|
||||
/**
|
||||
* Lock-free instantiation of the `audio_ring_buffer` type. This is safe to use
|
||||
* from two threads, one producer, one consumer (that never change role),
|
||||
* without explicit synchronization.
|
||||
*/
|
||||
template<typename T>
|
||||
using lock_free_audio_ring_buffer = audio_ring_buffer_base<T, Safe>;
|
||||
/**
|
||||
* An instantiation of the `audio_ring_buffer` type, to be used on a single
|
||||
* thread: it is not safe to use from multiple threads without explicit external
|
||||
* synchronization.
|
||||
*/
|
||||
template<typename T>
|
||||
using audio_ring_buffer = audio_ring_buffer_base<T, Unsafe>;
|
||||
using lock_free_audio_ring_buffer = audio_ring_buffer_base<T>;
|
||||
|
||||
#endif // CUBEB_RING_BUFFER_H
|
||||
|
@ -757,7 +757,7 @@ refill_callback_duplex(cubeb_stream * stm)
|
||||
bool
|
||||
refill_callback_input(cubeb_stream * stm)
|
||||
{
|
||||
bool rv, consumed_all_buffer;
|
||||
bool rv;
|
||||
|
||||
XASSERT(has_input(stm) && !has_output(stm));
|
||||
|
||||
@ -780,11 +780,10 @@ refill_callback_input(cubeb_stream * stm)
|
||||
0);
|
||||
|
||||
XASSERT(read >= 0);
|
||||
consumed_all_buffer = (unsigned long) read == stm->linear_input_buffer.length();
|
||||
|
||||
stm->linear_input_buffer.clear();
|
||||
|
||||
return consumed_all_buffer;
|
||||
return !stm->draining;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -87,20 +87,9 @@ AudioRecordJni::AudioRecordJni(AudioManager* audio_manager)
|
||||
ALOGD("ctor%s", GetThreadInfo().c_str());
|
||||
RTC_DCHECK(audio_parameters_.is_valid());
|
||||
RTC_CHECK(j_environment_);
|
||||
JNINativeMethod native_methods[] = {
|
||||
{"nativeCacheDirectBufferAddress", "(Ljava/nio/ByteBuffer;J)V",
|
||||
reinterpret_cast<void*>(
|
||||
&webrtc::AudioRecordJni::CacheDirectBufferAddress)},
|
||||
{"nativeDataIsRecorded", "(IJ)V",
|
||||
reinterpret_cast<void*>(&webrtc::AudioRecordJni::DataIsRecorded)}};
|
||||
j_native_registration_ = j_environment_->RegisterNatives(
|
||||
"org/webrtc/voiceengine/WebRtcAudioRecord",
|
||||
native_methods, arraysize(native_methods));
|
||||
j_audio_record_.reset(new JavaAudioRecord(
|
||||
j_native_registration_.get(),
|
||||
j_native_registration_->NewObject(
|
||||
"<init>", "(Landroid/content/Context;J)V",
|
||||
JVM::GetInstance()->context(), PointerTojlong(this))));
|
||||
// Defer creation of the j_audio_record object so we can defer native registration.
|
||||
// See Mozilla bug 1349581
|
||||
|
||||
// Detach from this thread since we want to use the checker to verify calls
|
||||
// from the Java based audio thread.
|
||||
thread_checker_java_.DetachFromThread();
|
||||
@ -112,6 +101,28 @@ AudioRecordJni::~AudioRecordJni() {
|
||||
Terminate();
|
||||
}
|
||||
|
||||
void
|
||||
AudioRecordJni::EnsureRecordObject()
|
||||
{
|
||||
if (!j_audio_record_.get()) {
|
||||
RTC_DCHECK(!j_native_registration_.get());
|
||||
JNINativeMethod native_methods[] = {
|
||||
{"nativeCacheDirectBufferAddress", "(Ljava/nio/ByteBuffer;J)V",
|
||||
reinterpret_cast<void*>(
|
||||
&webrtc::AudioRecordJni::CacheDirectBufferAddress)},
|
||||
{"nativeDataIsRecorded", "(IJ)V",
|
||||
reinterpret_cast<void*>(&webrtc::AudioRecordJni::DataIsRecorded)}};
|
||||
j_native_registration_ = j_environment_->RegisterNatives(
|
||||
"org/webrtc/voiceengine/WebRtcAudioRecord",
|
||||
native_methods, arraysize(native_methods));
|
||||
j_audio_record_.reset(new JavaAudioRecord(
|
||||
j_native_registration_.get(),
|
||||
j_native_registration_->NewObject(
|
||||
"<init>", "(Landroid/content/Context;J)V",
|
||||
JVM::GetInstance()->context(), PointerTojlong(this))));
|
||||
}
|
||||
}
|
||||
|
||||
int32_t AudioRecordJni::Init() {
|
||||
ALOGD("Init%s", GetThreadInfo().c_str());
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
@ -130,6 +141,7 @@ int32_t AudioRecordJni::InitRecording() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(!initialized_);
|
||||
RTC_DCHECK(!recording_);
|
||||
EnsureRecordObject();
|
||||
int frames_per_buffer = j_audio_record_->InitRecording(
|
||||
audio_parameters_.sample_rate(), audio_parameters_.channels());
|
||||
if (frames_per_buffer < 0) {
|
||||
@ -150,6 +162,7 @@ int32_t AudioRecordJni::StartRecording() {
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(initialized_);
|
||||
RTC_DCHECK(!recording_);
|
||||
RTC_DCHECK(j_audio_record_.get());
|
||||
if (!j_audio_record_->StartRecording()) {
|
||||
ALOGE("StartRecording failed!");
|
||||
return -1;
|
||||
@ -164,6 +177,7 @@ int32_t AudioRecordJni::StopRecording() {
|
||||
if (!initialized_ || !recording_) {
|
||||
return 0;
|
||||
}
|
||||
RTC_DCHECK(j_audio_record_.get());
|
||||
if (!j_audio_record_->StopRecording()) {
|
||||
ALOGE("StopRecording failed!");
|
||||
return -1;
|
||||
@ -197,18 +211,21 @@ void AudioRecordJni::AttachAudioBuffer(AudioDeviceBuffer* audioBuffer) {
|
||||
int32_t AudioRecordJni::EnableBuiltInAEC(bool enable) {
|
||||
ALOGD("EnableBuiltInAEC%s", GetThreadInfo().c_str());
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(j_audio_record_.get());
|
||||
return j_audio_record_->EnableBuiltInAEC(enable) ? 0 : -1;
|
||||
}
|
||||
|
||||
int32_t AudioRecordJni::EnableBuiltInAGC(bool enable) {
|
||||
ALOGD("EnableBuiltInAGC%s", GetThreadInfo().c_str());
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(j_audio_record_.get());
|
||||
return j_audio_record_->EnableBuiltInAGC(enable) ? 0 : -1;
|
||||
}
|
||||
|
||||
int32_t AudioRecordJni::EnableBuiltInNS(bool enable) {
|
||||
ALOGD("EnableBuiltInNS%s", GetThreadInfo().c_str());
|
||||
RTC_DCHECK(thread_checker_.CalledOnValidThread());
|
||||
RTC_DCHECK(j_audio_record_.get());
|
||||
return j_audio_record_->EnableBuiltInNS(enable) ? 0 : -1;
|
||||
}
|
||||
|
||||
|
@ -69,6 +69,8 @@ class AudioRecordJni {
|
||||
explicit AudioRecordJni(AudioManager* audio_manager);
|
||||
~AudioRecordJni();
|
||||
|
||||
void EnsureRecordObject();
|
||||
|
||||
int32_t Init();
|
||||
int32_t Terminate();
|
||||
|
||||
|
@ -585,7 +585,7 @@ void CacheEntry::TransferCallbacks(CacheEntry & aFromEntry)
|
||||
|
||||
uint32_t callbacksLength = mCallbacks.Length();
|
||||
if (callbacksLength) {
|
||||
// Carry the entry reference (unfortunatelly, needs to be done manually...)
|
||||
// Carry the entry reference (unfortunately, needs to be done manually...)
|
||||
for (uint32_t i = 0; i < callbacksLength; ++i)
|
||||
mCallbacks[i].ExchangeEntry(this);
|
||||
|
||||
@ -1934,7 +1934,7 @@ size_t CacheEntry::SizeOfExcludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
||||
// mDoomCallback is an arbitrary class that is probably reported elsewhere.
|
||||
// mOutputStream is reported in mFile.
|
||||
// mWriter is one of many handles we create, but (intentionally) not keep
|
||||
// any reference to, so those unfortunatelly cannot be reported. Handles are
|
||||
// any reference to, so those unfortunately cannot be reported. Handles are
|
||||
// small, though.
|
||||
// mSecurityInfo doesn't impl nsISizeOf.
|
||||
|
||||
|
@ -107,7 +107,7 @@ CacheFileOutputStream::Write(const char * aBuf, uint32_t aCount,
|
||||
return NS_ERROR_FILE_TOO_BIG;
|
||||
}
|
||||
|
||||
// We use 64-bit offset when accessing the file, unfortunatelly we use 32-bit
|
||||
// We use 64-bit offset when accessing the file, unfortunately we use 32-bit
|
||||
// metadata offset, so we cannot handle data bigger than 4GB.
|
||||
if (mPos + aCount > PR_UINT32_MAX) {
|
||||
LOG(("CacheFileOutputStream::Write() - Entry's size exceeds 4GB while it "
|
||||
|
@ -591,7 +591,7 @@ private:
|
||||
bool CleaupCacheDirectoriesRunnable::Post(uint32_t aVersion, uint32_t aActive)
|
||||
{
|
||||
// CleaupCacheDirectories is called regardless what cache version is set up to use.
|
||||
// To obtain the cache1 directory we must unfortunatelly instantiate the old cache
|
||||
// To obtain the cache1 directory we must unfortunately instantiate the old cache
|
||||
// service despite it may not be used at all... This also initialize nsDeleteDir.
|
||||
nsCOMPtr<nsICacheService> service = do_GetService(NS_CACHESERVICE_CONTRACTID);
|
||||
if (!service)
|
||||
|
@ -1551,6 +1551,14 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count)
|
||||
break;
|
||||
|
||||
payloadLength64 = mFramePtr[2] << 8 | mFramePtr[3];
|
||||
|
||||
if(payloadLength64 < 126){
|
||||
// Section 5.2 says that the minimal number of bytes MUST
|
||||
// be used to encode the length in all cases
|
||||
LOG(("WebSocketChannel:: non-minimal-encoded payload length"));
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
} else {
|
||||
// 64 bit length
|
||||
framingLength += 8;
|
||||
@ -1566,6 +1574,14 @@ WebSocketChannel::ProcessInput(uint8_t *buffer, uint32_t count)
|
||||
|
||||
// copy this in case it is unaligned
|
||||
payloadLength64 = NetworkEndian::readInt64(mFramePtr + 2);
|
||||
|
||||
if(payloadLength64 <= 0xffff){
|
||||
// Section 5.2 says that the minimal number of bytes MUST
|
||||
// be used to encode the length in all cases
|
||||
LOG(("WebSocketChannel:: non-minimal-encoded payload length"));
|
||||
return NS_ERROR_ILLEGAL_VALUE;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
payload = mFramePtr + framingLength;
|
||||
|
@ -107,7 +107,7 @@ class nsHtml5TreeOperation {
|
||||
}
|
||||
nsAutoString str;
|
||||
aAtom->ToString(str);
|
||||
return NS_Atomize(str);
|
||||
return NS_AtomizeMainThread(str);
|
||||
}
|
||||
|
||||
static nsresult AppendTextToTextNode(const char16_t* aBuffer,
|
||||
|
35
python/mozbuild/mozbuild/action/unpack_dmg.py
Normal file
35
python/mozbuild/mozbuild/action/unpack_dmg.py
Normal file
@ -0,0 +1,35 @@
|
||||
# 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/.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from mozpack import dmg
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
|
||||
def main(args):
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Explode a DMG into its relevant files')
|
||||
|
||||
parser.add_argument('--dsstore', help='DSStore file from')
|
||||
parser.add_argument('--background', help='Background file from')
|
||||
parser.add_argument('--icon', help='Icon file from')
|
||||
|
||||
parser.add_argument('dmgfile', metavar='DMG_IN',
|
||||
help='DMG File to Unpack')
|
||||
parser.add_argument('outpath', metavar='PATH_OUT',
|
||||
help='Location to put unpacked files')
|
||||
|
||||
options = parser.parse_args(args)
|
||||
|
||||
dmg.extract_dmg(dmgfile=options.dmgfile, output=options.outpath,
|
||||
dsstore=options.dsstore, background=options.background,
|
||||
icon=options.icon)
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
@ -9,6 +9,7 @@ import os
|
||||
import platform
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from mozbuild.util import ensureParentDir
|
||||
|
||||
@ -31,8 +32,8 @@ def chmod(dir):
|
||||
|
||||
def rsync(source, dest):
|
||||
'rsync the contents of directory source into directory dest'
|
||||
# Ensure a trailing slash so rsync copies the *contents* of source.
|
||||
if not source.endswith('/'):
|
||||
# Ensure a trailing slash on directories so rsync copies the *contents* of source.
|
||||
if not source.endswith('/') and os.path.isdir(source):
|
||||
source += '/'
|
||||
subprocess.check_call(['rsync', '-a', '--copy-unsafe-links',
|
||||
source, dest])
|
||||
@ -156,3 +157,53 @@ def create_dmg(source_directory, output_dmg, volume_name, extra_files):
|
||||
set_folder_icon(stagedir, tmpdir)
|
||||
chmod(stagedir)
|
||||
create_dmg_from_staged(stagedir, output_dmg, tmpdir, volume_name)
|
||||
|
||||
|
||||
def extract_dmg_contents(dmgfile, destdir):
|
||||
import buildconfig
|
||||
if is_linux:
|
||||
with mozfile.TemporaryDirectory() as tmpdir:
|
||||
hfs_file = os.path.join(tmpdir, 'firefox.hfs')
|
||||
subprocess.check_call([
|
||||
buildconfig.substs['DMG_TOOL'],
|
||||
'extract',
|
||||
dmgfile,
|
||||
hfs_file
|
||||
],
|
||||
# dmg is seriously chatty
|
||||
stdout=open(os.devnull, 'wb'))
|
||||
subprocess.check_call([
|
||||
buildconfig.substs['HFS_TOOL'], hfs_file, 'extractall', '/', destdir])
|
||||
else:
|
||||
unpack_diskimage = os.path.join(buildconfig.topsrcdir, 'build', 'package',
|
||||
'mac_osx', 'unpack-diskimage')
|
||||
unpack_mountpoint = os.path.join(
|
||||
'/tmp', '{}-unpack'.format(buildconfig.substs['MOZ_APP_NAME']))
|
||||
subprocess.check_call([unpack_diskimage, dmgfile, unpack_mountpoint,
|
||||
destdir])
|
||||
|
||||
|
||||
def extract_dmg(dmgfile, output, dsstore=None, icon=None, background=None):
|
||||
if platform.system() not in ('Darwin', 'Linux'):
|
||||
raise Exception("Don't know how to extract a DMG on '%s'" % platform.system())
|
||||
|
||||
if is_linux:
|
||||
check_tools('DMG_TOOL', 'MKFSHFS', 'HFS_TOOL')
|
||||
|
||||
with mozfile.TemporaryDirectory() as tmpdir:
|
||||
extract_dmg_contents(dmgfile, tmpdir)
|
||||
if os.path.islink(os.path.join(tmpdir, ' ')):
|
||||
# Rsync will fail on the presence of this symlink
|
||||
os.remove(os.path.join(tmpdir, ' '))
|
||||
rsync(tmpdir, output)
|
||||
|
||||
if dsstore:
|
||||
mkdir(os.path.dirname(dsstore))
|
||||
rsync(os.path.join(tmpdir, '.DS_Store'), dsstore)
|
||||
if background:
|
||||
mkdir(os.path.dirname(background))
|
||||
rsync(os.path.join(tmpdir, '.background', os.path.basename(background)),
|
||||
background)
|
||||
if icon:
|
||||
mkdir(os.path.dirname(icon))
|
||||
rsync(os.path.join(tmpdir, '.VolumeIcon.icns'), icon)
|
||||
|
@ -53,7 +53,8 @@ public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIIDENTITYKEYPAIR
|
||||
|
||||
KeyPair(SECKEYPrivateKey* aPrivateKey, SECKEYPublicKey* aPublicKey);
|
||||
KeyPair(SECKEYPrivateKey* aPrivateKey, SECKEYPublicKey* aPublicKey,
|
||||
nsIEventTarget* aOperationThread);
|
||||
|
||||
private:
|
||||
~KeyPair() override
|
||||
@ -81,6 +82,7 @@ private:
|
||||
|
||||
SECKEYPrivateKey * mPrivateKey;
|
||||
SECKEYPublicKey * mPublicKey;
|
||||
nsCOMPtr<nsIEventTarget> mThread;
|
||||
|
||||
KeyPair(const KeyPair &) = delete;
|
||||
void operator=(const KeyPair &) = delete;
|
||||
@ -93,7 +95,8 @@ class KeyGenRunnable : public Runnable, public nsNSSShutDownObject
|
||||
public:
|
||||
NS_DECL_NSIRUNNABLE
|
||||
|
||||
KeyGenRunnable(KeyType keyType, nsIIdentityKeyGenCallback * aCallback);
|
||||
KeyGenRunnable(KeyType keyType, nsIIdentityKeyGenCallback * aCallback,
|
||||
nsIEventTarget* aOperationThread);
|
||||
|
||||
private:
|
||||
~KeyGenRunnable() override
|
||||
@ -119,6 +122,7 @@ private:
|
||||
nsMainThreadPtrHandle<nsIIdentityKeyGenCallback> mCallback; // in
|
||||
nsresult mRv; // out
|
||||
nsCOMPtr<nsIIdentityKeyPair> mKeyPair; // out
|
||||
nsCOMPtr<nsIEventTarget> mThread;
|
||||
|
||||
KeyGenRunnable(const KeyGenRunnable &) = delete;
|
||||
void operator=(const KeyGenRunnable &) = delete;
|
||||
@ -179,6 +183,12 @@ public:
|
||||
= do_GetService("@mozilla.org/psm;1", &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
rv = NS_NewNamedThread("IdentityCrypto", getter_AddRefs(thread));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mThread = thread.forget();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -186,6 +196,8 @@ private:
|
||||
~IdentityCryptoService() = default;
|
||||
IdentityCryptoService(const KeyPair &) = delete;
|
||||
void operator=(const IdentityCryptoService &) = delete;
|
||||
|
||||
nsCOMPtr<nsIEventTarget> mThread;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(IdentityCryptoService, nsIIdentityCryptoService)
|
||||
@ -203,10 +215,8 @@ IdentityCryptoService::GenerateKeyPair(
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = new KeyGenRunnable(keyType, callback);
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsresult rv = NS_NewNamedThread("GenerateKeyPair", getter_AddRefs(thread),
|
||||
r);
|
||||
nsCOMPtr<nsIRunnable> r = new KeyGenRunnable(keyType, callback, mThread);
|
||||
nsresult rv = mThread->Dispatch(r.forget(), NS_DISPATCH_NORMAL);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
@ -221,9 +231,11 @@ IdentityCryptoService::Base64UrlEncode(const nsACString & utf8Input,
|
||||
Base64URLEncodePaddingPolicy::Include, result);
|
||||
}
|
||||
|
||||
KeyPair::KeyPair(SECKEYPrivateKey * privateKey, SECKEYPublicKey * publicKey)
|
||||
KeyPair::KeyPair(SECKEYPrivateKey * privateKey, SECKEYPublicKey * publicKey,
|
||||
nsIEventTarget* operationThread)
|
||||
: mPrivateKey(privateKey)
|
||||
, mPublicKey(publicKey)
|
||||
, mThread(operationThread)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
}
|
||||
@ -309,16 +321,16 @@ KeyPair::Sign(const nsACString & textToSign,
|
||||
nsCOMPtr<nsIRunnable> r = new SignRunnable(textToSign, mPrivateKey,
|
||||
callback);
|
||||
|
||||
nsCOMPtr<nsIThread> thread;
|
||||
nsresult rv = NS_NewNamedThread("KeyPair Sign", getter_AddRefs(thread), r);
|
||||
return rv;
|
||||
return mThread->Dispatch(r, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
KeyGenRunnable::KeyGenRunnable(KeyType keyType,
|
||||
nsIIdentityKeyGenCallback * callback)
|
||||
nsIIdentityKeyGenCallback * callback,
|
||||
nsIEventTarget* operationThread)
|
||||
: mKeyType(keyType)
|
||||
, mCallback(new nsMainThreadPtrHolder<nsIIdentityKeyGenCallback>(callback))
|
||||
, mRv(NS_ERROR_NOT_INITIALIZED)
|
||||
, mThread(operationThread)
|
||||
{
|
||||
}
|
||||
|
||||
@ -457,7 +469,7 @@ KeyGenRunnable::Run()
|
||||
MOZ_ASSERT(privk);
|
||||
MOZ_ASSERT(pubk);
|
||||
// mKeyPair will take over ownership of privk and pubk
|
||||
mKeyPair = new KeyPair(privk, pubk);
|
||||
mKeyPair = new KeyPair(privk, pubk, mThread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -479,8 +479,8 @@ mochitest-browser-chrome:
|
||||
chunks:
|
||||
by-test-platform:
|
||||
linux64-jsdcov/opt: 35
|
||||
linux64/debug: 12
|
||||
linux32/debug: 12
|
||||
linux64/debug: 16
|
||||
linux32/debug: 16
|
||||
linux64-asan/opt: 10
|
||||
default: 7
|
||||
e10s:
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user