Merge inbound to m-c. a=merge

CLOSED TREE
This commit is contained in:
Ryan VanderMeulen 2017-07-19 10:00:35 -04:00
commit 0cfb1d8460
165 changed files with 2033 additions and 836 deletions

View File

@ -131,8 +131,10 @@ HandlerProvider::GetHandlerPayloadSize(NotNull<DWORD*> aOutPayloadSize)
GetAndSerializePayload(lock);
if (!mSerializer) {
return E_FAIL;
if (!mSerializer || !(*mSerializer)) {
// Failed payload serialization is non-fatal
*aOutPayloadSize = mscom::StructToStream::GetEmptySize();
return S_OK;
}
*aOutPayloadSize = mSerializer->GetSize();
@ -176,7 +178,8 @@ HandlerProvider::WriteHandlerPayload(NotNull<IStream*> aStream)
{
MutexAutoLock lock(mMutex);
if (!mSerializer) {
if (!mSerializer || !(*mSerializer)) {
// Failed payload serialization is non-fatal
mscom::StructToStream emptyStruct;
return emptyStruct.Write(aStream);
}

View File

@ -1,6 +1,8 @@
"use strict";
var notificationURL = "http://example.org/browser/browser/base/content/test/alerts/file_dom_notifications.html";
var expectedURL = Services.prefs.getBoolPref("browser.preferences.useOldOrganization") ? "about:preferences#content"
: "about:preferences#privacy";
add_task(async function test_settingsOpen_observer() {
info("Opening a dummy tab so openPreferences=>switchToTabHavingURI doesn't use the blank tab.");
@ -11,7 +13,7 @@ add_task(async function test_settingsOpen_observer() {
// Ensure preferences is loaded before removing the tab.
let syncPaneLoadedPromise = TestUtils.topicObserved("sync-pane-loaded", () => true);
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "about:preferences#privacy");
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, expectedURL);
info("simulate a notifications-open-settings notification");
let uri = NetUtil.newURI("https://example.com");
let principal = Services.scriptSecurityManager.createCodebasePrincipal(uri, {});
@ -47,7 +49,7 @@ add_task(async function test_settingsOpen_button() {
}
let closePromise = promiseWindowClosed(alertWindow);
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, "about:preferences#privacy");
let tabPromise = BrowserTestUtils.waitForNewTab(gBrowser, expectedURL);
let openSettingsMenuItem = alertWindow.document.getElementById("openSettingsMenuItem");
openSettingsMenuItem.click();

View File

@ -659,24 +659,30 @@ function DownloadsDataCtor(aPrivate) {
// Contains all the available Download objects and their integer state.
this.oldDownloadStates = new Map();
// Array of view objects that should be notified when the available download
// data changes.
this._views = [];
// This defines "initializeDataLink" and "_promiseList" synchronously, then
// continues execution only when "initializeDataLink" is called, allowing the
// underlying data to be loaded only when actually needed.
this._promiseList = (async () => {
await new Promise(resolve => this.initializeDataLink = resolve);
let list = await Downloads.getList(this._isPrivate ? Downloads.PRIVATE
: Downloads.PUBLIC);
await list.addView(this);
return list;
})();
}
DownloadsDataCtor.prototype = {
/**
* Starts receiving events for current downloads.
*/
initializeDataLink() {
if (!this._dataLinkInitialized) {
let promiseList = Downloads.getList(this._isPrivate ? Downloads.PRIVATE
: Downloads.PUBLIC);
promiseList.then(list => list.addView(this)).catch(Cu.reportError);
this._dataLinkInitialized = true;
}
},
_dataLinkInitialized: false,
initializeDataLink() {},
/**
* Promise resolved with the underlying DownloadList object once we started
* receiving events for current downloads.
*/
_promiseList: null,
/**
* Iterator for all the available Download objects. This is empty until the
@ -700,13 +706,11 @@ DownloadsDataCtor.prototype = {
},
/**
* Asks the back-end to remove finished downloads from the list.
* Asks the back-end to remove finished downloads from the list. This method
* is only called after the data link has been initialized.
*/
removeFinished() {
let promiseList = Downloads.getList(this._isPrivate ? Downloads.PRIVATE
: Downloads.PUBLIC);
promiseList.then(list => list.removeFinished())
.catch(Cu.reportError);
this._promiseList.then(list => list.removeFinished()).catch(Cu.reportError);
let indicatorData = this._isPrivate ? PrivateDownloadsIndicatorData
: DownloadsIndicatorData;
indicatorData.attention = DownloadsCommon.ATTENTION_NONE;
@ -723,10 +727,6 @@ DownloadsDataCtor.prototype = {
this.oldDownloadStates.set(download,
DownloadsCommon.stateOfDownload(download));
for (let view of this._views) {
view.onDownloadAdded(download, true);
}
},
onDownloadChanged(download) {
@ -770,14 +770,6 @@ DownloadsDataCtor.prototype = {
}
}
for (let view of this._views) {
try {
view.onDownloadStateChanged(download);
} catch (ex) {
Cu.reportError(ex);
}
}
if (download.succeeded ||
(download.error && download.error.becauseBlocked)) {
this._notifyDownloadEvent("finish");
@ -788,18 +780,10 @@ DownloadsDataCtor.prototype = {
download.newDownloadNotified = true;
this._notifyDownloadEvent("start");
}
for (let view of this._views) {
view.onDownloadChanged(download);
}
},
onDownloadRemoved(download) {
this.oldDownloadStates.delete(download);
for (let view of this._views) {
view.onDownloadRemoved(download);
}
},
// Registration of views
@ -813,8 +797,8 @@ DownloadsDataCtor.prototype = {
* removeView before termination.
*/
addView(aView) {
this._views.push(aView);
this._updateView(aView);
this._promiseList.then(list => list.addView(aView))
.catch(Cu.reportError);
},
/**
@ -824,30 +808,8 @@ DownloadsDataCtor.prototype = {
* DownloadsView object to be removed.
*/
removeView(aView) {
let index = this._views.indexOf(aView);
if (index != -1) {
this._views.splice(index, 1);
}
},
/**
* Ensures that the currently loaded data is added to the specified view.
*
* @param aView
* DownloadsView object to be initialized.
*/
_updateView(aView) {
// Indicate to the view that a batch loading operation is in progress.
aView.onDataLoadStarting();
// Sort backwards by start time, ensuring that the most recent
// downloads are added first regardless of their state.
let downloadsArray = [...this.downloads];
downloadsArray.sort((a, b) => b.startTime - a.startTime);
downloadsArray.forEach(download => aView.onDownloadAdded(download, false));
// Notify the view that all data is available.
aView.onDataLoadCompleted();
this._promiseList.then(list => list.removeView(aView))
.catch(Cu.reportError);
},
// Notifications sent to the most recent browser window only
@ -912,6 +874,13 @@ XPCOMUtils.defineLazyGetter(this, "DownloadsData", function() {
* as a view is registered with it.
*/
const DownloadsViewPrototype = {
/**
* Contains all the available Download objects and their current state value.
*
* SUBCLASSES MUST OVERRIDE THIS PROPERTY.
*/
_oldDownloadStates: null,
// Registration of views
/**
@ -987,7 +956,7 @@ const DownloadsViewPrototype = {
}
},
// Callback functions from DownloadsData
// Callback functions from DownloadList
/**
* Indicates whether we are still loading downloads data asynchronously.
@ -997,14 +966,14 @@ const DownloadsViewPrototype = {
/**
* Called before multiple downloads are about to be loaded.
*/
onDataLoadStarting() {
onDownloadBatchStarting() {
this._loading = true;
},
/**
* Called after data loading finished.
*/
onDataLoadCompleted() {
onDownloadBatchEnded() {
this._loading = false;
},
@ -1014,17 +983,12 @@ const DownloadsViewPrototype = {
*
* @param download
* Download object that was just added.
* @param newest
* When true, indicates that this item is the most recent and should be
* added in the topmost position. This happens when a new download is
* started. When false, indicates that the item is the least recent
* with regard to the items that have been already added. The latter
* generally happens during the asynchronous data load.
*
* @note Subclasses should override this.
* @note Subclasses should override this and still call the base method.
*/
onDownloadAdded(download, newest) {
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
onDownloadAdded(download) {
this._oldDownloadStates.set(download,
DownloadsCommon.stateOfDownload(download));
},
/**
@ -1047,10 +1011,16 @@ const DownloadsViewPrototype = {
* Note that progress notification changes are throttled at the Downloads.jsm
* API level, and there is no throttling mechanism in the front-end.
*
* @note Subclasses should override this.
* @note Subclasses should override this and still call the base method.
*/
onDownloadChanged(download) {
throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
let oldState = this._oldDownloadStates.get(download);
let newState = DownloadsCommon.stateOfDownload(download);
this._oldDownloadStates.set(download, newState);
if (oldState != newState) {
this.onDownloadStateChanged(download);
}
},
/**
@ -1099,6 +1069,7 @@ const DownloadsViewPrototype = {
* the main browser window until the autostart timeout elapses.
*/
function DownloadsIndicatorDataCtor(aPrivate) {
this._oldDownloadStates = new WeakMap();
this._isPrivate = aPrivate;
this._views = [];
}
@ -1126,7 +1097,8 @@ DownloadsIndicatorDataCtor.prototype = {
this._updateViews();
},
onDownloadAdded(download, newest) {
onDownloadAdded(download) {
DownloadsViewPrototype.onDownloadAdded.call(this, download);
this._itemCount++;
this._updateViews();
},
@ -1164,6 +1136,7 @@ DownloadsIndicatorDataCtor.prototype = {
},
onDownloadChanged(download) {
DownloadsViewPrototype.onDownloadChanged.call(this, download);
this._updateViews();
},
@ -1329,6 +1302,7 @@ function DownloadsSummaryData(aIsPrivate, aNumToExclude) {
this._numActive = 0;
this._percentComplete = -1;
this._oldDownloadStates = new WeakMap();
this._isPrivate = aIsPrivate;
this._views = [];
}
@ -1361,13 +1335,9 @@ DownloadsSummaryData.prototype = {
this._updateViews();
},
onDownloadAdded(download, newest) {
if (newest) {
this._downloads.unshift(download);
} else {
this._downloads.push(download);
}
onDownloadAdded(download) {
DownloadsViewPrototype.onDownloadAdded.call(this, download);
this._downloads.unshift(download);
this._updateViews();
},
@ -1377,7 +1347,8 @@ DownloadsSummaryData.prototype = {
this._lastTimeLeft = -1;
},
onDownloadChanged() {
onDownloadChanged(download) {
DownloadsViewPrototype.onDownloadChanged.call(this, download);
this._updateViews();
},

View File

@ -178,7 +178,7 @@ HistoryDownload.prototype = {
* caller must do it and remove the element when it's no longer needed.
*
* The caller is also responsible for forwarding status notifications for
* session downloads, calling the onStateChanged and onChanged methods.
* session downloads, calling the onSessionDownloadChanged method.
*
* @param [optional] aSessionDownload
* The session download, required if aHistoryDownload is not set.
@ -239,6 +239,9 @@ HistoryDownloadElementShell.prototype = {
}
this._sessionDownload = aValue;
if (aValue) {
this.sessionDownloadState = DownloadsCommon.stateOfDownload(aValue);
}
this.ensureActive();
this._updateUI();
@ -291,7 +294,13 @@ HistoryDownloadElementShell.prototype = {
}
},
onChanged() {
onSessionDownloadChanged() {
let newState = DownloadsCommon.stateOfDownload(this.sessionDownload);
if (this.sessionDownloadState != newState) {
this.sessionDownloadState = newState;
this.onStateChanged();
}
// This cannot be placed within onStateChanged because
// when a download goes from hasBlockedData to !hasBlockedData
// it will still remain in the same state.
@ -610,7 +619,7 @@ DownloadsPlacesView.prototype = {
* @param [optional] aPlacesNode
* The Places node for a history download, or null for session downloads.
* @param [optional] aNewest
* @see onDownloadAdded. Ignored for history downloads.
* Whether the download should be added at the top of the list.
* @param [optional] aDocumentFragment
* To speed up the appending of multiple elements to the end of the
* list which are coming in a single batch (i.e. invalidateContainer),
@ -938,7 +947,8 @@ DownloadsPlacesView.prototype = {
},
get selectedNodes() {
return this._richlistbox.selectedItems.filter(element => element._placesNode);
return Array.filter(this._richlistbox.selectedItems,
element => element._placesNode);
},
get selectedNode() {
@ -1095,21 +1105,16 @@ DownloadsPlacesView.prototype = {
}
},
onDataLoadStarting() {},
onDataLoadCompleted() {
onDownloadBatchEnded() {
this._ensureInitialSelection();
},
onDownloadAdded(download, newest) {
this._addDownloadData(download, null, newest);
},
onDownloadStateChanged(download) {
this._viewItemsForDownloads.get(download).onStateChanged();
onDownloadAdded(download) {
this._addDownloadData(download, null, true);
},
onDownloadChanged(download) {
this._viewItemsForDownloads.get(download).onChanged();
this._viewItemsForDownloads.get(download).onSessionDownloadChanged();
},
onDownloadRemoved(download) {
@ -1171,7 +1176,8 @@ DownloadsPlacesView.prototype = {
},
_copySelectedDownloadsToClipboard() {
let urls = this._richlistbox.selectedItems.map(element => element._shell.download.source.url);
let urls = Array.map(this._richlistbox.selectedItems,
element => element._shell.download.source.url);
Cc["@mozilla.org/widget/clipboardhelper;1"]
.getService(Ci.nsIClipboardHelper)

View File

@ -739,16 +739,16 @@ const DownloadsView = {
/**
* Called before multiple downloads are about to be loaded.
*/
onDataLoadStarting() {
DownloadsCommon.log("onDataLoadStarting called for DownloadsView.");
onDownloadBatchStarting() {
DownloadsCommon.log("onDownloadBatchStarting called for DownloadsView.");
this.loading = true;
},
/**
* Called after data loading finished.
*/
onDataLoadCompleted() {
DownloadsCommon.log("onDataLoadCompleted called for DownloadsView.");
onDownloadBatchEnded() {
DownloadsCommon.log("onDownloadBatchEnded called for DownloadsView.");
this.loading = false;
@ -767,33 +767,17 @@ const DownloadsView = {
*
* @param aDownload
* Download object that was just added.
* @param aNewest
* When true, indicates that this item is the most recent and should be
* added in the topmost position. This happens when a new download is
* started. When false, indicates that the item is the least recent
* and should be appended. The latter generally happens during the
* asynchronous data load.
*/
onDownloadAdded(download, aNewest) {
DownloadsCommon.log("A new download data item was added - aNewest =",
aNewest);
onDownloadAdded(download) {
DownloadsCommon.log("A new download data item was added");
if (aNewest) {
this._downloads.unshift(download);
} else {
this._downloads.push(download);
}
this._downloads.unshift(download);
let itemsNowOverflow = this._downloads.length > this.kItemCountLimit;
if (aNewest || !itemsNowOverflow) {
// The newly added item is visible in the panel and we must add the
// corresponding element. This is either because it is the first item, or
// because it was added at the bottom but the list still doesn't overflow.
this._addViewItem(download, aNewest);
}
if (aNewest && itemsNowOverflow) {
// If the list overflows, remove the last item from the panel to make room
// for the new one that we just added at the top.
// The newly added item is visible in the panel and we must add the
// corresponding element. If the list overflows, remove the last item from
// the panel to make room for the new one that we just added at the top.
this._addViewItem(download, true);
if (this._downloads.length > this.kItemCountLimit) {
this._removeViewItem(this._downloads[this.kItemCountLimit]);
}
@ -804,13 +788,6 @@ const DownloadsView = {
}
},
onDownloadStateChanged(download) {
let viewItem = this._visibleViewItems.get(download);
if (viewItem) {
viewItem.onStateChanged();
}
},
onDownloadChanged(download) {
let viewItem = this._visibleViewItems.get(download);
if (viewItem) {
@ -1069,6 +1046,7 @@ XPCOMUtils.defineConstant(this, "DownloadsView", DownloadsView);
*/
function DownloadsViewItem(download, aElement) {
this.download = download;
this.downloadState = DownloadsCommon.stateOfDownload(download);
this.element = aElement;
this.element._shell = this;
@ -1086,11 +1064,12 @@ DownloadsViewItem.prototype = {
*/
_element: null,
onStateChanged() {
this._updateState();
},
onChanged() {
let newState = DownloadsCommon.stateOfDownload(this.download);
if (this.downloadState != newState) {
this.downloadState = newState;
this._updateState();
}
this._updateProgress();
},

View File

@ -83,11 +83,8 @@ add_task(async function test_remote_window_open_data_uri() {
Assert.ok(content.document.nodePrincipal.isNullPrincipal,
"The principal of data: document should be a NullPrincipal.");
let str = content.document.nodePrincipal.originNoSuffix;
let expectDomain = str.substring("moz-nullprincipal:{".length, str.length - 1) + ".mozilla";
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
expectDomain,
"data: URI should have firstPartyDomain set to " + expectDomain);
Assert.ok(content.document.nodePrincipal.originAttributes.firstPartyDomain != "",
"data: URI should have firstPartyDomain set.");
});
win.close();
@ -116,14 +113,11 @@ add_task(async function test_remote_window_open_data_uri2() {
Assert.ok(content.document.nodePrincipal.isNullPrincipal,
"The principal of data: document should be a NullPrincipal.");
let str = content.document.nodePrincipal.originNoSuffix;
let expectDomain = str.substring("moz-nullprincipal:{".length, str.length - 1) + ".mozilla";
Assert.equal(content.document.nodePrincipal.originAttributes.firstPartyDomain,
expectDomain,
"data: URI should have firstPartyDomain set to " + expectDomain);
Assert.ok(content.document.nodePrincipal.originAttributes.firstPartyDomain != "",
"data: URI should have firstPartyDomain set.");
Assert.equal(iframe.contentDocument.nodePrincipal.originAttributes.firstPartyDomain,
expectDomain,
content.document.nodePrincipal.originAttributes.firstPartyDomain,
"iframe should inherit firstPartyDomain from parent document.");
Assert.equal(iframe.contentDocument.cookie, "test2=foo", "iframe should have cookies");
});

View File

@ -88,6 +88,8 @@ gyp_vars.update({
'include_pcm16b': 1,
#'rtc_opus_variable_complexity': 1,
'apm_debug_dump': 1,
})
if os == 'Android':

View File

@ -363,10 +363,10 @@ set_config('LIB', lib_path)
option(env='MT', nargs=1, help='Path to the Microsoft Manifest Tool')
@depends(valid_windows_sdk_dir)
@depends(valid_windows_sdk_dir, valid_ucrt_sdk_dir)
@imports(_from='os', _import='environ')
@imports('platform')
def sdk_bin_path(valid_windows_sdk_dir):
def sdk_bin_path(valid_windows_sdk_dir, valid_ucrt_sdk_dir):
if not valid_windows_sdk_dir:
return
@ -375,13 +375,16 @@ def sdk_bin_path(valid_windows_sdk_dir):
'AMD64': 'x64',
}.get(platform.machine())
# From version 10.0.15063.0 onwards the bin path contains the version number.
versioned_bin = ('bin' if valid_ucrt_sdk_dir.version < '10.0.15063.0'
else os.path.join('bin', str(valid_ucrt_sdk_dir.version)))
result = [
environ['PATH'],
os.path.join(valid_windows_sdk_dir.path, 'bin', vc_host)
os.path.join(valid_windows_sdk_dir.path, versioned_bin, vc_host)
]
if vc_host == 'x64':
result.append(
os.path.join(valid_windows_sdk_dir.path, 'bin', 'x86'))
os.path.join(valid_windows_sdk_dir.path, versioned_bin, 'x86'))
return result

View File

@ -39,7 +39,6 @@ let App = createClass({
devices: PropTypes.shape(Types.devices).isRequired,
dispatch: PropTypes.func.isRequired,
displayPixelRatio: Types.pixelRatio.value.isRequired,
location: Types.location.isRequired,
networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
screenshot: PropTypes.shape(Types.screenshot).isRequired,
touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired,
@ -144,7 +143,6 @@ let App = createClass({
let {
devices,
displayPixelRatio,
location,
networkThrottling,
screenshot,
touchSimulation,
@ -203,7 +201,6 @@ let App = createClass({
}),
Viewports({
devices,
location,
screenshot,
viewports,
onBrowserMounted,

View File

@ -12,7 +12,6 @@ const { getToplevelWindow } = require("../utils/window");
const { DOM: dom, createClass, addons, PropTypes } =
require("devtools/client/shared/vendor/react");
const Types = require("../types");
const e10s = require("../utils/e10s");
const message = require("../utils/message");
@ -27,7 +26,6 @@ module.exports = createClass({
displayName: "Browser",
propTypes: {
location: Types.location.isRequired,
swapAfterMount: PropTypes.bool.isRequired,
onBrowserMounted: PropTypes.func.isRequired,
onContentResize: PropTypes.func.isRequired,
@ -111,13 +109,6 @@ module.exports = createClass({
}),
render() {
let {
location,
} = this.props;
// innerHTML expects & to be an HTML entity
location = location.replace(/&/g, "&amp;");
return dom.div(
{
ref: "browserContainer",
@ -140,7 +131,7 @@ module.exports = createClass({
__html: `<iframe class="browser" mozbrowser="true"
remote="true" remoteType="web"
noisolation="true" allowfullscreen="true"
src="${location}" width="100%" height="100%">
src="about:blank" width="100%" height="100%">
</iframe>`
}
}

View File

@ -23,7 +23,6 @@ module.exports = createClass({
propTypes: {
devices: PropTypes.shape(Types.devices).isRequired,
location: Types.location.isRequired,
screenshot: PropTypes.shape(Types.screenshot).isRequired,
swapAfterMount: PropTypes.bool.isRequired,
viewport: PropTypes.shape(Types.viewport).isRequired,
@ -126,7 +125,6 @@ module.exports = createClass({
render() {
let {
devices,
location,
screenshot,
swapAfterMount,
viewport,
@ -169,7 +167,6 @@ module.exports = createClass({
},
},
Browser({
location,
swapAfterMount,
onBrowserMounted,
onContentResize,

View File

@ -17,7 +17,6 @@ module.exports = createClass({
propTypes: {
devices: PropTypes.shape(Types.devices).isRequired,
location: Types.location.isRequired,
screenshot: PropTypes.shape(Types.screenshot).isRequired,
swapAfterMount: PropTypes.bool.isRequired,
viewport: PropTypes.shape(Types.viewport).isRequired,
@ -69,7 +68,6 @@ module.exports = createClass({
render() {
let {
devices,
location,
screenshot,
swapAfterMount,
viewport,
@ -96,7 +94,6 @@ module.exports = createClass({
}),
ResizableViewport({
devices,
location,
screenshot,
swapAfterMount,
viewport,

View File

@ -16,7 +16,6 @@ module.exports = createClass({
propTypes: {
devices: PropTypes.shape(Types.devices).isRequired,
location: Types.location.isRequired,
screenshot: PropTypes.shape(Types.screenshot).isRequired,
viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired,
onBrowserMounted: PropTypes.func.isRequired,
@ -31,7 +30,6 @@ module.exports = createClass({
render() {
let {
devices,
location,
screenshot,
viewports,
onBrowserMounted,
@ -51,7 +49,6 @@ module.exports = createClass({
return Viewport({
key: viewport.id,
devices,
location,
screenshot,
swapAfterMount: i == 0,
viewport,

View File

@ -10959,21 +10959,25 @@ nsDocShell::DoURILoad(nsIURI* aURI,
MOZ_ASSERT(aTriggeringPrincipal, "Need a valid triggeringPrincipal");
bool isSandBoxed = mSandboxFlags & SANDBOXED_ORIGIN;
// only inherit if we have a aPrincipalToInherit
bool inherit = false;
// We want to inherit aPrincipalToInherit when:
// 1. ChannelShouldInheritPrincipal returns true.
// 2. aURI is not data: URI, or data: URI is not configured as unique opaque
// origin.
bool inheritAttrs = false, inheritPrincipal = false;
if (aPrincipalToInherit) {
inheritAttrs = nsContentUtils::ChannelShouldInheritPrincipal(
aPrincipalToInherit,
aURI,
true, // aInheritForAboutBlank
isSrcdoc);
bool isData;
bool isURIUniqueOrigin = nsIOService::IsDataURIUniqueOpaqueOrigin() &&
NS_SUCCEEDED(aURI->SchemeIs("data", &isData)) &&
isData;
// If aURI is data: URI and is treated as a unique opaque origin, we don't
// want to inherit principal.
inherit = nsContentUtils::ChannelShouldInheritPrincipal(
aPrincipalToInherit,
aURI,
true, // aInheritForAboutBlank
isSrcdoc) && !isURIUniqueOrigin ;
inheritPrincipal = inheritAttrs && !isURIUniqueOrigin;
}
nsLoadFlags loadFlags = mDefaultLoadFlags;
@ -10991,7 +10995,7 @@ nsDocShell::DoURILoad(nsIURI* aURI,
securityFlags |= nsILoadInfo::SEC_LOAD_ERROR_PAGE;
}
if (inherit) {
if (inheritPrincipal) {
securityFlags |= nsILoadInfo::SEC_FORCE_INHERIT_PRINCIPAL;
}
if (isSandBoxed) {
@ -11040,14 +11044,9 @@ nsDocShell::DoURILoad(nsIURI* aURI,
OriginAttributes attrs;
// If inherit is true, which means loadInfo will have SEC_FORCE_INHERIT_PRINCIPAL
// set, so later when we create principal of the document from
// nsScriptSecurityManager::GetChannelResultPrincipal, we will use
// principalToInherit of the loadInfo as the document principal.
// Therefore we use the origin attributes from aPrincipalToInherit.
//
// Inherit origin attributes from aPrincipalToInherit if inheritAttrs is true.
// Otherwise we just use the origin attributes from docshell.
if (inherit) {
if (inheritAttrs) {
MOZ_ASSERT(aPrincipalToInherit, "We should have aPrincipalToInherit here.");
attrs = aPrincipalToInherit->OriginAttributesRef();
// If firstPartyIsolation is not enabled, then PrincipalToInherit should

View File

@ -1659,6 +1659,14 @@ nsFrameLoader::SwapWithOtherLoader(nsFrameLoader* aOther,
return NS_ERROR_NOT_IMPLEMENTED;
}
bool ourPaymentRequestAllowed =
ourContent->HasAttr(kNameSpaceID_None, nsGkAtoms::allowpaymentrequest);
bool otherPaymentRequestAllowed =
otherContent->HasAttr(kNameSpaceID_None, nsGkAtoms::allowpaymentrequest);
if (ourPaymentRequestAllowed != otherPaymentRequestAllowed) {
return NS_ERROR_NOT_IMPLEMENTED;
}
// Divert to a separate path for the remaining steps in the remote case
if (IsRemoteFrame()) {
MOZ_ASSERT(aOther->IsRemoteFrame());

View File

@ -83,6 +83,7 @@ GK_ATOM(allowforms,"allow-forms")
GK_ATOM(allowfullscreen, "allowfullscreen")
GK_ATOM(allowmodals, "allow-modals")
GK_ATOM(alloworientationlock,"allow-orientation-lock")
GK_ATOM(allowpaymentrequest, "allowpaymentrequest")
GK_ATOM(allowpointerlock,"allow-pointer-lock")
GK_ATOM(allowpopupstoescapesandbox,"allow-popups-to-escape-sandbox")
GK_ATOM(allowpopups,"allow-popups")

View File

@ -680,8 +680,6 @@ skip-if = (toolkit == 'android') # Android: Bug 775227
[test_innersize_scrollport.html]
[test_integer_attr_with_leading_zero.html]
[test_intersectionobservers.html]
[test_intersectionobserver_no_root.html]
skip-if = true # bug 1369253
[test_link_prefetch.html]
skip-if = !e10s # Track Bug 1281415
[test_link_stylesheet.html]

View File

@ -1,38 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for Bug 1313927</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body onload="onLoad()">
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1313927">Mozilla Bug 1313927</a>
<p id="display"></p>
<pre id="test">
<script type="application/javascript">
function runTest() {
var win;
window.onmessage = function (e) {
win.close();
is(e.data, true);
SimpleTest.finish();
};
win = window.open("intersectionobserver_window.html");
}
function onLoad() {
SpecialPowers.pushPrefEnv({"set": [["dom.IntersectionObserver.enabled", true]]}, runTest);
}
SimpleTest.waitForExplicitFinish();
</script>
</pre>
<div id="log">
</div>
</body>
</html>

View File

@ -5362,10 +5362,18 @@ CanvasRenderingContext2D::DrawImage(const CanvasImageSource& aImage,
return;
}
// Per spec, the smoothing setting applies only to scaling up a bitmap image.
// When down-scaling the user agent is free to choose whether or not to smooth
// the image. Nearest sampling when down-scaling is rarely desirable and
// smoothing when down-scaling matches chromium's behavior.
// If any dimension is up-scaled, we consider the image as being up-scaled.
auto scale = mTarget->GetTransform().ScaleFactors(true);
bool isDownScale = aDw * Abs(scale.width) < aSw && aDh * Abs(scale.height) < aSh;
SamplingFilter samplingFilter;
AntialiasMode antialiasMode;
if (CurrentState().imageSmoothingEnabled) {
if (CurrentState().imageSmoothingEnabled || isDownScale) {
samplingFilter = gfx::SamplingFilter::LINEAR;
antialiasMode = AntialiasMode::DEFAULT;
} else {

View File

@ -508,6 +508,8 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
case LOCAL_GL_POLYGON_OFFSET_FILL:
case LOCAL_GL_SCISSOR_TEST:
case LOCAL_GL_SAMPLE_COVERAGE_INVERT:
case LOCAL_GL_SAMPLE_ALPHA_TO_COVERAGE:
case LOCAL_GL_SAMPLE_COVERAGE:
case LOCAL_GL_DEPTH_WRITEMASK: {
realGLboolean b = 0;
gl->fGetBooleanv(pname, &b);

View File

@ -1389,8 +1389,17 @@ WebGLFramebuffer::FramebufferRenderbuffer(const char* funcName, GLenum attachEnu
}
// `rb`
if (rb && !mContext->ValidateObject("framebufferRenderbuffer: rb", *rb))
return;
if (rb) {
if (!mContext->ValidateObject("framebufferRenderbuffer: rb", *rb))
return;
if (!rb->mHasBeenBound) {
mContext->ErrorInvalidOperation("%s: bindRenderbuffer must be called before"
" attachment to %04x",
funcName, attachEnum);
return;
}
}
// End of validation.

View File

@ -86,6 +86,8 @@ FlyWebFetchEvent::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
RefPtr<InternalResponse> intResponse;
if (response && response->Type() != ResponseType::Opaque) {
intResponse = response->GetInternalResponse();
response->SetBodyUsed();
}
if (!intResponse) {

View File

@ -53,6 +53,7 @@ NS_IMPL_STRING_ATTR(HTMLIFrameElement, Scrolling, scrolling)
NS_IMPL_URI_ATTR(HTMLIFrameElement, Src, src)
NS_IMPL_STRING_ATTR(HTMLIFrameElement, Width, width)
NS_IMPL_BOOL_ATTR(HTMLIFrameElement, AllowFullscreen, allowfullscreen)
NS_IMPL_BOOL_ATTR(HTMLIFrameElement, AllowPaymentRequest, allowpaymentrequest)
NS_IMPL_STRING_ATTR(HTMLIFrameElement, Srcdoc, srcdoc)
NS_IMETHODIMP

View File

@ -83,6 +83,14 @@ public:
{
SetHTMLBoolAttr(nsGkAtoms::allowfullscreen, aAllow, aError);
}
bool AllowPaymentRequest() const
{
return GetBoolAttr(nsGkAtoms::allowpaymentrequest);
}
void SetAllowPaymentRequest(bool aAllow, ErrorResult& aError)
{
SetHTMLBoolAttr(nsGkAtoms::allowpaymentrequest, aAllow, aError);
}
void GetWidth(DOMString& aWidth)
{
GetHTMLAttr(nsGkAtoms::width, aWidth);

View File

@ -34,4 +34,5 @@ interface nsIDOMHTMLIFrameElement : nsISupports
readonly attribute nsIDOMDocument contentDocument;
attribute boolean allowFullscreen;
attribute boolean allowPaymentRequest;
};

View File

@ -3018,15 +3018,16 @@ TabChild::ReinitRendering()
SendEnsureLayersConnected(&options);
mCompositorOptions = Some(options);
bool success = false;
RefPtr<CompositorBridgeChild> cb = CompositorBridgeChild::Get();
if (gfxVars::UseWebRender()) {
RefPtr<LayerManager> lm = mPuppetWidget->RecreateLayerManager(nullptr);
MOZ_ASSERT(lm->AsWebRenderLayerManager());
lm->AsWebRenderLayerManager()->Initialize(cb,
wr::AsPipelineId(mLayersId),
&mTextureFactoryIdentifier);
success = mPuppetWidget->RecreateLayerManager([&] (LayerManager* aLayerManager) -> bool {
MOZ_ASSERT(aLayerManager->AsWebRenderLayerManager());
return aLayerManager->AsWebRenderLayerManager()->Initialize(cb,
wr::AsPipelineId(mLayersId),
&mTextureFactoryIdentifier);
});
} else {
bool success = false;
nsTArray<LayersBackend> ignored;
PLayerTransactionChild* shadowManager = cb->SendPLayerTransactionConstructor(ignored, LayersId());
if (shadowManager &&
@ -3040,9 +3041,17 @@ TabChild::ReinitRendering()
return;
}
RefPtr<LayerManager> lm = mPuppetWidget->RecreateLayerManager(shadowManager);
ShadowLayerForwarder* lf = lm->AsShadowForwarder();
lf->IdentifyTextureHost(mTextureFactoryIdentifier);
success = mPuppetWidget->RecreateLayerManager([&] (LayerManager* aLayerManager) -> bool {
ShadowLayerForwarder* lf = aLayerManager->AsShadowForwarder();
lf->SetShadowManager(shadowManager);
lf->IdentifyTextureHost(mTextureFactoryIdentifier);
return true;
});
}
if (!success) {
NS_WARNING("failed to recreate layer manager");
return;
}
ImageBridgeChild::IdentifyCompositorTextureHost(mTextureFactoryIdentifier);

View File

@ -429,7 +429,7 @@ void InitLibrary()
// calling this callback on init would immediately re-disble the logging.
Preferences::RegisterCallback(PrefChanged, PREF_CUBEB_LOGGING_LEVEL);
#ifndef MOZ_WIDGET_ANDROID
NS_DispatchToMainThread(
AbstractThread::MainThread()->Dispatch(
NS_NewRunnableFunction("CubebUtils::InitLibrary", &InitBrandName));
#endif
}

View File

@ -147,8 +147,9 @@ public:
void Forget() { mStream = nullptr; }
void DoNotifyTrackCreated(TrackID aTrackID, MediaSegment::Type aType,
MediaStream* aInputStream, TrackID aInputTrackID)
void DoNotifyTrackCreated(MediaStreamGraph* aGraph, TrackID aTrackID,
MediaSegment::Type aType, MediaStream* aInputStream,
TrackID aInputTrackID)
{
MOZ_ASSERT(NS_IsMainThread());
@ -186,15 +187,15 @@ public:
RefPtr<MediaStreamTrack> newTrack =
mStream->CreateDOMTrack(aTrackID, aType, source);
NS_DispatchToMainThread(NewRunnableMethod<RefPtr<MediaStreamTrack>>(
aGraph->AbstractMainThread()->Dispatch(NewRunnableMethod<RefPtr<MediaStreamTrack>>(
"DOMMediaStream::AddTrackInternal",
mStream,
&DOMMediaStream::AddTrackInternal,
newTrack));
}
void DoNotifyTrackEnded(MediaStream* aInputStream, TrackID aInputTrackID,
TrackID aTrackID)
void DoNotifyTrackEnded(MediaStreamGraph* aGraph, MediaStream* aInputStream,
TrackID aInputTrackID, TrackID aTrackID)
{
MOZ_ASSERT(NS_IsMainThread());
@ -208,7 +209,7 @@ public:
if (track) {
LOG(LogLevel::Debug, ("DOMMediaStream %p MediaStreamTrack %p ended at the source. Marking it ended.",
mStream, track.get()));
NS_DispatchToMainThread(
aGraph->AbstractMainThread()->Dispatch(
NewRunnableMethod("dom::MediaStreamTrack::OverrideEnded",
track,
&MediaStreamTrack::OverrideEnded));
@ -223,23 +224,25 @@ public:
{
if (aTrackEvents & TrackEventCommand::TRACK_EVENT_CREATED) {
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
NewRunnableMethod<TrackID,
NewRunnableMethod<MediaStreamGraph*, TrackID,
MediaSegment::Type,
RefPtr<MediaStream>,
TrackID>(
"DOMMediaStream::OwnedStreamListener::DoNotifyTrackCreated",
this,
&OwnedStreamListener::DoNotifyTrackCreated,
aGraph,
aID,
aQueuedMedia.GetType(),
aInputStream,
aInputTrackID));
} else if (aTrackEvents & TrackEventCommand::TRACK_EVENT_ENDED) {
aGraph->DispatchToMainThreadAfterStreamStateUpdate(
NewRunnableMethod<RefPtr<MediaStream>, TrackID, TrackID>(
NewRunnableMethod<MediaStreamGraph*, RefPtr<MediaStream>, TrackID, TrackID>(
"DOMMediaStream::OwnedStreamListener::DoNotifyTrackEnded",
this,
&OwnedStreamListener::DoNotifyTrackEnded,
aGraph,
aInputStream,
aInputTrackID,
aID));
@ -279,7 +282,8 @@ public:
// The owned stream listener adds its tracks after another main thread
// dispatch. We have to do the same to notify of created tracks to stay
// in sync. (Or NotifyTracksCreated is called before tracks are added).
NS_DispatchToMainThread(
MOZ_ASSERT(mStream->GetPlaybackStream());
mStream->GetPlaybackStream()->Graph()->AbstractMainThread()->Dispatch(
NewRunnableMethod("DOMMediaStream::NotifyTracksCreated",
mStream,
&DOMMediaStream::NotifyTracksCreated));
@ -293,9 +297,10 @@ public:
return;
}
NS_DispatchToMainThread(NewRunnableMethod("DOMMediaStream::NotifyFinished",
mStream,
&DOMMediaStream::NotifyFinished));
mStream->GetPlaybackStream()->Graph()->AbstractMainThread()->Dispatch(
NewRunnableMethod("DOMMediaStream::NotifyFinished",
mStream,
&DOMMediaStream::NotifyFinished));
}
// The methods below are called on the MediaStreamGraph thread.

View File

@ -165,9 +165,10 @@ ThreadedDriver::~ThreadedDriver()
if (mThread) {
nsCOMPtr<nsIRunnable> event =
new MediaStreamGraphShutdownThreadRunnable(mThread.forget());
NS_DispatchToMainThread(event);
GraphImpl()->Dispatch(event.forget());
}
}
class MediaStreamGraphInitThreadRunnable : public Runnable {
public:
explicit MediaStreamGraphInitThreadRunnable(ThreadedDriver* aDriver)
@ -493,10 +494,11 @@ AsyncCubebTask::EnsureThread()
// since we don't know the order that the shutdown-threads observers
// will run. ClearOnShutdown guarantees it runs first.
if (!NS_IsMainThread()) {
NS_DispatchToMainThread(
nsCOMPtr<nsIRunnable> runnable =
NS_NewRunnableFunction("AsyncCubebTask::EnsureThread", []() -> void {
ClearOnShutdown(&sThreadPool, ShutdownPhase::ShutdownThreads);
}));
});
AbstractThread::MainThread()->Dispatch(runnable.forget());
} else {
ClearOnShutdown(&sThreadPool, ShutdownPhase::ShutdownThreads);
}

View File

@ -103,8 +103,9 @@ WebAudioUtils::LogToDeveloperConsole(uint64_t aWindowID, const char* aKey)
if (!NS_IsMainThread()) {
nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
"dom::WebAudioUtils::LogToDeveloperConsole",
[aWindowID, aKey]() { LogToDeveloperConsole(aWindowID, aKey); });
NS_DispatchToMainThread(task.forget(), NS_DISPATCH_NORMAL);
[aWindowID, aKey] { LogToDeveloperConsole(aWindowID, aKey); });
SystemGroup::Dispatch("dom::WebAudioUtils::LogToDeveloperConsole",
TaskCategory::Other, task.forget());
return;
}

View File

@ -4,6 +4,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/Element.h"
#include "mozilla/dom/PaymentRequest.h"
#include "mozilla/dom/PaymentResponse.h"
#include "nsContentUtils.h"
@ -225,7 +226,36 @@ PaymentRequest::Constructor(const GlobalObject& aGlobal,
return nullptr;
}
// [TODO] Bug 1318988 - Implement `allowPaymentRequest` on iframe
// the feature can only be used in an active document
if (!window->IsCurrentInnerWindow()) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
// If the node has the same origin as the parent node, the feature is allowed-to-use.
// Otherwise, only allow-to-use this feature when the browsing context container is
// an iframe with "allowpaymentrequest" attribute.
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
nsINode* node = static_cast<nsINode*>(doc);
if (!node) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
do {
nsINode* parentNode = nsContentUtils::GetCrossDocParentNode(node);
if (parentNode) {
nsresult rv = nsContentUtils::CheckSameOrigin(node, parentNode);
if (NS_FAILED(rv)) {
nsIContent* content = static_cast<nsIContent*>(parentNode);
if (!content->IsHTMLElement(nsGkAtoms::iframe) ||
!content->HasAttr(kNameSpaceID_None, nsGkAtoms::allowpaymentrequest)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
}
}
node = parentNode;
} while (node);
// Check payment methods and details
nsAutoString message;

View File

@ -3,6 +3,7 @@
skip-if = !e10s
scheme = https
support-files =
simple_payment_request.html
CanMakePaymentChromeScript.js
ConstructorChromeScript.js
ShowPaymentChromeScript.js
@ -12,3 +13,4 @@ support-files =
[test_constructor.html]
[test_showPayment.html]
[test_validate_decimal_value.html]
[test_payment-request-in-iframe.html]

View File

@ -7,6 +7,7 @@
</head>
<body>
<script type="text/javascript">
const supportedInstruments = [{
supportedMethods: "MyPay",
}];
@ -17,7 +18,18 @@
amount: { currency: "USD", value: "55.00" }
},
};
const payRequest = new PaymentRequest(supportedInstruments, details);
try {
const payRequest = new PaymentRequest(supportedInstruments, details);
if(window.parent) {
window.parent.postMessage("successful", '*');
}
} catch(err) {
if(window.parent) {
window.parent.postMessage(err.name, '*');
}
}
</script>
</body>
</html>

View File

@ -0,0 +1,102 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=1318988
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 1318988</title>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript">
"use strict";
SimpleTest.waitForExplicitFinish();
function testRequestInSameOrigin() {
return new Promise((resolve, reject) => {
var ifr = document.createElement('iframe');
let listener = function(event) {
is(event.data, "successful",
"Expected 'successful', but got '" + event.data + "'");
resolve();
};
window.addEventListener("message", listener);
ifr.src = "simple_payment_request.html";
document.body.appendChild(ifr);
ifr.addEventListener('load', function() {
window.removeEventListener("message", listener);
});
});
}
function testRequestInIFrame() {
return new Promise((resolve, reject) => {
var ifr = document.createElement('iframe');
let listener = function(event) {
is(event.data, "SecurityError",
"Expected 'SecurityError', but got '" + event.data + "'");
resolve();
};
window.addEventListener("message", listener);
ifr.src = "https://test1.example.com:443/tests/dom/payments/test/simple_payment_request.html";
document.body.appendChild(ifr);
ifr.addEventListener('load', function() {
window.removeEventListener("message", listener);
});
});
}
function testRequestInIFrameWithAttribute() {
return new Promise((resolve, reject) => {
var ifrr = document.createElement('iframe');
window.addEventListener("message", function(event) {
is(event.data, "successful",
"Expected 'successful', but got '" + event.data + "'");
resolve();
});
ifrr.setAttribute('allowpaymentrequest', '');
ifrr.src = "https://test1.example.com:443/tests/dom/payments/test/simple_payment_request.html";
document.body.appendChild(ifrr);
});
}
function runTests() {
testRequestInSameOrigin()
.then(testRequestInIFrame)
.then(testRequestInIFrameWithAttribute)
.then(SimpleTest.finish)
.catch( e => {
ok(false, "Unexpected error: " + e.name);
SimpleTest.finish();
});
}
window.addEventListener('load', function() {
SpecialPowers.pushPrefEnv({
'set': [
['dom.payments.request.enabled', true],
]
}, runTests);
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1318988">Mozilla Bug 1318988</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

View File

@ -86,20 +86,16 @@ URLParams::Set(const nsAString& aName, const nsAString& aValue)
param->mValue = aValue;
}
bool
void
URLParams::Delete(const nsAString& aName)
{
bool found = false;
for (uint32_t i = 0; i < mParams.Length();) {
if (mParams[i].mKey.Equals(aName)) {
mParams.RemoveElementAt(i);
found = true;
} else {
++i;
}
}
return found;
}
void
@ -375,9 +371,8 @@ URLSearchParams::Has(const nsAString& aName)
void
URLSearchParams::Delete(const nsAString& aName)
{
if (mParams->Delete(aName)) {
NotifyObserver();
}
mParams->Delete(aName);
NotifyObserver();
}
void

View File

@ -77,8 +77,7 @@ public:
bool Has(const nsAString& aName);
// Returns true if aName was found and deleted, false otherwise.
bool Delete(const nsAString& aName);
void Delete(const nsAString& aName);
void DeleteAll()
{

View File

@ -29,6 +29,7 @@
#define nsRuleNetwork_h__
#include "mozilla/Attributes.h"
#include "mozilla/HashFunctions.h"
#include "nsCOMPtr.h"
#include "nsCOMArray.h"
#include "nsIAtom.h"
@ -208,9 +209,8 @@ public:
return mVariable != aAssignment.mVariable || mValue != aAssignment.mValue; }
PLHashNumber Hash() const {
// XXX I have no idea if this hashing function is good or not // XXX change this
PLHashNumber temp = PLHashNumber(NS_PTR_TO_INT32(mValue.get())) >> 2; // strip alignment bits
return (temp & 0xffff) | NS_PTR_TO_INT32(mVariable.get()); }
using mozilla::HashGeneric;
return HashGeneric(mVariable.get()) ^ HashGeneric(mValue.get()); }
};

View File

@ -1,4 +1,4 @@
52354
52356
0/nm
0th/pt
1/n1
@ -20021,6 +20021,7 @@ combined/U
combiner/MS
combings/M
combo/SM
combust/DS
combustibility/M
combustible/MS
combustion/M
@ -50702,6 +50703,7 @@ vicissitude/SM
victim/MS
victimization/M
victimize/GDS
victimless
victor/MS
victorious/Y
victory/SM

View File

@ -27,6 +27,8 @@
// solution.
#include "mozilla/RefPtr.h"
#include "mozilla/ServoUtils.h"
#include "mozilla/StaticMutex.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/WeakPtr.h"
#include "mozilla/DebugOnly.h"
@ -1662,11 +1664,12 @@ public:
* Returns true on success, or false on failure and leaves the D2D1/Direct3D11 devices unset.
*/
static bool SetDirect3D11Device(ID3D11Device *aDevice);
static ID3D11Device *GetDirect3D11Device();
static ID2D1Device *GetD2D1Device();
static uint32_t GetD2D1DeviceSeq();
static IDWriteFactory *GetDWriteFactory();
static IDWriteFactory* EnsureDWriteFactory();
static RefPtr<ID3D11Device> GetDirect3D11Device();
static RefPtr<ID2D1Device> GetD2D1Device(uint32_t* aOutSeqNo = nullptr);
static bool HasD2D1Device();
static RefPtr<IDWriteFactory> GetDWriteFactory();
static bool SetDWriteFactory(IDWriteFactory *aFactory);
static RefPtr<IDWriteFactory> EnsureDWriteFactory();
static bool SupportsD2D1();
static uint64_t GetD2DVRAMUsageDrawTarget();
@ -1687,13 +1690,20 @@ public:
static void UpdateSystemTextQuality();
private:
static ID2D1Device *mD2D1Device;
static ID3D11Device *mD3D11Device;
static IDWriteFactory *mDWriteFactory;
static StaticRefPtr<ID2D1Device> mD2D1Device;
static StaticRefPtr<ID3D11Device> mD3D11Device;
static StaticRefPtr<IDWriteFactory> mDWriteFactory;
static bool mDWriteFactoryInitialized;
static Mutex* mDWriteFactoryLock;
protected:
// This guards access to the singleton devices above, as well as the
// singleton devices in DrawTargetD2D1.
static StaticMutex mDeviceLock;
friend class DrawTargetD2D1;
#endif
private:
static DrawEventRecorder *mRecorder;
};

View File

@ -16,6 +16,7 @@
#include "ExtendInputEffectD2D1.h"
#include "Tools.h"
#include "nsAppRunner.h"
#include "MainThreadUtils.h"
#include "mozilla/Mutex.h"
@ -34,9 +35,9 @@ namespace gfx {
uint64_t DrawTargetD2D1::mVRAMUsageDT;
uint64_t DrawTargetD2D1::mVRAMUsageSS;
ID2D1Factory1* DrawTargetD2D1::mFactory = nullptr;
StaticRefPtr<ID2D1Factory1> DrawTargetD2D1::mFactory;
ID2D1Factory1 *D2DFactory1()
RefPtr<ID2D1Factory1> D2DFactory()
{
return DrawTargetD2D1::factory();
}
@ -1037,7 +1038,8 @@ DrawTargetD2D1::CreateGradientStops(GradientStop *rawStops, uint32_t aNumStops,
return nullptr;
}
return MakeAndAddRef<GradientStopsD2D>(stopCollection, Factory::GetDirect3D11Device());
RefPtr<ID3D11Device> device = Factory::GetDirect3D11Device();
return MakeAndAddRef<GradientStopsD2D>(stopCollection, device);
}
already_AddRefed<FilterNode>
@ -1069,12 +1071,10 @@ DrawTargetD2D1::Init(ID3D11Texture2D* aTexture, SurfaceFormat aFormat)
{
HRESULT hr;
ID2D1Device* device = Factory::GetD2D1Device();
RefPtr<ID2D1Device> device = Factory::GetD2D1Device(&mDeviceSeq);
if (!device) {
gfxCriticalNote << "[D2D1.1] Failed to obtain a device for DrawTargetD2D1::Init(ID3D11Texture2D*, SurfaceFormat).";
return false;
} else {
mDeviceSeq = Factory::GetD2D1DeviceSeq();
}
hr = device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS, getter_AddRefs(mDC));
@ -1136,12 +1136,10 @@ DrawTargetD2D1::Init(const IntSize &aSize, SurfaceFormat aFormat)
{
HRESULT hr;
ID2D1Device* device = Factory::GetD2D1Device();
RefPtr<ID2D1Device> device = Factory::GetD2D1Device(&mDeviceSeq);
if (!device) {
gfxCriticalNote << "[D2D1.1] Failed to obtain a device for DrawTargetD2D1::Init(IntSize, SurfaceFormat).";
return false;
} else {
mDeviceSeq = Factory::GetD2D1DeviceSeq();
}
hr = device->CreateDeviceContext(D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS, getter_AddRefs(mDC));
@ -1201,13 +1199,18 @@ DrawTargetD2D1::GetByteSize() const
return mSize.width * mSize.height * BytesPerPixel(mFormat);
}
ID2D1Factory1*
RefPtr<ID2D1Factory1>
DrawTargetD2D1::factory()
{
if (mFactory) {
StaticMutexAutoLock lock(Factory::mDeviceLock);
if (mFactory || !NS_IsMainThread()) {
return mFactory;
}
// We don't allow initializing the factory off the main thread.
MOZ_RELEASE_ASSERT(NS_IsMainThread());
RefPtr<ID2D1Factory> factory;
D2D1CreateFactoryFunc createD2DFactory;
HMODULE d2dModule = LoadLibraryW(L"d2d1.dll");
@ -1237,11 +1240,14 @@ DrawTargetD2D1::factory()
return nullptr;
}
hr = factory->QueryInterface((ID2D1Factory1**)&mFactory);
if (FAILED(hr) || !mFactory) {
RefPtr<ID2D1Factory1> factory1;
hr = factory->QueryInterface(__uuidof(ID2D1Factory1), getter_AddRefs(factory1));
if (FAILED(hr) || !factory1) {
return nullptr;
}
mFactory = factory1;
ExtendInputEffectD2D1::Register(mFactory);
RadialGradientEffectD2D1::Register(mFactory);
@ -1251,10 +1257,12 @@ DrawTargetD2D1::factory()
void
DrawTargetD2D1::CleanupD2D()
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
Factory::mDeviceLock.AssertCurrentThreadOwns();
if (mFactory) {
RadialGradientEffectD2D1::Unregister(mFactory);
ExtendInputEffectD2D1::Unregister(mFactory);
mFactory->Release();
mFactory = nullptr;
}
}
@ -1997,7 +2005,8 @@ DrawTargetD2D1::PushD2DLayer(ID2D1DeviceContext *aDC, ID2D1Geometry *aGeometry,
bool
DrawTargetD2D1::IsDeviceContextValid() {
return (mDeviceSeq == Factory::GetD2D1DeviceSeq()) && Factory::GetD2D1Device();
uint32_t seqNo;
return Factory::GetD2D1Device(&seqNo) && seqNo == mDeviceSeq;
}
}

View File

@ -11,6 +11,7 @@
#include <d2d1_1.h>
#include "PathD2D.h"
#include "HelpersD2D.h"
#include "mozilla/StaticPtr.h"
#include <vector>
#include <sstream>
@ -153,7 +154,7 @@ public:
return GetImageForSurface(aSurface, mat, aExtendMode, nullptr);
}
static ID2D1Factory1 *factory();
static RefPtr<ID2D1Factory1> factory();
static void CleanupD2D();
operator std::string() const {
@ -292,7 +293,7 @@ private:
// we can avoid the subsequent hang. (See bug 1293586)
bool mDidComplexBlendWithListInList;
static ID2D1Factory1 *mFactory;
static StaticRefPtr<ID2D1Factory1> mFactory;
// This value is uesed to verify if the DrawTarget is created by a stale device.
uint32_t mDeviceSeq;

View File

@ -67,6 +67,7 @@
#include "mozilla/Mutex.h"
#endif
#include "MainThreadUtils.h"
#if defined(MOZ_LOGGING)
GFX2D_API mozilla::LogModule*
@ -200,12 +201,13 @@ Mutex* Factory::mFTLock = nullptr;
#endif
#ifdef WIN32
// Note: mDeviceLock must be held when mutating these values.
static uint32_t mDeviceSeq = 0;
ID3D11Device *Factory::mD3D11Device = nullptr;
ID2D1Device *Factory::mD2D1Device = nullptr;
IDWriteFactory *Factory::mDWriteFactory = nullptr;
StaticRefPtr<ID3D11Device> Factory::mD3D11Device;
StaticRefPtr<ID2D1Device> Factory::mD2D1Device;
StaticRefPtr<IDWriteFactory> Factory::mDWriteFactory;
bool Factory::mDWriteFactoryInitialized = false;
Mutex* Factory::mDWriteFactoryLock = nullptr;
StaticMutex Factory::mDeviceLock;
#endif
DrawEventRecorder *Factory::mRecorder;
@ -221,10 +223,6 @@ Factory::Init(const Config& aConfig)
#ifdef MOZ_ENABLE_FREETYPE
mFTLock = new Mutex("Factory::mFTLock");
#endif
#ifdef WIN32
mDWriteFactoryLock = new Mutex("Factory::mDWriteFactoryLock");
#endif
}
void
@ -243,13 +241,6 @@ Factory::ShutDown()
mFTLock = nullptr;
}
#endif
#ifdef WIN32
if (mDWriteFactoryLock) {
delete mDWriteFactoryLock;
mDWriteFactoryLock = nullptr;
}
#endif
}
bool
@ -750,10 +741,17 @@ Factory::CreateDrawTargetForD3D11Texture(ID3D11Texture2D *aTexture, SurfaceForma
bool
Factory::SetDirect3D11Device(ID3D11Device *aDevice)
{
MOZ_RELEASE_ASSERT(NS_IsMainThread());
// D2DFactory already takes the device lock, so we get the factory before
// entering the lock scope.
RefPtr<ID2D1Factory1> factory = D2DFactory();
StaticMutexAutoLock lock(mDeviceLock);
mD3D11Device = aDevice;
if (mD2D1Device) {
mD2D1Device->Release();
mD2D1Device = nullptr;
}
@ -761,52 +759,57 @@ Factory::SetDirect3D11Device(ID3D11Device *aDevice)
return true;
}
RefPtr<ID2D1Factory1> factory = D2DFactory1();
RefPtr<IDXGIDevice> device;
aDevice->QueryInterface((IDXGIDevice**)getter_AddRefs(device));
HRESULT hr = factory->CreateDevice(device, &mD2D1Device);
RefPtr<ID2D1Device> d2dDevice;
HRESULT hr = factory->CreateDevice(device, getter_AddRefs(d2dDevice));
if (FAILED(hr)) {
gfxCriticalError() << "[D2D1] Failed to create gfx factory's D2D1 device, code: " << hexa(hr);
mD3D11Device = nullptr;
return false;
} else {
mDeviceSeq++;
}
mDeviceSeq++;
mD2D1Device = d2dDevice;
return true;
}
ID3D11Device*
RefPtr<ID3D11Device>
Factory::GetDirect3D11Device()
{
StaticMutexAutoLock lock(mDeviceLock);
return mD3D11Device;
}
ID2D1Device*
Factory::GetD2D1Device()
RefPtr<ID2D1Device>
Factory::GetD2D1Device(uint32_t* aOutSeqNo)
{
return mD2D1Device;
StaticMutexAutoLock lock(mDeviceLock);
if (aOutSeqNo) {
*aOutSeqNo = mDeviceSeq;
}
return mD2D1Device.get();
}
uint32_t
Factory::GetD2D1DeviceSeq()
bool
Factory::HasD2D1Device()
{
return mDeviceSeq;
return !!GetD2D1Device();
}
IDWriteFactory*
RefPtr<IDWriteFactory>
Factory::GetDWriteFactory()
{
StaticMutexAutoLock lock(mDeviceLock);
return mDWriteFactory;
}
IDWriteFactory*
RefPtr<IDWriteFactory>
Factory::EnsureDWriteFactory()
{
MOZ_ASSERT(mDWriteFactoryLock);
MutexAutoLock lock(*mDWriteFactoryLock);
StaticMutexAutoLock lock(mDeviceLock);
if (mDWriteFactoryInitialized) {
return mDWriteFactory;
@ -836,7 +839,7 @@ Factory::EnsureDWriteFactory()
bool
Factory::SupportsD2D1()
{
return !!D2DFactory1();
return !!D2DFactory();
}
BYTE sSystemTextQuality = CLEARTYPE_QUALITY;
@ -863,8 +866,8 @@ Factory::GetD2DVRAMUsageSourceSurface()
void
Factory::D2DCleanup()
{
StaticMutexAutoLock lock(mDeviceLock);
if (mD2D1Device) {
mD2D1Device->Release();
mD2D1Device = nullptr;
}
DrawTargetD2D1::CleanupD2D();

View File

@ -25,8 +25,7 @@
namespace mozilla {
namespace gfx {
ID2D1Factory1* D2DFactory1();
static ID2D1Factory* D2DFactory() { return D2DFactory1(); }
RefPtr<ID2D1Factory1> D2DFactory();
static inline D2D1_POINT_2F D2DPoint(const Point &aPoint)
{

View File

@ -221,7 +221,7 @@ already_AddRefed<NativeFontResourceDWrite>
NativeFontResourceDWrite::Create(uint8_t *aFontData, uint32_t aDataLength,
bool aNeedsCairo)
{
IDWriteFactory *factory = Factory::EnsureDWriteFactory();
RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
if (!factory) {
gfxWarning() << "Failed to get DWrite Factory.";
return nullptr;

View File

@ -151,7 +151,7 @@ SkTypeface*
ScaledFontDWrite::GetSkTypeface()
{
if (!mTypeface) {
IDWriteFactory *factory = Factory::GetDWriteFactory();
RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
if (!factory) {
return nullptr;
}

View File

@ -80,7 +80,7 @@ SourceSurfaceD2D1::EnsureRealizedBitmap()
}
// Why aren't we using mDevice here or anywhere else?
ID2D1Device* device = Factory::GetD2D1Device();
RefPtr<ID2D1Device> device = Factory::GetD2D1Device();
if (!device) {
return false;
}

View File

@ -38,6 +38,7 @@
#include "mozilla/dom/VideoDecoderManagerChild.h"
#include "mozilla/dom/VideoDecoderManagerParent.h"
#include "MediaPrefs.h"
#include "nsPrintfCString.h"
#ifdef MOZ_CRASHREPORTER
# include "nsExceptionHandler.h"
@ -366,6 +367,10 @@ GPUProcessManager::OnProcessLaunchComplete(GPUProcessHost* aHost)
CrashReporter::AnnotateCrashReport(
NS_LITERAL_CSTRING("GPUProcessStatus"),
NS_LITERAL_CSTRING("Running"));
CrashReporter::AnnotateCrashReport(
NS_LITERAL_CSTRING("GPUProcessLaunchCount"),
nsPrintfCString("%d", mNumProcessAttempts));
#endif
}

View File

@ -84,8 +84,6 @@ TextureInfo ImageClientSingle::GetTextureInfo() const
void
ImageClientSingle::FlushAllImages()
{
MOZ_ASSERT(GetForwarder()->GetTextureForwarder()->UsesImageBridge());
for (auto& b : mBuffers) {
RemoveTexture(b.mTextureClient);
}

View File

@ -22,6 +22,7 @@ using namespace mozilla::gfx;
WebRenderBridgeChild::WebRenderBridgeChild(const wr::PipelineId& aPipelineId)
: mReadLockSequenceNumber(0)
, mIsInTransaction(false)
, mIsInClearCachedResources(false)
, mIdNamespace(0)
, mResourceId(0)
, mPipelineId(aPipelineId)
@ -57,7 +58,7 @@ WebRenderBridgeChild::ActorDestroy(ActorDestroyReason why)
void
WebRenderBridgeChild::AddWebRenderParentCommand(const WebRenderParentCommand& aCmd)
{
MOZ_ASSERT(mIsInTransaction);
MOZ_ASSERT(mIsInTransaction || mIsInClearCachedResources);
mParentCommands.AppendElement(aCmd);
}
@ -460,5 +461,19 @@ WebRenderBridgeChild::RecvWrUpdated(const uint32_t& aNewIdNameSpace)
return IPC_OK();
}
void
WebRenderBridgeChild::BeginClearCachedResources()
{
mIsInClearCachedResources = true;
SendClearCachedResources();
}
void
WebRenderBridgeChild::EndClearCachedResources()
{
ProcessWebRenderParentCommands();
mIsInClearCachedResources = false;
}
} // namespace layers
} // namespace mozilla

View File

@ -110,6 +110,9 @@ public:
void RemoveExpiredFontKeys();
void ClearReadLocks();
void BeginClearCachedResources();
void EndClearCachedResources();
private:
friend class CompositorBridgeChild;
@ -162,6 +165,7 @@ private:
nsTArray<nsTArray<ReadLockInit>> mReadLocks;
uint64_t mReadLockSequenceNumber;
bool mIsInTransaction;
bool mIsInClearCachedResources;
uint32_t mIdNamespace;
uint32_t mResourceId;
wr::PipelineId mPipelineId;

View File

@ -27,9 +27,15 @@ namespace layers {
WebRenderCanvasLayer::~WebRenderCanvasLayer()
{
MOZ_COUNT_DTOR(WebRenderCanvasLayer);
ClearWrResources();
}
void
WebRenderCanvasLayer::ClearWrResources()
{
if (mExternalImageId.isSome()) {
WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
mExternalImageId = Nothing();
}
}
@ -97,5 +103,17 @@ WebRenderCanvasLayer::GetForwarder()
return WrManager()->WrBridge();
}
void
WebRenderCanvasLayer::ClearCachedResources()
{
ClearWrResources();
if (mBufferProvider) {
mBufferProvider->ClearCachedResources();
}
if (mCanvasClient) {
mCanvasClient->Clear();
}
}
} // namespace layers
} // namespace mozilla

View File

@ -33,9 +33,13 @@ public:
virtual void AttachCompositable() override;
virtual void ClearCachedResources() override;
protected:
virtual ~WebRenderCanvasLayer();
void ClearWrResources();
public:
Layer* GetLayer() override { return this; }
void RenderLayer(wr::DisplayListBuilder& aBuilder,

View File

@ -32,16 +32,23 @@ WebRenderImageLayer::WebRenderImageLayer(WebRenderLayerManager* aLayerManager)
WebRenderImageLayer::~WebRenderImageLayer()
{
MOZ_COUNT_DTOR(WebRenderImageLayer);
ClearWrResources();
}
void
WebRenderImageLayer::ClearWrResources()
{
if (mKey.isSome()) {
WrManager()->AddImageKeyForDiscard(mKey.value());
mKey = Nothing();
}
if (mExternalImageId.isSome()) {
WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
mExternalImageId = Nothing();
}
if (mPipelineId.isSome()) {
WrBridge()->RemovePipelineIdForAsyncCompositable(mPipelineId.ref());
mPipelineId = Nothing();
}
}
@ -85,6 +92,7 @@ WebRenderImageLayer::GetAsSourceSurface()
void
WebRenderImageLayer::ClearCachedResources()
{
ClearWrResources();
if (mImageClient) {
mImageClient->ClearCachedResources();
}

View File

@ -38,6 +38,7 @@ public:
protected:
CompositableType GetImageClientType();
void ClearWrResources();
void AddWRVideoImage(size_t aChannelNumber);

View File

@ -47,7 +47,7 @@ WebRenderLayerManager::AsKnowsCompositor()
return mWrChild;
}
void
bool
WebRenderLayerManager::Initialize(PCompositorBridgeChild* aCBChild,
wr::PipelineId aLayersId,
TextureFactoryIdentifier* aTextureFactoryIdentifier)
@ -62,12 +62,21 @@ WebRenderLayerManager::Initialize(PCompositorBridgeChild* aCBChild,
size,
&textureFactoryIdentifier,
&id_namespace);
MOZ_ASSERT(bridge);
if (!bridge) {
// This should only fail if we attempt to access a layer we don't have
// permission for, or more likely, the GPU process crashed again during
// reinitialization. We can expect to be notified again to reinitialize
// (which may or may not be using WebRender).
gfxCriticalNote << "Failed to create WebRenderBridgeChild.";
return false;
}
mWrChild = static_cast<WebRenderBridgeChild*>(bridge);
WrBridge()->SendCreate(size.ToUnknownSize());
WrBridge()->IdentifyTextureHost(textureFactoryIdentifier);
WrBridge()->SetNamespace(id_namespace);
*aTextureFactoryIdentifier = textureFactoryIdentifier;
return true;
}
void
@ -86,9 +95,12 @@ WebRenderLayerManager::DoDestroy(bool aIsSync)
mWidget->CleanupWebRenderWindowOverlay(WrBridge());
LayerManager::Destroy();
DiscardImages();
DiscardCompositorAnimations();
WrBridge()->Destroy(aIsSync);
if (WrBridge()) {
DiscardImages();
DiscardCompositorAnimations();
WrBridge()->Destroy(aIsSync);
}
if (mTransactionIdAllocator) {
// Make sure to notify the refresh driver just in case it's waiting on a
@ -698,7 +710,9 @@ WebRenderLayerManager::Hold(Layer* aLayer)
void
WebRenderLayerManager::SetLayerObserverEpoch(uint64_t aLayerObserverEpoch)
{
WrBridge()->SendSetLayerObserverEpoch(aLayerObserverEpoch);
if (WrBridge()->IPCOpen()) {
WrBridge()->SendSetLayerObserverEpoch(aLayerObserverEpoch);
}
}
void
@ -732,6 +746,9 @@ void
WebRenderLayerManager::ClearLayer(Layer* aLayer)
{
aLayer->ClearCachedResources();
if (aLayer->GetMaskLayer()) {
aLayer->GetMaskLayer()->ClearCachedResources();
}
for (Layer* child = aLayer->GetFirstChild(); child;
child = child->GetNextSibling()) {
ClearLayer(child);
@ -741,12 +758,13 @@ WebRenderLayerManager::ClearLayer(Layer* aLayer)
void
WebRenderLayerManager::ClearCachedResources(Layer* aSubtree)
{
WrBridge()->SendClearCachedResources();
WrBridge()->BeginClearCachedResources();
if (aSubtree) {
ClearLayer(aSubtree);
} else if (mRoot) {
ClearLayer(mRoot);
}
WrBridge()->EndClearCachedResources();
}
void

View File

@ -35,7 +35,7 @@ class WebRenderLayerManager final : public LayerManager
public:
explicit WebRenderLayerManager(nsIWidget* aWidget);
void Initialize(PCompositorBridgeChild* aCBChild, wr::PipelineId aLayersId, TextureFactoryIdentifier* aTextureFactoryIdentifier);
bool Initialize(PCompositorBridgeChild* aCBChild, wr::PipelineId aLayersId, TextureFactoryIdentifier* aTextureFactoryIdentifier);
virtual void Destroy() override;

View File

@ -163,5 +163,29 @@ WebRenderPaintedLayer::RenderLayer(wr::DisplayListBuilder& aBuilder,
CreateWebRenderDisplayList(aBuilder, aSc);
}
void
WebRenderPaintedLayer::ClearCachedResources()
{
ClearWrResources();
if (mImageClient) {
mImageClient->FlushAllImages();
mImageClient->ClearCachedResources();
}
if (mImageContainer) {
mImageContainer->ClearAllImages();
mImageContainer->ClearCachedResources();
}
ClearValidRegion();
}
void
WebRenderPaintedLayer::ClearWrResources()
{
if (mExternalImageId.isSome()) {
WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
mExternalImageId = Nothing();
}
}
} // namespace layers
} // namespace mozilla

View File

@ -32,9 +32,7 @@ protected:
virtual ~WebRenderPaintedLayer()
{
MOZ_COUNT_DTOR(WebRenderPaintedLayer);
if (mExternalImageId.isSome()) {
WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
}
ClearWrResources();
}
wr::MaybeExternalImageId mExternalImageId;
@ -49,6 +47,8 @@ public:
Layer* GetLayer() override { return this; }
void RenderLayer(wr::DisplayListBuilder& aBuilder,
const StackingContextHelper& aSc) override;
virtual void ClearCachedResources() override;
RefPtr<ImageContainer> mImageContainer;
RefPtr<ImageClient> mImageClient;
@ -57,6 +57,7 @@ private:
bool UpdateImageClient();
void CreateWebRenderDisplayList(wr::DisplayListBuilder& aBuilder,
const StackingContextHelper& aSc);
void ClearWrResources();
};
} // namespace layers

View File

@ -32,11 +32,17 @@ protected:
virtual ~WebRenderPaintedLayerBlob()
{
MOZ_COUNT_DTOR(WebRenderPaintedLayerBlob);
ClearWrResources();
}
void ClearWrResources()
{
if (mExternalImageId.isSome()) {
WrBridge()->DeallocExternalImageId(mExternalImageId.ref());
mExternalImageId = Nothing();
}
if (mImageKey.isSome()) {
WrManager()->AddImageKeyForDiscard(mImageKey.value());
mImageKey = Nothing();
}
}
@ -48,7 +54,10 @@ public:
mInvalidRegion.Add(aRegion);
UpdateValidRegionAfterInvalidRegionChanged();
}
virtual void ClearCachedResources() override
{
ClearWrResources();
}
Layer* GetLayer() override { return this; }
void RenderLayer(wr::DisplayListBuilder& aBuilder,
const StackingContextHelper& aSc) override;

View File

@ -15,9 +15,11 @@
#include "mozilla/gfx/GPUParent.h"
#include "mozilla/gfx/GraphicsMessages.h"
#include "mozilla/gfx/Logging.h"
#include "mozilla/layers/CompositorBridgeChild.h"
#include "mozilla/layers/CompositorThread.h"
#include "mozilla/layers/DeviceAttachmentsD3D11.h"
#include "mozilla/layers/MLGDeviceD3D11.h"
#include "mozilla/layers/PaintThread.h"
#include "nsIGfxInfo.h"
#include "nsString.h"
#include <d3d11.h>
@ -701,6 +703,14 @@ DeviceManagerDx::CreateMLGDevice()
void
DeviceManagerDx::ResetDevices()
{
// Flush the paint thread before revoking all these singletons. This
// should ensure that the paint thread doesn't start mixing and matching
// old and new objects together.
if (PaintThread::Get()) {
CompositorBridgeChild* cbc = CompositorBridgeChild::Get();
cbc->FlushAsyncPaints();
}
MutexAutoLock lock(mDeviceLock);
mAdapter = nullptr;

View File

@ -158,7 +158,7 @@ gfxDWriteFontFileLoader::CreateCustomFontFile(FallibleTArray<uint8_t>& aFontData
MOZ_ASSERT(aFontFile);
MOZ_ASSERT(aFontFileStream);
IDWriteFactory *factory = mozilla::gfx::Factory::GetDWriteFactory();
RefPtr<IDWriteFactory> factory = mozilla::gfx::Factory::GetDWriteFactory();
if (!factory) {
gfxCriticalError() << "Failed to get DWrite Factory in CreateCustomFontFile.";
return E_FAIL;

View File

@ -59,6 +59,7 @@
#include <dwmapi.h>
#include <d3d11.h>
#include <d2d1_1.h>
#include "nsIMemoryReporter.h"
#include <winternl.h>
@ -148,14 +149,13 @@ class GPUAdapterReporter final : public nsIMemoryReporter
// Callers must Release the DXGIAdapter after use or risk mem-leak
static bool GetDXGIAdapter(IDXGIAdapter **aDXGIAdapter)
{
ID3D11Device *d3d11Device;
IDXGIDevice *dxgiDevice;
RefPtr<ID3D11Device> d3d11Device;
RefPtr<IDXGIDevice> dxgiDevice;
bool result = false;
if ((d3d11Device = mozilla::gfx::Factory::GetDirect3D11Device())) {
if (d3d11Device->QueryInterface(__uuidof(IDXGIDevice), (void **)&dxgiDevice) == S_OK) {
if (d3d11Device->QueryInterface(__uuidof(IDXGIDevice), getter_AddRefs(dxgiDevice)) == S_OK) {
result = (dxgiDevice->GetAdapter(aDXGIAdapter) == S_OK);
dxgiDevice->Release();
}
}
@ -430,7 +430,7 @@ gfxWindowsPlatform::UpdateBackendPrefs()
uint32_t contentMask = BackendTypeBit(BackendType::CAIRO) |
BackendTypeBit(BackendType::SKIA);
BackendType defaultBackend = BackendType::SKIA;
if (gfxConfig::IsEnabled(Feature::DIRECT2D) && Factory::GetD2D1Device()) {
if (gfxConfig::IsEnabled(Feature::DIRECT2D) && Factory::HasD2D1Device()) {
contentMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
canvasMask |= BackendTypeBit(BackendType::DIRECT2D1_1);
defaultBackend = BackendType::DIRECT2D1_1;
@ -456,9 +456,9 @@ gfxWindowsPlatform::UpdateRenderMode()
CreateOffscreenContentDrawTarget(IntSize(1, 1), SurfaceFormat::B8G8R8A8);
if (!mScreenReferenceDrawTarget) {
gfxCriticalNote << "Failed to update reference draw target after device reset"
<< ", D3D11 device:" << hexa(Factory::GetDirect3D11Device())
<< ", D3D11 device:" << hexa(Factory::GetDirect3D11Device().get())
<< ", D3D11 status:" << FeatureStatusToString(gfxConfig::GetValue(Feature::D3D11_COMPOSITING))
<< ", D2D1 device:" << hexa(Factory::GetD2D1Device())
<< ", D2D1 device:" << hexa(Factory::GetD2D1Device().get())
<< ", D2D1 status:" << FeatureStatusToString(gfxConfig::GetValue(Feature::DIRECT2D))
<< ", content:" << int(GetDefaultContentBackend())
<< ", compositor:" << int(GetCompositorBackend());

View File

@ -11,6 +11,7 @@
#include <X11/Xlibint.h> /* For XESetCloseDisplay */
#undef max // Xlibint.h defines this and it breaks std::max
#undef min // Xlibint.h defines this and it breaks std::min
#undef Data
#include "nsTArray.h"
#include "nsAlgorithm.h"

View File

@ -42,7 +42,8 @@ namespace JS {
_(GetElem_TypedArray) \
_(GetElem_String) \
_(GetElem_Arguments) \
_(GetElem_ArgumentsInlined) \
_(GetElem_ArgumentsInlinedConstant) \
_(GetElem_ArgumentsInlinedSwitch) \
_(GetElem_InlineCache) \
\
_(SetElem_TypedObject) \

View File

@ -181,12 +181,17 @@ function ArrayStaticSome(list, callbackfn/*, thisArg*/) {
return callFunction(ArraySome, list, callbackfn, T);
}
/* ES6 draft 2016-1-15 22.1.3.25 Array.prototype.sort (comparefn) */
// ES2018 draft rev 3bbc87cd1b9d3bf64c3e68ca2fe9c5a3f2c304c0
// 22.1.3.25 Array.prototype.sort ( comparefn )
function ArraySort(comparefn) {
/* Step 1. */
var O = ToObject(this);
// Step 1.
assert(typeof comparefn === "function", "Only called when a comparator is present");
/* Step 2. */
// Step 2.
assert(IsObject(this), "|this| should be an object");
var O = this;
// Step 3.
var len = ToLength(O.length);
if (len <= 1)
@ -724,10 +729,13 @@ function ArrayIteratorNext() {
// Step 8-9.
var len;
if (IsPossiblyWrappedTypedArray(a)) {
if (PossiblyWrappedTypedArrayHasDetachedBuffer(a))
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
len = PossiblyWrappedTypedArrayLength(a);
// If the length is non-zero, the buffer can't be detached.
if (len === 0) {
if (PossiblyWrappedTypedArrayHasDetachedBuffer(a))
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
}
} else {
len = ToLength(a.length);
}

View File

@ -1155,14 +1155,21 @@ function TypedArrayCompareInt(x, y) {
return 0;
}
// ES6 draft 20151210 22.2.3.26 %TypedArray%.prototype.sort ( comparefn ).
// ES2018 draft rev 3bbc87cd1b9d3bf64c3e68ca2fe9c5a3f2c304c0
// 22.2.3.26 %TypedArray%.prototype.sort ( comparefn )
function TypedArraySort(comparefn) {
// This function is not generic.
// Step 1.
var obj = this;
if (comparefn !== undefined) {
if (!IsCallable(comparefn))
ThrowTypeError(JSMSG_NOT_FUNCTION, DecompileArg(0, comparefn));
}
// Step 2.
var obj = this;
// Step 3.
var isTypedArray = IsObject(obj) && IsTypedArray(obj);
var buffer;
@ -1172,7 +1179,7 @@ function TypedArraySort(comparefn) {
buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, obj, "GetAttachedArrayBuffer");
}
// Step 3.
// Step 4.
var len;
if (isTypedArray) {
len = TypedArrayLength(obj);
@ -1180,6 +1187,10 @@ function TypedArraySort(comparefn) {
len = callFunction(CallTypedArrayMethodIfWrapped, obj, obj, "TypedArrayLength");
}
// Arrays with less than two elements remain unchanged when sorted.
if (len <= 1)
return obj;
if (comparefn === undefined) {
// CountingSort doesn't invoke the comparator function.
if (IsUint8TypedArray(obj)) {
@ -1202,39 +1213,33 @@ function TypedArraySort(comparefn) {
// To satisfy step 2 from TypedArray SortCompare described in 22.2.3.26
// the user supplied comparefn is wrapped.
var wrappedCompareFn = comparefn;
comparefn = function(x, y) {
var wrappedCompareFn = function(x, y) {
// Step a.
var v = wrappedCompareFn(x, y);
var v = comparefn(x, y);
// Step b.
if (buffer === null) {
// A typed array previously using inline storage may acquire a
// buffer, so we must check with the source.
if (isTypedArray) {
buffer = GetAttachedArrayBuffer(obj);
} else {
buffer = callFunction(CallTypedArrayMethodIfWrapped, obj, obj,
"GetAttachedArrayBuffer");
}
}
var bufferDetached;
var length;
if (isTypedArray) {
bufferDetached = IsDetachedBuffer(buffer);
length = TypedArrayLength(obj);
} else {
// This is totally cheating and only works because we know `obj`
// and `buffer` are same-compartment".
bufferDetached = callFunction(CallTypedArrayMethodIfWrapped, obj,
buffer, "IsDetachedBuffer");
length = callFunction(CallTypedArrayMethodIfWrapped, obj, obj, "TypedArrayLength");
}
if (bufferDetached)
// It's faster for us to check the typed array's length than to check
// for detached buffers.
if (length === 0) {
assert(PossiblyWrappedTypedArrayHasDetachedBuffer(obj),
"Length can only change from non-zero to zero when the buffer was detached");
ThrowTypeError(JSMSG_TYPED_ARRAY_DETACHED);
}
// Step c. is redundant, see:
// https://bugzilla.mozilla.org/show_bug.cgi?id=1121937#c36
// Step d.
return v;
}
return QuickSort(obj, len, comparefn);
return QuickSort(obj, len, wrappedCompareFn);
}
// ES2017 draft rev f8a9be8ea4bd97237d176907a1e3080dce20c68f

View File

@ -0,0 +1,5 @@
// Source string has balanced parentheses even when the source code was discarded.
setDiscardSource(true);
eval("var f = function() { return 0; };");
assertEq(f.toSource(), "(function() {\n [sourceless code]\n})");

View File

@ -1,4 +1,5 @@
// |jit-test| allow-oom; allow-unhandlable-oom
gczeal(0);
function MyObject( value ) {}
gcparam("maxBytes", gcparam("gcBytes") + 4*(1));
gczeal(4);

View File

@ -0,0 +1,59 @@
function cat() {
var res = "";
for (var i = 0; i < arguments.length; i++)
res += arguments[i];
return res;
}
function cat_m1(ion) {
var res = "";
for (var i = (ion ? -1 : 0); i < arguments.length; i++)
res += arguments[i];
return res;
}
function cat_p1(ion) {
var res = "";
for (var i = 0; i < arguments.length + (ion ? 1 : 0); i++)
res += arguments[i];
return res;
}
function sum() {
var res = 0;
for (var i = 0; i < arguments.length; i++)
res += arguments[i];
return res;
}
function wrapper() {
var res;
var i6 = { valueOf: () => 6 },
i8 = 8.5,
s2 = { toString: () => "2" },
s4 = {},
s6 = "6",
s7 = undefined,
s8 = null;
for (var b = true; b; b = !inIon()) {
res = sum(1,2,3,4,5,i6,7,i8,9,10);
assertEq(res, 55.5);
res = cat(true,s2,3,s4,5,s6,s7,s8);
assertEq(res, "true23[object Object]56undefinednull");
ion = inIon();
if (typeof ion !== "boolean") break;
res = cat_m1(ion,1,s2,3,s4,5,s6,s7,s8);
if (ion) assertEq(res, "undefinedtrue123[object Object]56undefinednull");
else assertEq(res, "false123[object Object]56undefinednull");
ion = inIon();
if (typeof ion !== "boolean") break;
res = cat_p1(ion,1,s2,3,s4,5,s6,s7,s8);
if (ion) assertEq(res, "true123[object Object]56undefinednullundefined");
else assertEq(res, "false123[object Object]56undefinednull");
}
}
wrapper();

View File

@ -124,6 +124,7 @@ GetObject(const MDefinition* ins)
case MDefinition::Op_TypedArrayElements:
case MDefinition::Op_TypedObjectElements:
case MDefinition::Op_CopyLexicalEnvironmentObject:
case MDefinition::Op_IsPackedArray:
object = ins->getOperand(0);
break;
case MDefinition::Op_GetPropertyCache:

View File

@ -1584,8 +1584,10 @@ jit::BailoutIonToBaseline(JSContext* cx, JitActivation* activation, JitFrameIter
JitSpew(JitSpew_BaselineBailouts, " Incoming frame ptr = %p", builder.startFrame());
SnapshotIteratorForBailout snapIter(activation, iter);
if (!snapIter.init(cx))
if (!snapIter.init(cx)) {
ReportOutOfMemory(cx);
return BAILOUT_RETURN_FATAL_ERROR;
}
#ifdef TRACK_SNAPSHOTS
snapIter.spewBailingFrom();

View File

@ -143,7 +143,7 @@ FrameInfo::popRegsAndSync(uint32_t uses)
// clobbered by the first popValue.
StackValue* val = peek(-2);
if (val->kind() == StackValue::Register && val->reg() == R1) {
masm.moveValue(R1, R2);
masm.moveValue(R1, ValueOperand(R2));
val->setRegister(R2);
}
popValue(R1);

View File

@ -105,8 +105,10 @@ PrepareOsrTempData(JSContext* cx, ICWarmUpCounter_Fallback* stub, BaselineFrame*
AlignBytes(ionOsrTempDataSpace, sizeof(Value));
IonOsrTempData* info = (IonOsrTempData*)cx->allocateOsrTempData(totalSpace);
if (!info)
if (!info) {
ReportOutOfMemory(cx);
return nullptr;
}
memset(info, 0, totalSpace);

View File

@ -42,6 +42,7 @@
#include "jit/MoveEmitter.h"
#include "jit/RangeAnalysis.h"
#include "jit/SharedICHelpers.h"
#include "jit/StackSlotAllocator.h"
#include "vm/AsyncFunction.h"
#include "vm/AsyncIteration.h"
#include "vm/MatchPairs.h"
@ -11023,6 +11024,238 @@ CodeGenerator::visitLoadTypedArrayElementHole(LLoadTypedArrayElementHole* lir)
masm.bind(&done);
}
template <SwitchTableType tableType>
class OutOfLineSwitch : public OutOfLineCodeBase<CodeGenerator>
{
using LabelsVector = Vector<Label, 0, JitAllocPolicy>;
using CodeLabelsVector = Vector<CodeLabel, 0, JitAllocPolicy>;
LabelsVector labels_;
CodeLabelsVector codeLabels_;
CodeLabel start_;
bool isOutOfLine_;
void accept(CodeGenerator* codegen) {
codegen->visitOutOfLineSwitch(this);
}
public:
explicit OutOfLineSwitch(TempAllocator& alloc)
: labels_(alloc),
codeLabels_(alloc),
isOutOfLine_(false)
{}
CodeLabel* start() {
return &start_;
}
CodeLabelsVector& codeLabels() {
return codeLabels_;
}
LabelsVector& labels() {
return labels_;
}
void jumpToCodeEntries(MacroAssembler& masm, Register index, Register temp) {
Register base;
if (tableType == SwitchTableType::Inline) {
#if defined(JS_CODEGEN_ARM)
base = ::js::jit::pc;
#else
MOZ_CRASH("NYI: SwitchTableType::Inline");
#endif
} else {
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
MOZ_CRASH("NYI: SwitchTableType::OutOfLine");
#else
masm.mov(start_.patchAt(), temp);
base = temp;
#endif
}
BaseIndex jumpTarget(base, index, ScalePointer);
masm.branchToComputedAddress(jumpTarget);
}
// Register an entry in the switch table.
void addTableEntry(MacroAssembler& masm) {
if ((!isOutOfLine_ && tableType == SwitchTableType::Inline) ||
(isOutOfLine_ && tableType == SwitchTableType::OutOfLine))
{
CodeLabel cl;
masm.writeCodePointer(cl.patchAt());
masm.propagateOOM(codeLabels_.append(mozilla::Move(cl)));
}
}
// Register the code, to which the table will jump to.
void addCodeEntry(MacroAssembler& masm) {
Label entry;
masm.bind(&entry);
masm.propagateOOM(labels_.append(mozilla::Move(entry)));
}
void setOutOfLine() {
isOutOfLine_ = true;
}
};
template <SwitchTableType tableType>
void
CodeGenerator::visitOutOfLineSwitch(OutOfLineSwitch<tableType>* jumpTable)
{
jumpTable->setOutOfLine();
if (tableType == SwitchTableType::OutOfLine) {
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
MOZ_CRASH("NYI: SwitchTableType::OutOfLine");
#else
masm.haltingAlign(sizeof(void*));
masm.use(jumpTable->start()->target());
masm.addCodeLabel(*jumpTable->start());
#endif
}
// Add table entries if the table is inlined.
auto& labels = jumpTable->labels();
for (size_t i = 0, e = labels.length(); i < e; i++)
jumpTable->addTableEntry(masm);
auto& codeLabels = jumpTable->codeLabels();
for (size_t i = 0, e = codeLabels.length(); i < e; i++) {
// The entries of the jump table need to be absolute addresses and thus
// must be patched after codegen is finished.
auto& cl = codeLabels[i];
cl.target()->bind(labels[i].offset());
masm.addCodeLabel(cl);
}
}
template void CodeGenerator::visitOutOfLineSwitch(OutOfLineSwitch<SwitchTableType::Inline>* jumpTable);
template void CodeGenerator::visitOutOfLineSwitch(OutOfLineSwitch<SwitchTableType::OutOfLine>* jumpTable);
void
CodeGenerator::visitLoadElementFromStateV(LLoadElementFromStateV* lir)
{
Register index = ToRegister(lir->index());
Register temp0 = ToRegister(lir->temp0());
#ifdef JS_NUNBOX32
Register temp1 = ToRegister(lir->temp1());
#endif
FloatRegister tempD = ToFloatRegister(lir->tempD());
ValueOperand out = ToOutValue(lir);
// For each element, load it and box it.
MArgumentState* array = lir->array()->toArgumentState();
Label join;
// Jump to the code which is loading the element, based on its index.
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
auto* jumpTable = new (alloc()) OutOfLineSwitch<SwitchTableType::Inline>(alloc());
#else
auto* jumpTable = new (alloc()) OutOfLineSwitch<SwitchTableType::OutOfLine>(alloc());
#endif
{
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
// Inhibit pools within the following sequence because we are indexing into
// a pc relative table. The region will have one instruction for ma_ldr, one
// for breakpoint, and each table case takes one word.
AutoForbidPools afp(&masm, 1 + 1 + array->numElements());
#endif
jumpTable->jumpToCodeEntries(masm, index, temp0);
// Add table entries if the table is inlined.
for (size_t i = 0, e = array->numElements(); i < e; i++)
jumpTable->addTableEntry(masm);
}
// Add inlined code for loading arguments from where they are allocated.
for (size_t i = 0, e = array->numElements(); i < e; i++) {
MDefinition* elem = array->getElement(i);
ConstantOrRegister input;
jumpTable->addCodeEntry(masm);
Register typeReg = Register::Invalid();
const LAllocation* a = lir->getOperand(1 + BOX_PIECES * i);
if (a->isBogus()) {
if (elem->type() == MIRType::Null) {
input = NullValue();
} else if (elem->type() == MIRType::Undefined) {
input = UndefinedValue();
} else if (elem->isConstant() && elem->isEmittedAtUses()) {
input = elem->toConstant()->toJSValue();
} else {
MOZ_CRASH("Unsupported element constant allocation.");
}
} else if (a->isMemory()) {
if (elem->type() == MIRType::Double) {
masm.loadDouble(ToAddress(a), tempD);
input = TypedOrValueRegister(elem->type(), AnyRegister(tempD));
} else if (elem->type() == MIRType::Value) {
typeReg = temp0;
masm.loadPtr(ToAddress(a), temp0);
#ifdef JS_PUNBOX64
input = TypedOrValueRegister(ValueOperand(temp0));
#endif
} else {
typeReg = temp0;
size_t width = StackSlotAllocator::width(LDefinition::TypeFrom(elem->type()));
if (width == 4)
masm.load32(ToAddress(a), temp0);
else if (width == 8)
masm.loadPtr(ToAddress(a), temp0);
else
MOZ_CRASH("Unsupported load size");
input = TypedOrValueRegister(elem->type(), AnyRegister(typeReg));
}
} else if (a->isGeneralReg()) {
typeReg = ToRegister(a);
input = TypedOrValueRegister(elem->type(), AnyRegister(typeReg));
#ifdef JS_PUNBOX64
if (elem->type() != MIRType::Value)
input = TypedOrValueRegister(elem->type(), AnyRegister(typeReg));
else
input = TypedOrValueRegister(ValueOperand(typeReg));
#else
if (elem->type() != MIRType::Value)
input = TypedOrValueRegister(elem->type(), AnyRegister(typeReg));
#endif
} else if (a->isFloatReg()) {
input = TypedOrValueRegister(elem->type(), AnyRegister(ToFloatRegister(a)));
} else if (a->isConstantValue()) {
input = a->toConstant()->toJSValue();
} else {
MOZ_CRASH("Unsupported element allocation.");
}
#ifdef JS_NUNBOX32
if (elem->type() == MIRType::Value) {
static_assert(TYPE_INDEX == 0, "Unexpected type allocation index");
static_assert(PAYLOAD_INDEX == 1, "Unexpected payload allocation index");
const LAllocation* a1 = lir->getOperand(1 + BOX_PIECES * i + 1);
MOZ_ASSERT(!a1->isBogus());
MOZ_ASSERT(typeReg != Register::Invalid());
if (a1->isMemory()) {
masm.loadPtr(ToAddress(a1), temp1);
input = TypedOrValueRegister(ValueOperand(typeReg, temp1));
} else if (a1->isGeneralReg()) {
input = TypedOrValueRegister(ValueOperand(typeReg, ToRegister(a1)));
} else {
MOZ_CRASH("Unsupported Value allocation.");
}
} else {
MOZ_ASSERT(lir->getOperand(1 + BOX_PIECES * i + 1)->isBogus());
}
#endif
masm.moveValue(input, out);
// For the last entry, fall-through.
if (i + 1 < e)
masm.jump(&join);
}
addOutOfLineCode(jumpTable, lir->mir());
masm.bind(&join);
}
template <typename T>
static inline void
StoreToTypedArray(MacroAssembler& masm, Scalar::Type writeType, const LAllocation* value,
@ -12613,5 +12846,30 @@ CodeGenerator::visitFinishBoundFunctionInit(LFinishBoundFunctionInit* lir)
masm.bind(ool->rejoin());
}
void
CodeGenerator::visitIsPackedArray(LIsPackedArray* lir)
{
Register array = ToRegister(lir->array());
Register output = ToRegister(lir->output());
Register elementsTemp = ToRegister(lir->temp());
Label notPacked, done;
// Load elements and length.
masm.loadPtr(Address(array, NativeObject::offsetOfElements()), elementsTemp);
masm.load32(Address(elementsTemp, ObjectElements::offsetOfLength()), output);
// Test length == initializedLength.
Address initLength(elementsTemp, ObjectElements::offsetOfInitializedLength());
masm.branch32(Assembler::NotEqual, initLength, output, &notPacked);
masm.move32(Imm32(1), output);
masm.jump(&done);
masm.bind(&notPacked);
masm.move32(Imm32(0), output);
masm.bind(&done);
}
} // namespace jit
} // namespace js

View File

@ -33,6 +33,12 @@
namespace js {
namespace jit {
enum class SwitchTableType {
Inline,
OutOfLine
};
template <SwitchTableType tableType> class OutOfLineSwitch;
class OutOfLineTestObject;
class OutOfLineNewArray;
class OutOfLineNewObject;
@ -307,6 +313,9 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitLoadUnboxedPointerV(LLoadUnboxedPointerV* lir);
void visitLoadUnboxedPointerT(LLoadUnboxedPointerT* lir);
void visitUnboxObjectOrNull(LUnboxObjectOrNull* lir);
template <SwitchTableType tableType>
void visitOutOfLineSwitch(OutOfLineSwitch<tableType>* ool);
void visitLoadElementFromStateV(LLoadElementFromStateV* lir);
void visitStoreElementT(LStoreElementT* lir);
void visitStoreElementV(LStoreElementV* lir);
template <typename T> void emitStoreElementHoleT(T* lir);
@ -402,6 +411,7 @@ class CodeGenerator final : public CodeGeneratorSpecific
void visitNaNToZero(LNaNToZero* ins);
void visitOutOfLineNaNToZero(OutOfLineNaNToZero* ool);
void visitFinishBoundFunctionInit(LFinishBoundFunctionInit* lir);
void visitIsPackedArray(LIsPackedArray* lir);
void visitCheckOverRecursed(LCheckOverRecursed* lir);
void visitCheckOverRecursedFailure(CheckOverRecursedFailure* ool);

View File

@ -122,6 +122,7 @@
_(IntrinsicSubstringKernel) \
_(IntrinsicObjectHasPrototype) \
_(IntrinsicFinishBoundFunctionInit) \
_(IntrinsicIsPackedArray) \
\
_(IntrinsicIsArrayIterator) \
_(IntrinsicIsMapIterator) \

View File

@ -7735,13 +7735,20 @@ IonBuilder::jsop_getelem()
if (emitted)
return Ok();
trackOptimizationAttempt(TrackedStrategy::GetElem_ArgumentsInlined);
MOZ_TRY(getElemTryArgumentsInlined(&emitted, obj, index));
trackOptimizationAttempt(TrackedStrategy::GetElem_ArgumentsInlinedConstant);
MOZ_TRY(getElemTryArgumentsInlinedConstant(&emitted, obj, index));
if (emitted)
return Ok();
if (script()->argumentsHasVarBinding())
trackOptimizationAttempt(TrackedStrategy::GetElem_ArgumentsInlinedSwitch);
MOZ_TRY(getElemTryArgumentsInlinedIndex(&emitted, obj, index));
if (emitted)
return Ok();
if (script()->argumentsHasVarBinding()) {
trackOptimizationOutcome(TrackedOutcome::NoTypeInfo);
return abort(AbortReason::Disable, "Type is not definitely lazy arguments.");
}
}
obj = maybeUnboxForPropertyAccess(obj);
@ -8393,7 +8400,7 @@ IonBuilder::getElemTryArguments(bool* emitted, MDefinition* obj, MDefinition* in
}
AbortReasonOr<Ok>
IonBuilder::getElemTryArgumentsInlined(bool* emitted, MDefinition* obj, MDefinition* index)
IonBuilder::getElemTryArgumentsInlinedConstant(bool* emitted, MDefinition* obj, MDefinition* index)
{
MOZ_ASSERT(*emitted == false);
@ -8403,31 +8410,83 @@ IonBuilder::getElemTryArgumentsInlined(bool* emitted, MDefinition* obj, MDefinit
if (obj->type() != MIRType::MagicOptimizedArguments)
return Ok();
MConstant* indexConst = index->maybeConstantValue();
if (!indexConst || indexConst->type() != MIRType::Int32)
return Ok();
// Emit inlined arguments.
obj->setImplicitlyUsedUnchecked();
MOZ_ASSERT(!info().argsObjAliasesFormals());
// When the id is constant, we can just return the corresponding inlined argument
MConstant* indexConst = index->maybeConstantValue();
if (indexConst && indexConst->type() == MIRType::Int32) {
MOZ_ASSERT(inliningDepth_ > 0);
MOZ_ASSERT(inliningDepth_ > 0);
int32_t id = indexConst->toInt32();
index->setImplicitlyUsedUnchecked();
int32_t id = indexConst->toInt32();
index->setImplicitlyUsedUnchecked();
if (id < (int32_t)inlineCallInfo_->argc() && id >= 0)
current->push(inlineCallInfo_->getArg(id));
else
pushConstant(UndefinedValue());
if (id < (int32_t)inlineCallInfo_->argc() && id >= 0)
current->push(inlineCallInfo_->getArg(id));
else
pushConstant(UndefinedValue());
trackOptimizationSuccess();
*emitted = true;
trackOptimizationSuccess();
*emitted = true;
return Ok();
}
AbortReasonOr<Ok>
IonBuilder::getElemTryArgumentsInlinedIndex(bool* emitted, MDefinition* obj, MDefinition* index)
{
MOZ_ASSERT(*emitted == false);
if (inliningDepth_ == 0)
return Ok();
if (obj->type() != MIRType::MagicOptimizedArguments)
return Ok();
if (!IsNumberType(index->type()))
return Ok();
// Currently, we do not support any arguments vector larger than 10, as this
// is being translated into code at the call site, and it would be better to
// store the arguments contiguously on the stack.
if (inlineCallInfo_->argc() > 10) {
trackOptimizationOutcome(TrackedOutcome::CantInlineBound);
return abort(AbortReason::Disable, "NYI get argument element with too many arguments");
}
// inlined not constant not supported, yet.
return abort(AbortReason::Disable, "NYI inlined not constant get argument element");
// Emit inlined arguments.
obj->setImplicitlyUsedUnchecked();
MOZ_ASSERT(!info().argsObjAliasesFormals());
// Ensure index is an integer.
MInstruction* idInt32 = MToInt32::New(alloc(), index);
current->add(idInt32);
index = idInt32;
// Bailout if we read more than the number of actual arguments. This bailout
// cannot re-enter because reading out of bounds arguments will disable the
// lazy arguments optimization for this script, when this code would be
// executed in Baseline. (see GetElemOptimizedArguments)
index = addBoundsCheck(index, constantInt(inlineCallInfo_->argc()));
// Get an instruction to represent the state of the argument vector.
MInstruction* args = MArgumentState::New(alloc().fallible(), inlineCallInfo_->argv());
if (!args)
return abort(AbortReason::Alloc);
current->add(args);
// Select a value to pick from a vector.
MInstruction* load = MLoadElementFromState::New(alloc(), args, index);
current->add(load);
current->push(load);
trackOptimizationSuccess();
*emitted = true;
return Ok();
}
AbortReasonOr<Ok>

View File

@ -427,8 +427,10 @@ class IonBuilder
AbortReasonOr<Ok> getElemTryTypedObject(bool* emitted, MDefinition* obj, MDefinition* index);
AbortReasonOr<Ok> getElemTryString(bool* emitted, MDefinition* obj, MDefinition* index);
AbortReasonOr<Ok> getElemTryArguments(bool* emitted, MDefinition* obj, MDefinition* index);
AbortReasonOr<Ok> getElemTryArgumentsInlined(bool* emitted, MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemTryArgumentsInlinedConstant(bool* emitted, MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemTryArgumentsInlinedIndex(bool* emitted, MDefinition* obj,
MDefinition* index);
AbortReasonOr<Ok> getElemAddCache(MDefinition* obj, MDefinition* index);
AbortReasonOr<Ok> getElemTryScalarElemOfTypedObject(bool* emitted,
MDefinition* obj,
@ -779,6 +781,7 @@ class IonBuilder
InliningResult inlineSubstringKernel(CallInfo& callInfo);
InliningResult inlineObjectHasPrototype(CallInfo& callInfo);
InliningResult inlineFinishBoundFunctionInit(CallInfo& callInfo);
InliningResult inlineIsPackedArray(CallInfo& callInfo);
// Testing functions.
InliningResult inlineBailout(CallInfo& callInfo);

View File

@ -1177,6 +1177,14 @@ class LVariadicInstruction : public details::LInstructionFixedDefsTempsHelper<De
void setOperand(size_t index, const LAllocation& a) final override {
operands_[index] = a;
}
void setBoxOperand(size_t index, const LBoxAllocation& a) {
#ifdef JS_NUNBOX32
operands_[index + TYPE_INDEX] = a.type();
operands_[index + PAYLOAD_INDEX] = a.payload();
#else
operands_[index] = a.value();
#endif
}
};
template <size_t Defs, size_t Operands, size_t Temps>

View File

@ -3235,6 +3235,73 @@ LIRGenerator::visitLoadUnboxedString(MLoadUnboxedString* ins)
define(lir, ins);
}
void
LIRGenerator::visitLoadElementFromState(MLoadElementFromState* ins)
{
MOZ_ASSERT(ins->index()->type() == MIRType::Int32);
LDefinition temp1 = LDefinition::BogusTemp();
#ifdef JS_NUNBOX32
temp1 = temp();
#endif
LLoadElementFromStateV* lir = new(alloc()) LLoadElementFromStateV(temp(), temp1, tempDouble());
MOZ_ASSERT(ins->array()->isArgumentState(),
"LIRGenerator::visitLoadElementFromState: Unsupported state object");
MArgumentState* array = ins->array()->toArgumentState();
// 1 -- for the index as a register
// BOX_PIECES * array->numElements() -- for using as operand all the
// elements of the inlined array.
size_t numOperands = 1 + BOX_PIECES * array->numElements();
if (!lir->init(alloc(), numOperands)) {
abort(AbortReason::Alloc, "OOM: LIRGenerator::visitLoadElementFromState");
return;
}
lir->setOperand(0, useRegister(ins->index())); // index
for (size_t i = 0, e = array->numElements(); i < e; i++) {
MDefinition* elem = array->getElement(i);
if (elem->isConstant() && elem->isEmittedAtUses()) {
lir->setOperand(1 + BOX_PIECES * i, LAllocation());
#ifdef JS_NUNBOX32
lir->setOperand(1 + BOX_PIECES * i + 1, LAllocation());
#endif
continue;
}
switch (array->getElement(i)->type()) {
case MIRType::Value:
lir->setBoxOperand(1 + BOX_PIECES * i, useBox(elem, LUse::ANY));
break;
// Anything which can be boxed:
case MIRType::Boolean:
case MIRType::Int32:
case MIRType::Double:
case MIRType::Object:
case MIRType::String:
case MIRType::Symbol:
lir->setOperand(1 + BOX_PIECES * i, use(elem));
#ifdef JS_NUNBOX32
// Bogus second operand.
lir->setOperand(1 + BOX_PIECES * i + 1, LAllocation());
#endif
break;
case MIRType::Null:
case MIRType::Undefined:
// Bogus operand, as these can be inlined.
lir->setOperand(1 + BOX_PIECES * i, LAllocation());
#ifdef JS_NUNBOX32
lir->setOperand(1 + BOX_PIECES * i + 1, LAllocation());
#endif
break;
default:
MOZ_CRASH("LIRGenerator::visitLoadElementFromState: Unsupported element type.");
return;
}
}
defineBox(lir, ins);
}
void
LIRGenerator::visitStoreElement(MStoreElement* ins)
{
@ -4905,6 +4972,16 @@ LIRGenerator::visitFinishBoundFunctionInit(MFinishBoundFunctionInit* ins)
assignSafepoint(lir, ins);
}
void
LIRGenerator::visitIsPackedArray(MIsPackedArray* ins)
{
MOZ_ASSERT(ins->array()->type() == MIRType::Object);
MOZ_ASSERT(ins->type() == MIRType::Boolean);
auto lir = new(alloc()) LIsPackedArray(useRegister(ins->array()), temp());
define(lir, ins);
}
static void
SpewResumePoint(MBasicBlock* block, MInstruction* ins, MResumePoint* resumePoint)
{
@ -5130,6 +5207,12 @@ LIRGenerator::visitArrayState(MArrayState* objState)
MOZ_CRASH("Unexpected ArrayState node during Lowering.");
}
void
LIRGenerator::visitArgumentState(MArgumentState* objState)
{
// ArgumentState nodes are always inlined at their uses.
}
void
LIRGenerator::visitUnknownValue(MUnknownValue* ins)
{

View File

@ -232,6 +232,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitLoadElementHole(MLoadElementHole* ins);
void visitLoadUnboxedObjectOrNull(MLoadUnboxedObjectOrNull* ins);
void visitLoadUnboxedString(MLoadUnboxedString* ins);
void visitLoadElementFromState(MLoadElementFromState* ins);
void visitStoreElement(MStoreElement* ins);
void visitStoreElementHole(MStoreElementHole* ins);
void visitFallibleStoreElement(MFallibleStoreElement* ins);
@ -325,6 +326,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitBeta(MBeta* ins);
void visitObjectState(MObjectState* ins);
void visitArrayState(MArrayState* ins);
void visitArgumentState(MArgumentState* ins);
void visitUnknownValue(MUnknownValue* ins);
void visitLexicalCheck(MLexicalCheck* ins);
void visitThrowRuntimeLexicalError(MThrowRuntimeLexicalError* ins);
@ -341,6 +343,7 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitCheckObjCoercible(MCheckObjCoercible* ins);
void visitDebugCheckSelfHosted(MDebugCheckSelfHosted* ins);
void visitFinishBoundFunctionInit(MFinishBoundFunctionInit* ins);
void visitIsPackedArray(MIsPackedArray* ins);
};
} // namespace jit

View File

@ -312,6 +312,8 @@ IonBuilder::inlineNativeCall(CallInfo& callInfo, JSFunction* target)
return inlineObjectHasPrototype(callInfo);
case InlinableNative::IntrinsicFinishBoundFunctionInit:
return inlineFinishBoundFunctionInit(callInfo);
case InlinableNative::IntrinsicIsPackedArray:
return inlineIsPackedArray(callInfo);
// Map intrinsics.
case InlinableNative::IntrinsicIsMapObject:
@ -1745,6 +1747,47 @@ IonBuilder::inlineFinishBoundFunctionInit(CallInfo& callInfo)
return InliningStatus_Inlined;
}
IonBuilder::InliningResult
IonBuilder::inlineIsPackedArray(CallInfo& callInfo)
{
MOZ_ASSERT(!callInfo.constructing());
MOZ_ASSERT(callInfo.argc() == 1);
if (getInlineReturnType() != MIRType::Boolean)
return InliningStatus_NotInlined;
MDefinition* array = callInfo.getArg(0);
if (array->type() != MIRType::Object)
return InliningStatus_NotInlined;
TemporaryTypeSet* arrayTypes = array->resultTypeSet();
if (!arrayTypes)
return InliningStatus_NotInlined;
const Class* clasp = arrayTypes->getKnownClass(constraints());
if (clasp != &ArrayObject::class_)
return InliningStatus_NotInlined;
// Only inline if the array uses dense storage.
ObjectGroupFlags unhandledFlags = OBJECT_FLAG_SPARSE_INDEXES |
OBJECT_FLAG_LENGTH_OVERFLOW |
OBJECT_FLAG_NON_PACKED;
if (arrayTypes->hasObjectFlags(constraints(), unhandledFlags)) {
trackOptimizationOutcome(TrackedOutcome::ArrayBadFlags);
return InliningStatus_NotInlined;
}
callInfo.setImplicitlyUsedUnchecked();
auto* ins = MIsPackedArray::New(alloc(), array);
current->add(ins);
current->push(ins);
return InliningStatus_Inlined;
}
IonBuilder::InliningResult
IonBuilder::inlineStrCharCodeAt(CallInfo& callInfo)
{

View File

@ -5098,6 +5098,28 @@ MArrayState::Copy(TempAllocator& alloc, MArrayState* state)
return res;
}
MArgumentState*
MArgumentState::New(TempAllocator::Fallible view, const MDefinitionVector& args)
{
MArgumentState* res = new(view.alloc) MArgumentState();
if (!res || !res->init(view.alloc, args.length()))
return nullptr;
for (size_t i = 0, e = args.length(); i < e; i++)
res->initOperand(i, args[i]);
return res;
}
MArgumentState*
MArgumentState::Copy(TempAllocator& alloc, MArgumentState* state)
{
MArgumentState* res = new(alloc) MArgumentState();
if (!res || !res->init(alloc, state->numElements()))
return nullptr;
for (size_t i = 0, e = res->numOperands(); i < e; i++)
res->initOperand(i, state->getOperand(i));
return res;
}
MNewArray::MNewArray(CompilerConstraintList* constraints, uint32_t length, MConstant* templateConst,
gc::InitialHeap initialHeap, jsbytecode* pc, bool vmCall)
: MUnaryInstruction(templateConst),
@ -6147,34 +6169,6 @@ PropertyReadNeedsTypeBarrier(CompilerConstraintList* constraints,
return BarrierKind::NoBarrier;
}
static bool
ObjectSubsumes(TypeSet::ObjectKey* first, TypeSet::ObjectKey* second)
{
if (first->isSingleton() ||
second->isSingleton() ||
first->clasp() != second->clasp() ||
first->unknownProperties() ||
second->unknownProperties())
{
return false;
}
if (first->clasp() == &ArrayObject::class_) {
HeapTypeSetKey firstElements = first->property(JSID_VOID);
HeapTypeSetKey secondElements = second->property(JSID_VOID);
return firstElements.maybeTypes() && secondElements.maybeTypes() &&
firstElements.maybeTypes()->equals(secondElements.maybeTypes());
}
if (first->clasp() == &UnboxedArrayObject::class_) {
return first->group()->unboxedLayout().elementType() ==
second->group()->unboxedLayout().elementType();
}
return false;
}
BarrierKind
jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
CompilerConstraintList* constraints,
@ -6216,30 +6210,6 @@ jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx,
} while (obj);
}
// If any objects which could be observed are similar to ones that have
// already been observed, add them to the observed type set.
if (!key->unknownProperties()) {
HeapTypeSetKey property = key->property(name ? NameToId(name) : JSID_VOID);
if (property.maybeTypes() && !property.maybeTypes()->unknownObject()) {
for (size_t i = 0; i < property.maybeTypes()->getObjectCount(); i++) {
TypeSet::ObjectKey* key = property.maybeTypes()->getObject(i);
if (!key || observed->unknownObject())
continue;
for (size_t j = 0; j < observed->getObjectCount(); j++) {
TypeSet::ObjectKey* observedKey = observed->getObject(j);
if (observedKey && ObjectSubsumes(observedKey, key)) {
// Note: the return value here is ignored.
observed->addType(TypeSet::ObjectType(key),
GetJitContext()->temp->lifoAlloc());
break;
}
}
}
}
}
return PropertyReadNeedsTypeBarrier(constraints, key, name, observed);
}

View File

@ -3957,6 +3957,41 @@ class MArrayState
}
};
// Hold the arguments of an inlined frame. At the moment this class is not
// recovered on bailout as it does not have an implementation and it should
// be inlined at all its uses.
class MArgumentState
: public MVariadicInstruction,
public NoFloatPolicyAfter<0>::Data
{
private:
explicit MArgumentState() {
setResultType(MIRType::Object);
setMovable();
}
public:
INSTRUCTION_HEADER(ArgumentState)
static MArgumentState* New(TempAllocator::Fallible view, const MDefinitionVector& args);
static MArgumentState* Copy(TempAllocator& alloc, MArgumentState* state);
size_t numElements() const {
return numOperands();
}
MDefinition* getElement(uint32_t index) const {
return getOperand(index);
}
bool congruentTo(const MDefinition* ins) const override {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const override {
return AliasSet::None();
}
};
// Setting __proto__ in an object literal.
class MMutateProto
: public MAryInstruction<2>,
@ -9656,6 +9691,30 @@ class MStoreElementCommon
}
};
// This instruction is used to load an element of a non-escaped inlined array.
class MLoadElementFromState
: public MBinaryInstruction,
public SingleObjectPolicy::Data
{
MLoadElementFromState(MDefinition* array, MDefinition* index)
: MBinaryInstruction(array, index)
{
MOZ_ASSERT(array->isArgumentState());
MOZ_ASSERT(index->type() == MIRType::Int32);
setResultType(MIRType::Value);
setMovable();
}
public:
INSTRUCTION_HEADER(LoadElementFromState)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, array), (1, index));
AliasSet getAliasSet() const override {
return AliasSet::None();
}
};
// Store a value to a dense array slots vector.
class MStoreElement
: public MAryInstruction<3>,
@ -12691,7 +12750,7 @@ class MArgumentsLength : public MNullaryInstruction
AliasSet getAliasSet() const override {
// Arguments |length| cannot be mutated by Ion Code.
return AliasSet::None();
}
}
void computeRange(TempAllocator& alloc) override;
@ -13798,6 +13857,27 @@ class MFinishBoundFunctionInit
NAMED_OPERANDS((0, bound), (1, target), (2, argCount))
};
class MIsPackedArray
: public MUnaryInstruction,
public SingleObjectPolicy::Data
{
explicit MIsPackedArray(MDefinition* array)
: MUnaryInstruction(array)
{
setResultType(MIRType::Boolean);
setMovable();
}
public:
INSTRUCTION_HEADER(IsPackedArray)
TRIVIAL_NEW_WRAPPERS
NAMED_OPERANDS((0, array))
AliasSet getAliasSet() const override {
return AliasSet::Load(AliasSet::ObjectFields);
}
};
// Flips the input's sign bit, independently of the rest of the number's
// payload. Note this is different from multiplying by minus-one, which has
// side-effects for e.g. NaNs.

View File

@ -144,6 +144,7 @@ namespace jit {
_(NewStringObject) \
_(ObjectState) \
_(ArrayState) \
_(ArgumentState) \
_(InitElem) \
_(InitElemGetterSetter) \
_(MutateProto) \
@ -217,6 +218,7 @@ namespace jit {
_(LoadUnboxedScalar) \
_(LoadUnboxedObjectOrNull) \
_(LoadUnboxedString) \
_(LoadElementFromState) \
_(StoreElement) \
_(StoreElementHole) \
_(FallibleStoreElement) \
@ -296,6 +298,7 @@ namespace jit {
_(CheckObjCoercible) \
_(DebugCheckSelfHosted) \
_(FinishBoundFunctionInit) \
_(IsPackedArray) \
_(AsmJSLoadHeap) \
_(AsmJSStoreHeap) \
_(AsmJSCompareExchangeHeap) \

View File

@ -327,6 +327,20 @@ MacroAssembler::hasSelfReference() const
return selfReferencePatch_.bound();
}
// ===============================================================
// Move instructions
void
MacroAssembler::moveValue(const ConstantOrRegister& src, const ValueOperand& dest)
{
if (src.constant()) {
moveValue(src.value(), dest);
return;
}
moveValue(src.reg(), dest);
}
// ===============================================================
// Arithmetic functions

View File

@ -986,7 +986,7 @@ MacroAssembler::fillSlotsWithConstantValue(Address base, Register temp,
for (unsigned i = start; i < end; ++i, addr.offset += sizeof(GCPtrValue))
store32(temp, ToType(addr));
#else
moveValue(v, temp);
moveValue(v, ValueOperand(temp));
for (uint32_t i = start; i < end; ++i, base.offset += sizeof(GCPtrValue))
storePtr(temp, base);
#endif

View File

@ -736,6 +736,14 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void move8SignExtend(Register src, Register dest) PER_SHARED_ARCH;
inline void move16SignExtend(Register src, Register dest) PER_SHARED_ARCH;
// Copy a constant, typed-register, or a ValueOperand into a ValueOperand
// destination.
inline void moveValue(const ConstantOrRegister& src, const ValueOperand& dest);
void moveValue(const TypedOrValueRegister& src, const ValueOperand& dest) PER_ARCH;
void moveValue(const ValueOperand& src, const ValueOperand& dest) PER_ARCH;
void moveValue(const Value& src, const ValueOperand& dest) PER_ARCH;
public:
// ===============================================================
// Logical instructions
@ -1258,6 +1266,9 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branchTestStringTruthy(bool truthy, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
// Create an unconditional branch to the address given as argument.
inline void branchToComputedAddress(const BaseIndex& address) PER_ARCH;
private:
// Implementation for branch* methods.

View File

@ -587,6 +587,7 @@ NoFloatPolicyAfter<FirstOp>::adjustInputs(TempAllocator& alloc, MInstruction* de
return true;
}
template bool NoFloatPolicyAfter<0>::adjustInputs(TempAllocator& alloc, MInstruction* def);
template bool NoFloatPolicyAfter<1>::adjustInputs(TempAllocator& alloc, MInstruction* def);
template bool NoFloatPolicyAfter<2>::adjustInputs(TempAllocator& alloc, MInstruction* def);
@ -1268,6 +1269,7 @@ FilterTypeSetPolicy::adjustInputs(TempAllocator& alloc, MInstruction* ins)
_(MixPolicy<StringPolicy<0>, StringPolicy<1> >) \
_(MixPolicy<BoxPolicy<0>, BoxPolicy<1> >) \
_(NoFloatPolicy<0>) \
_(NoFloatPolicyAfter<0>) \
_(NoFloatPolicyAfter<1>) \
_(NoFloatPolicyAfter<2>) \
_(ObjectPolicy<0>) \

View File

@ -1404,7 +1404,7 @@ CodeGeneratorARM::visitBox(LBox* box)
MOZ_ASSERT(!box->getOperand(0)->isConstant());
// On x86, the input operand and the output payload have the same virtual
// On arm, the input operand and the output payload have the same virtual
// register. All that needs to be written is the type tag for the type
// definition.
masm.ma_mov(Imm32(MIRTypeToTag(box->type())), ToRegister(type));
@ -1413,18 +1413,10 @@ CodeGeneratorARM::visitBox(LBox* box)
void
CodeGeneratorARM::visitBoxFloatingPoint(LBoxFloatingPoint* box)
{
const LDefinition* payload = box->getDef(PAYLOAD_INDEX);
const LDefinition* type = box->getDef(TYPE_INDEX);
const LAllocation* in = box->getOperand(0);
FloatRegister reg = ToFloatRegister(in);
const AnyRegister in = ToAnyRegister(box->getOperand(0));
const ValueOperand out = ToOutValue(box);
if (box->type() == MIRType::Float32) {
ScratchFloat32Scope scratch(masm);
masm.convertFloat32ToDouble(reg, scratch);
masm.ma_vxfer(VFPRegister(scratch), ToRegister(payload), ToRegister(type));
} else {
masm.ma_vxfer(VFPRegister(reg), ToRegister(payload), ToRegister(type));
}
masm.moveValue(TypedOrValueRegister(box->type(), in), out);
}
void

View File

@ -2057,6 +2057,21 @@ MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMag
branch32(cond, ToPayload(valaddr), Imm32(why), label);
}
void
MacroAssembler::branchToComputedAddress(const BaseIndex& addr)
{
MOZ_ASSERT(addr.base == pc, "Unsupported jump from any other addresses.");
MOZ_ASSERT(addr.offset == 0, "NYI: offsets from pc should be shifted by the number of instructions.");
Register base = addr.base;
uint32_t scale = Imm32::ShiftOf(addr.scale).value;
ma_ldr(DTRAddr(base, DtrRegImmShift(addr.index, LSL, scale)), pc);
// When loading from pc, the pc is shifted to the next instruction, we
// add one extra instruction to accomodate for this shifted offset.
breakpoint();
}
// ========================================================================
// Memory access primitives.
void

View File

@ -3277,22 +3277,6 @@ MacroAssemblerARMCompat::extractTag(const BaseIndex& address, Register scratch)
return extractTag(Address(scratch, address.offset), scratch);
}
void
MacroAssemblerARMCompat::moveValue(const Value& val, Register type, Register data)
{
ma_mov(Imm32(val.toNunboxTag()), type);
if (val.isGCThing())
ma_mov(ImmGCPtr(val.toGCThing()), data);
else
ma_mov(Imm32(val.toNunboxPayload()), data);
}
void
MacroAssemblerARMCompat::moveValue(const Value& val, const ValueOperand& dest)
{
moveValue(val, dest.typeReg(), dest.payloadReg());
}
/////////////////////////////////////////////////////////////////
// X86/X64-common (ARM too now) interface.
/////////////////////////////////////////////////////////////////
@ -3645,7 +3629,7 @@ MacroAssemblerARMCompat::handleFailureWithHandlerTail(void* handler)
// No exception handler. Load the error value, load the new stack pointer
// and return from the entry frame.
bind(&entryFrame);
moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
asMasm().moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
{
ScratchRegisterScope scratch(asMasm());
ma_ldr(Address(sp, offsetof(ResumeFromException, stackPointer)), sp, scratch);
@ -5324,6 +5308,78 @@ MacroAssembler::pushFakeReturnAddress(Register scratch)
return pseudoReturnOffset;
}
// ===============================================================
// Move instructions
void
MacroAssembler::moveValue(const TypedOrValueRegister& src, const ValueOperand& dest)
{
if (src.hasValue()) {
moveValue(src.valueReg(), dest);
return;
}
MIRType type = src.type();
AnyRegister reg = src.typedReg();
if (!IsFloatingPointType(type)) {
mov(ImmWord(MIRTypeToTag(type)), dest.typeReg());
if (reg.gpr() != dest.payloadReg())
mov(reg.gpr(), dest.payloadReg());
return;
}
ScratchDoubleScope scratch(*this);
FloatRegister freg = reg.fpu();
if (type == MIRType::Float32) {
convertFloat32ToDouble(freg, ScratchFloat32Reg);
freg = ScratchFloat32Reg;
}
ma_vxfer(freg, dest.payloadReg(), dest.typeReg());
}
void
MacroAssembler::moveValue(const ValueOperand& src, const ValueOperand& dest)
{
Register s0 = src.typeReg();
Register s1 = src.payloadReg();
Register d0 = dest.typeReg();
Register d1 = dest.payloadReg();
// Either one or both of the source registers could be the same as a
// destination register.
if (s1 == d0) {
if (s0 == d1) {
// If both are, this is just a swap of two registers.
ScratchRegisterScope scratch(*this);
MOZ_ASSERT(d1 != scratch);
MOZ_ASSERT(d0 != scratch);
ma_mov(d1, scratch);
ma_mov(d0, d1);
ma_mov(scratch, d0);
return;
}
// If only one is, copy that source first.
mozilla::Swap(s0, s1);
mozilla::Swap(d0, d1);
}
if (s0 != d0)
ma_mov(s0, d0);
if (s1 != d1)
ma_mov(s1, d1);
}
void
MacroAssembler::moveValue(const Value& src, const ValueOperand& dest)
{
ma_mov(Imm32(src.toNunboxTag()), dest.typeReg());
if (src.isGCThing())
ma_mov(ImmGCPtr(src.toGCThing()), dest.payloadReg());
else
ma_mov(Imm32(src.toNunboxPayload()), dest.payloadReg());
}
// ===============================================================
// Branch functions

View File

@ -819,8 +819,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
void int32ValueToFloat32(const ValueOperand& operand, FloatRegister dest);
void loadConstantFloat32(float f, FloatRegister dest);
void moveValue(const Value& val, Register type, Register data);
CodeOffsetJump jumpWithPatch(RepatchLabel* label, Condition cond = Always,
Label* documentation = nullptr);
CodeOffsetJump backedgeJump(RepatchLabel* label, Label* documentation) {
@ -856,36 +854,6 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
}
}
void moveValue(const Value& val, const ValueOperand& dest);
void moveValue(const ValueOperand& src, const ValueOperand& dest) {
Register s0 = src.typeReg(), d0 = dest.typeReg(),
s1 = src.payloadReg(), d1 = dest.payloadReg();
// Either one or both of the source registers could be the same as a
// destination register.
if (s1 == d0) {
if (s0 == d1) {
// If both are, this is just a swap of two registers.
ScratchRegisterScope scratch(asMasm());
MOZ_ASSERT(d1 != scratch);
MOZ_ASSERT(d0 != scratch);
ma_mov(d1, scratch);
ma_mov(d0, d1);
ma_mov(scratch, d0);
return;
}
// If only one is, copy that source first.
mozilla::Swap(s0, s1);
mozilla::Swap(d0, d1);
}
if (s0 != d0)
ma_mov(s0, d0);
if (s1 != d1)
ma_mov(s1, d1);
}
void storeValue(ValueOperand val, const Address& dst);
void storeValue(ValueOperand val, const BaseIndex& dest);
void storeValue(JSValueType type, Register reg, BaseIndex dest) {

View File

@ -516,7 +516,7 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut)
}
// Push undefined.
masm.moveValue(UndefinedValue(), r5, r4);
masm.moveValue(UndefinedValue(), ValueOperand(r5, r4));
{
Label undefLoopTop;
masm.bind(&undefLoopTop);

View File

@ -387,6 +387,12 @@ class Assembler : public vixl::Assembler
LabelBase* label = absoluteLabel;
label->bind(off.getOffset());
}
void writeCodePointer(CodeOffset* label) {
uintptr_t x = LabelBase::INVALID_OFFSET;
BufferOffset off = EmitData(&x, sizeof(uintptr_t));
label->bind(off.getOffset());
}
void verifyHeapAccessDisassembly(uint32_t begin, uint32_t end,
const Disassembler::HeapAccess& heapAccess)

View File

@ -1656,6 +1656,12 @@ MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr, JSWhyMag
B(label, cond);
}
void
MacroAssembler::branchToComputedAddress(const BaseIndex& addr)
{
MOZ_CRASH("branchToComputedAddress");
}
// ========================================================================
// Memory access primitives.
void

View File

@ -773,6 +773,54 @@ MacroAssembler::pushFakeReturnAddress(Register scratch)
return pseudoReturnOffset;
}
// ===============================================================
// Move instructions
void
MacroAssembler::moveValue(const TypedOrValueRegister& src, const ValueOperand& dest)
{
if (src.hasValue()) {
moveValue(src.valueReg(), dest);
return;
}
MIRType type = src.type();
AnyRegister reg = src.typedReg();
if (!IsFloatingPointType(type)) {
boxNonDouble(ValueTypeFromMIRType(type), reg.gpr(), dest);
return;
}
FloatRegister scratch = ScratchDoubleReg;
FloatRegister freg = reg.fpu();
if (type == MIRType::Float32) {
convertFloat32ToDouble(freg, scratch);
freg = scratch;
}
boxDouble(freg, dest, scratch);
}
void
MacroAssembler::moveValue(const ValueOperand& src, const ValueOperand& dest)
{
if (src == dest)
return;
movePtr(src.valueReg(), dest.valueReg());
}
void
MacroAssembler::moveValue(const Value& src, const ValueOperand& dest)
{
if (!src.isGCThing()) {
movePtr(ImmWord(src.asRawBits()), dest.valueReg());
return;
}
BufferOffset load = movePatchablePtr(ImmPtr(src.bitsAsPunboxPointer()), dest.valueReg());
writeDataRelocation(src, load);
}
// ===============================================================
// Branch functions

View File

@ -359,10 +359,6 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
void moveValue(const Value& src, const ValueOperand& dest) {
moveValue(src, dest.valueReg());
}
void moveValue(const ValueOperand& src, const ValueOperand& dest) {
if (src.valueReg() != dest.valueReg())
movePtr(src.valueReg(), dest.valueReg());
}
CodeOffset pushWithPatch(ImmWord imm) {
vixl::UseScratchRegisterScope temps(this);

View File

@ -373,7 +373,7 @@ JitRuntime::generateArgumentsRectifier(JSContext* cx, void** returnAddrOut)
masm.Sub(w2, w6, w8);
// Put an undefined in a register so it can be pushed.
masm.moveValue(UndefinedValue(), r4);
masm.moveValue(UndefinedValue(), ValueOperand(r4));
// Push undefined N times.
{

View File

@ -1488,19 +1488,6 @@ MacroAssemblerMIPSCompat::moveData(const Value& val, Register data)
ma_li(data, Imm32(val.toNunboxPayload()));
}
void
MacroAssemblerMIPSCompat::moveValue(const Value& val, Register type, Register data)
{
MOZ_ASSERT(type != data);
ma_li(type, Imm32(getType(val)));
moveData(val, data);
}
void
MacroAssemblerMIPSCompat::moveValue(const Value& val, const ValueOperand& dest)
{
moveValue(val, dest.typeReg(), dest.payloadReg());
}
/* There are 3 paths trough backedge jump. They are listed here in the order
* in which instructions are executed.
* - The short jump is simple:
@ -1866,7 +1853,7 @@ MacroAssemblerMIPSCompat::handleFailureWithHandlerTail(void* handler)
// No exception handler. Load the error value, load the new stack pointer
// and return from the entry frame.
bind(&entryFrame);
moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
asMasm().moveValue(MagicValue(JS_ION_ERROR), JSReturnOperand);
loadPtr(Address(StackPointer, offsetof(ResumeFromException, stackPointer)), StackPointer);
// We're going to be returning by the ion calling convention

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