merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2017-04-04 12:35:03 +02:00
commit 14e0b51ace
154 changed files with 1441 additions and 960 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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 ||

View File

@ -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];

View File

@ -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

View File

@ -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.
*

View File

@ -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)

View File

@ -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;

View File

@ -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

View File

@ -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]

View File

@ -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));

View File

@ -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));

View File

@ -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

View File

@ -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");

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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.

View File

@ -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`

View File

@ -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.
*/

View File

@ -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");`

View File

@ -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);
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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();
}

View File

@ -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;

View File

@ -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()
{

View File

@ -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;

View File

@ -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

View File

@ -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)
{

View File

@ -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,

View File

@ -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,

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -992,6 +992,8 @@ description =
description =
[PCompositorBridge::NotifyChildCreated]
description =
[PCompositorBridge::MapAndNotifyChildCreated]
description = bug 1350660
[PCompositorBridge::NotifyChildRecreated]
description =
[PCompositorBridge::MakeSnapshot]

View File

@ -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:

View File

@ -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*

View File

@ -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());

View File

@ -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);

View File

@ -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,

View File

@ -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);

View File

@ -129,6 +129,8 @@
\
_(IntrinsicGetNextSetEntryForIterator) \
\
_(IntrinsicNewArrayIterator) \
\
_(IntrinsicArrayBufferByteLength) \
_(IntrinsicPossiblyWrappedArrayBufferByteLength) \
\

View File

@ -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_))

View File

@ -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);

View File

@ -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);

View File

@ -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)
{

View File

@ -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);

View File

@ -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)
{

View File

@ -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_;

View File

@ -133,6 +133,7 @@ namespace jit {
_(NewArray) \
_(NewArrayCopyOnWrite) \
_(NewArrayDynamicLength) \
_(NewArrayIterator) \
_(NewTypedArray) \
_(NewTypedArrayDynamicLength) \
_(NewObject) \

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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; };

View File

@ -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:

View File

@ -67,6 +67,7 @@
_(NewArray) \
_(NewArrayCopyOnWrite) \
_(NewArrayDynamicLength) \
_(NewArrayIterator) \
_(NewTypedArray) \
_(NewTypedArrayDynamicLength) \
_(NewObject) \

View File

@ -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)
{

View File

@ -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.

View File

@ -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

View File

@ -145,6 +145,9 @@ class ArrayIteratorObject : public JSObject
static const Class class_;
};
ArrayIteratorObject*
NewArrayIteratorObject(JSContext* cx, NewObjectKind newKind = GenericObject);
class StringIteratorObject : public JSObject
{
public:

View File

@ -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)

View File

@ -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),

View File

@ -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_ */

View File

@ -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

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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
}

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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.
}

View File

@ -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.

View File

@ -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);

View File

@ -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)

View File

@ -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;
}
}

View File

@ -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)

View File

@ -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);

View File

@ -47,7 +47,7 @@ public:
return;
}
PodCopy(storage, str, length);
storage[length + 1] = '\0';
storage[length] = '\0';
}
char const * get() {
return storage;

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -69,6 +69,8 @@ class AudioRecordJni {
explicit AudioRecordJni(AudioManager* audio_manager);
~AudioRecordJni();
void EnsureRecordObject();
int32_t Init();
int32_t Terminate();

View File

@ -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.

View File

@ -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 "

View File

@ -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)

View File

@ -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;

View File

@ -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,

View 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:]))

View File

@ -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)

View File

@ -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);
}
}
}

View File

@ -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