mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-24 05:11:16 +00:00
Merge inbound to m-c. a=merge
CLOSED TREE
This commit is contained in:
commit
0cfb1d8460
@ -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);
|
||||
}
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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();
|
||||
},
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
},
|
||||
|
||||
|
@ -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");
|
||||
});
|
||||
|
@ -88,6 +88,8 @@ gyp_vars.update({
|
||||
'include_pcm16b': 1,
|
||||
|
||||
#'rtc_opus_variable_complexity': 1,
|
||||
|
||||
'apm_debug_dump': 1,
|
||||
})
|
||||
|
||||
if os == 'Android':
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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, "&");
|
||||
|
||||
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>`
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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")
|
||||
|
@ -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]
|
||||
|
@ -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>
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -34,4 +34,5 @@ interface nsIDOMHTMLIFrameElement : nsISupports
|
||||
readonly attribute nsIDOMDocument contentDocument;
|
||||
|
||||
attribute boolean allowFullscreen;
|
||||
attribute boolean allowPaymentRequest;
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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]
|
||||
|
@ -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>
|
||||
|
102
dom/payments/test/test_payment-request-in-iframe.html
Normal file
102
dom/payments/test/test_payment-request-in-iframe.html
Normal 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>
|
@ -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
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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()); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
28
gfx/2d/2D.h
28
gfx/2d/2D.h
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -151,7 +151,7 @@ SkTypeface*
|
||||
ScaledFontDWrite::GetSkTypeface()
|
||||
{
|
||||
if (!mTypeface) {
|
||||
IDWriteFactory *factory = Factory::GetDWriteFactory();
|
||||
RefPtr<IDWriteFactory> factory = Factory::GetDWriteFactory();
|
||||
if (!factory) {
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -84,8 +84,6 @@ TextureInfo ImageClientSingle::GetTextureInfo() const
|
||||
void
|
||||
ImageClientSingle::FlushAllImages()
|
||||
{
|
||||
MOZ_ASSERT(GetForwarder()->GetTextureForwarder()->UsesImageBridge());
|
||||
|
||||
for (auto& b : mBuffers) {
|
||||
RemoveTexture(b.mTextureClient);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
|
||||
protected:
|
||||
CompositableType GetImageClientType();
|
||||
void ClearWrResources();
|
||||
|
||||
void AddWRVideoImage(size_t aChannelNumber);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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());
|
||||
|
@ -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"
|
||||
|
@ -42,7 +42,8 @@ namespace JS {
|
||||
_(GetElem_TypedArray) \
|
||||
_(GetElem_String) \
|
||||
_(GetElem_Arguments) \
|
||||
_(GetElem_ArgumentsInlined) \
|
||||
_(GetElem_ArgumentsInlinedConstant) \
|
||||
_(GetElem_ArgumentsInlinedSwitch) \
|
||||
_(GetElem_InlineCache) \
|
||||
\
|
||||
_(SetElem_TypedObject) \
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
5
js/src/jit-test/tests/basic/bug1380962.js
Normal file
5
js/src/jit-test/tests/basic/bug1380962.js
Normal 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})");
|
@ -1,4 +1,5 @@
|
||||
// |jit-test| allow-oom; allow-unhandlable-oom
|
||||
gczeal(0);
|
||||
function MyObject( value ) {}
|
||||
gcparam("maxBytes", gcparam("gcBytes") + 4*(1));
|
||||
gczeal(4);
|
||||
|
59
js/src/jit-test/tests/ion/inlining/inline-getelem-args.js
Normal file
59
js/src/jit-test/tests/ion/inlining/inline-getelem-args.js
Normal 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();
|
@ -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:
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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, ¬Packed);
|
||||
|
||||
masm.move32(Imm32(1), output);
|
||||
masm.jump(&done);
|
||||
masm.bind(¬Packed);
|
||||
masm.move32(Imm32(0), output);
|
||||
|
||||
masm.bind(&done);
|
||||
}
|
||||
|
||||
} // namespace jit
|
||||
} // namespace js
|
||||
|
@ -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);
|
||||
|
@ -122,6 +122,7 @@
|
||||
_(IntrinsicSubstringKernel) \
|
||||
_(IntrinsicObjectHasPrototype) \
|
||||
_(IntrinsicFinishBoundFunctionInit) \
|
||||
_(IntrinsicIsPackedArray) \
|
||||
\
|
||||
_(IntrinsicIsArrayIterator) \
|
||||
_(IntrinsicIsMapIterator) \
|
||||
|
@ -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>
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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) \
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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>) \
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
{
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user