mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-c to b2ginbound, a=merge
This commit is contained in:
commit
d56847e545
@ -224,7 +224,7 @@ DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
|
||||
aChildDoc->mParentDoc = this;
|
||||
|
||||
if (aCreating) {
|
||||
ProxyCreated(aChildDoc, 0);
|
||||
ProxyCreated(aChildDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -52,7 +52,6 @@ let CustomizationHandler = {
|
||||
},
|
||||
|
||||
_customizationChange: function() {
|
||||
gHomeButton.updatePersonalToolbarStyle();
|
||||
PlacesToolbarHelper.customizeChange();
|
||||
},
|
||||
|
||||
|
@ -1353,7 +1353,6 @@ let BookmarkingUI = {
|
||||
this.broadcaster.removeAttribute("stardisabled");
|
||||
this._updateStar();
|
||||
}
|
||||
this._updateToolbarStyle();
|
||||
},
|
||||
|
||||
_updateCustomizationState: function BUI__updateCustomizationState() {
|
||||
@ -1361,20 +1360,6 @@ let BookmarkingUI = {
|
||||
this._currentAreaType = placement && CustomizableUI.getAreaType(placement.area);
|
||||
},
|
||||
|
||||
_updateToolbarStyle: function BUI__updateToolbarStyle() {
|
||||
let onPersonalToolbar = false;
|
||||
if (this._currentAreaType == CustomizableUI.TYPE_TOOLBAR) {
|
||||
let personalToolbar = document.getElementById("PersonalToolbar");
|
||||
onPersonalToolbar = this.button.parentNode == personalToolbar ||
|
||||
this.button.parentNode.parentNode == personalToolbar;
|
||||
}
|
||||
|
||||
if (onPersonalToolbar)
|
||||
this.button.classList.add("bookmark-item");
|
||||
else
|
||||
this.button.classList.remove("bookmark-item");
|
||||
},
|
||||
|
||||
_uninitView: function BUI__uninitView() {
|
||||
// When an element with a placesView attached is removed and re-inserted,
|
||||
// XBL reapplies the binding causing any kind of issues and possible leaks,
|
||||
@ -1437,14 +1422,12 @@ let BookmarkingUI = {
|
||||
if (!this._isCustomizing) {
|
||||
this._uninitView();
|
||||
}
|
||||
this._updateToolbarStyle();
|
||||
},
|
||||
|
||||
onCustomizeEnd: function BUI_customizeEnd(aWindow) {
|
||||
if (aWindow == window) {
|
||||
this._isCustomizing = false;
|
||||
this.onToolbarVisibilityChange();
|
||||
this._updateToolbarStyle();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -597,8 +597,7 @@ toolbarbutton.bookmark-item {
|
||||
toolbar[mode="text"] #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
display: -moz-box !important;
|
||||
}
|
||||
toolbar[mode="text"] #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-text,
|
||||
toolbar[mode="full"] #bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button > .toolbarbutton-text {
|
||||
toolbar[mode="text"] #bookmarks-menu-button > .toolbarbutton-menubutton-button > .toolbarbutton-text {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -1296,7 +1296,6 @@ var gBrowserInit = {
|
||||
|
||||
var homeButton = document.getElementById("home-button");
|
||||
gHomeButton.updateTooltip(homeButton);
|
||||
gHomeButton.updatePersonalToolbarStyle(homeButton);
|
||||
|
||||
let safeMode = document.getElementById("helpSafeMode");
|
||||
if (Services.appinfo.inSafeMode) {
|
||||
@ -5388,17 +5387,6 @@ var gHomeButton = {
|
||||
|
||||
return url;
|
||||
},
|
||||
|
||||
updatePersonalToolbarStyle: function (homeButton)
|
||||
{
|
||||
if (!homeButton)
|
||||
homeButton = document.getElementById("home-button");
|
||||
if (homeButton)
|
||||
homeButton.className = homeButton.parentNode.id == "PersonalToolbar"
|
||||
|| homeButton.parentNode.parentNode.id == "PersonalToolbar" ?
|
||||
homeButton.className.replace("toolbarbutton-1", "bookmark-item") :
|
||||
homeButton.className.replace("bookmark-item", "toolbarbutton-1");
|
||||
},
|
||||
};
|
||||
|
||||
const nodeToTooltipMap = {
|
||||
|
@ -815,7 +815,6 @@
|
||||
|
||||
<toolbarbutton id="bookmarks-menu-button"
|
||||
class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
persist="class"
|
||||
removable="true"
|
||||
type="menu-button"
|
||||
label="&bookmarksMenuButton.label;"
|
||||
@ -939,7 +938,7 @@
|
||||
tooltip="dynamic-shortcut-tooltip"/>
|
||||
|
||||
<toolbarbutton id="home-button" class="toolbarbutton-1 chromeclass-toolbar-additional"
|
||||
persist="class" removable="true"
|
||||
removable="true"
|
||||
label="&homeButton.label;"
|
||||
ondragover="homeButtonObserver.onDragOver(event)"
|
||||
ondragenter="homeButtonObserver.onDragOver(event)"
|
||||
|
@ -60,7 +60,6 @@ skip-if = os == "linux"
|
||||
[browser_938980_navbar_collapsed.js]
|
||||
[browser_938995_indefaultstate_nonremovable.js]
|
||||
[browser_940013_registerToolbarNode_calls_registerArea.js]
|
||||
[browser_940107_home_button_in_bookmarks_toolbar.js]
|
||||
[browser_940307_panel_click_closure_handling.js]
|
||||
[browser_940946_removable_from_navbar_customizemode.js]
|
||||
[browser_941083_invalidate_wrapper_cache_createWidget.js]
|
||||
|
@ -1,41 +0,0 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Bug 940107 - Home icon not displayed correctly when in bookmarks toolbar.
|
||||
add_task(function() {
|
||||
ok(CustomizableUI.inDefaultState, "Should be in default state when test starts.");
|
||||
let bookmarksToolbar = document.getElementById(CustomizableUI.AREA_BOOKMARKS);
|
||||
bookmarksToolbar.collapsed = false;
|
||||
|
||||
let homeButton = document.getElementById("home-button");
|
||||
ok(homeButton.classList.contains("toolbarbutton-1"), "Home Button should have toolbarbutton-1 when in the nav-bar");
|
||||
ok(!homeButton.classList.contains("bookmark-item"), "Home Button should not be displayed as a bookmarks item");
|
||||
|
||||
yield startCustomizing();
|
||||
CustomizableUI.addWidgetToArea(homeButton.id, CustomizableUI.AREA_BOOKMARKS);
|
||||
yield endCustomizing();
|
||||
ok(homeButton.classList.contains("bookmark-item"), "Home Button should be displayed as a bookmarks item");
|
||||
ok(!homeButton.classList.contains("toolbarbutton-1"), "Home Button should not be displayed as a nav-bar item");
|
||||
|
||||
gCustomizeMode.addToPanel(homeButton);
|
||||
let panelShownPromise = promisePanelShown(window);
|
||||
PanelUI.toggle();
|
||||
yield panelShownPromise;
|
||||
|
||||
ok(homeButton.classList.contains("toolbarbutton-1"), "Home Button should have toolbarbutton-1 when in the panel");
|
||||
ok(!homeButton.classList.contains("bookmark-item"), "Home Button should not be displayed as a bookmarks item");
|
||||
|
||||
gCustomizeMode.addToToolbar(homeButton);
|
||||
let panelHiddenPromise = promisePanelHidden(window);
|
||||
PanelUI.toggle();
|
||||
yield panelHiddenPromise;
|
||||
|
||||
ok(homeButton.classList.contains("toolbarbutton-1"), "Home Button should have toolbarbutton-1 when in the nav-bar");
|
||||
ok(!homeButton.classList.contains("bookmark-item"), "Home Button should not be displayed as a bookmarks item");
|
||||
|
||||
bookmarksToolbar.collapsed = true;
|
||||
CustomizableUI.reset();
|
||||
});
|
@ -1771,7 +1771,7 @@ BrowserGlue.prototype = {
|
||||
},
|
||||
|
||||
_migrateUI: function BG__migrateUI() {
|
||||
const UI_VERSION = 30;
|
||||
const UI_VERSION = 31;
|
||||
const BROWSER_DOCURL = "chrome://browser/content/browser.xul";
|
||||
let currentUIVersion = 0;
|
||||
try {
|
||||
@ -2132,6 +2132,11 @@ BrowserGlue.prototype = {
|
||||
|
||||
Services.prefs.clearUserPref("browser.devedition.showCustomizeButton");
|
||||
}
|
||||
|
||||
if (currentUIVersion < 31) {
|
||||
xulStore.removeValue(BROWSER_DOCURL, "bookmarks-menu-button", "class");
|
||||
xulStore.removeValue(BROWSER_DOCURL, "home-button", "class");
|
||||
}
|
||||
|
||||
// Update the migration version.
|
||||
Services.prefs.setIntPref("browser.migration.version", UI_VERSION);
|
||||
|
@ -8,6 +8,7 @@ this.EXPORTED_SYMBOLS = ["ContentRestore"];
|
||||
|
||||
const Cu = Components.utils;
|
||||
const Ci = Components.interfaces;
|
||||
const Cr = Components.results;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm", this);
|
||||
|
||||
@ -182,8 +183,19 @@ ContentRestoreInternal.prototype = {
|
||||
let webNavigation = this.docShell.QueryInterface(Ci.nsIWebNavigation);
|
||||
let history = webNavigation.sessionHistory;
|
||||
|
||||
// Listen for the tab to finish loading.
|
||||
this.restoreTabContentStarted(finishCallback);
|
||||
// Wait for the tab load to complete or fail
|
||||
this.restoreTabContentStarted((status) => {
|
||||
// If loadArgument is not null then we're attempting to load a new url
|
||||
// that required us to switch process. If that load is cancelled (for
|
||||
// example by a content handler) we want to restore the current history
|
||||
// entry.
|
||||
if (loadArguments && (status == Cr.NS_BINDING_ABORTED)) {
|
||||
this._tabData = tabData;
|
||||
this.restoreTabContent(null, finishCallback);
|
||||
} else {
|
||||
finishCallback();
|
||||
}
|
||||
});
|
||||
|
||||
// Reset the current URI to about:blank. We changed it above for
|
||||
// switch-to-tab, but now it must go back to the correct value before the
|
||||
@ -248,22 +260,26 @@ ContentRestoreInternal.prototype = {
|
||||
*/
|
||||
restoreTabContentStarted(finishCallback) {
|
||||
// The reload listener is no longer needed.
|
||||
this._historyListener.uninstall();
|
||||
this._historyListener = null;
|
||||
if (this._historyListener) {
|
||||
this._historyListener.uninstall();
|
||||
this._historyListener = null;
|
||||
}
|
||||
|
||||
// Remove the old progress listener.
|
||||
this._progressListener.uninstall();
|
||||
if (this._progressListener) {
|
||||
this._progressListener.uninstall();
|
||||
}
|
||||
|
||||
// We're about to start a load. This listener will be called when the load
|
||||
// has finished getting everything from the network.
|
||||
this._progressListener = new ProgressListener(this.docShell, {
|
||||
onStopRequest: () => {
|
||||
onStopRequest: (status) => {
|
||||
// Call resetRestore() to reset the state back to normal. The data
|
||||
// needed for restoreDocument() (which hasn't happened yet) will
|
||||
// remain in _restoringDocument.
|
||||
this.resetRestore();
|
||||
|
||||
finishCallback();
|
||||
finishCallback(status);
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -415,7 +431,7 @@ ProgressListener.prototype = {
|
||||
}
|
||||
|
||||
if (stateFlags & STATE_STOP && this.callbacks.onStopRequest) {
|
||||
this.callbacks.onStopRequest();
|
||||
this.callbacks.onStopRequest(status);
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -45,3 +45,53 @@ add_task(function* () {
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
// Add a new non-remote tab.
|
||||
let tab = gBrowser.addTab("about:robots");
|
||||
let browser = tab.linkedBrowser;
|
||||
yield promiseBrowserLoaded(browser);
|
||||
ok(!browser.isRemoteBrowser, "browser is not remote");
|
||||
|
||||
// Wait for the tab to change to remote before adding the progress listener
|
||||
tab.addEventListener("TabRemotenessChange", function listener() {
|
||||
tab.removeEventListener("TabRemotenessChange", listener);
|
||||
|
||||
ContentTask.spawn(browser, URL, function*(url) {
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
let wp = docShell.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIWebProgress);
|
||||
|
||||
wp.addProgressListener({
|
||||
onStateChange: function(progress, request, stateFlags, status) {
|
||||
if (!(request instanceof Ci.nsIChannel))
|
||||
return;
|
||||
|
||||
if (request.URI.spec == url) {
|
||||
request.cancel(Cr.NS_BINDING_ABORTED);
|
||||
wp.removeProgressListener(this);
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIWebProgressListener,
|
||||
Ci.nsISupportsWeakReference
|
||||
])
|
||||
}, Ci.nsIWebProgress.NOTIFY_ALL);
|
||||
});
|
||||
});
|
||||
|
||||
// Load a new remote URI and when we see the load start cancel it
|
||||
browser.loadURI(URL);
|
||||
yield promiseTabRestored(tab);
|
||||
|
||||
let count = yield countHistoryEntries(browser);
|
||||
is(count, 1, "Should only be the one history entry.");
|
||||
|
||||
is(browser.currentURI.spec, "about:robots", "Should be back to the original URI");
|
||||
ok(!browser.isRemoteBrowser, "Should have gone back to a remote browser");
|
||||
|
||||
// Cleanup.
|
||||
gBrowser.removeTab(tab);
|
||||
});
|
||||
|
@ -3,6 +3,8 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
/* globals ViewHelpers, Task, AnimationsPanel, promise, EventEmitter,
|
||||
AnimationsFront */
|
||||
|
||||
"use strict";
|
||||
|
||||
@ -35,7 +37,8 @@ let startup = Task.async(function*(inspector) {
|
||||
|
||||
// Don't assume that AnimationsPanel is defined here, it's in another file.
|
||||
if (!typeof AnimationsPanel === "undefined") {
|
||||
throw new Error("AnimationsPanel was not loaded in the animationinspector window");
|
||||
throw new Error("AnimationsPanel was not loaded in the " +
|
||||
"animationinspector window");
|
||||
}
|
||||
|
||||
// Startup first initalizes the controller and then the panel, in sequence.
|
||||
@ -170,7 +173,7 @@ let AnimationsController = {
|
||||
gInspector.sidebar.getCurrentTabID() == "animationinspector";
|
||||
},
|
||||
|
||||
onPanelVisibilityChange: Task.async(function*(e, id) {
|
||||
onPanelVisibilityChange: Task.async(function*() {
|
||||
if (this.isPanelVisible()) {
|
||||
this.onNewNodeFront();
|
||||
this.startAllAutoRefresh();
|
||||
@ -181,14 +184,15 @@ let AnimationsController = {
|
||||
|
||||
onNewNodeFront: Task.async(function*() {
|
||||
// Ignore if the panel isn't visible or the node selection hasn't changed.
|
||||
if (!this.isPanelVisible() || this.nodeFront === gInspector.selection.nodeFront) {
|
||||
if (!this.isPanelVisible() ||
|
||||
this.nodeFront === gInspector.selection.nodeFront) {
|
||||
return;
|
||||
}
|
||||
|
||||
let done = gInspector.updating("animationscontroller");
|
||||
|
||||
if(!gInspector.selection.isConnected() ||
|
||||
!gInspector.selection.isElementNode()) {
|
||||
if (!gInspector.selection.isConnected() ||
|
||||
!gInspector.selection.isElementNode()) {
|
||||
yield this.destroyAnimationPlayers();
|
||||
this.emit(this.PLAYERS_UPDATED_EVENT);
|
||||
done();
|
||||
@ -207,7 +211,7 @@ let AnimationsController = {
|
||||
*/
|
||||
toggleAll: function() {
|
||||
if (!this.hasToggleAll) {
|
||||
return promis.resolve();
|
||||
return promise.resolve();
|
||||
}
|
||||
|
||||
return this.animationsFront.toggleAll().catch(Cu.reportError);
|
||||
|
@ -783,7 +783,8 @@ AnimationsTimeline.prototype = {
|
||||
drawHeaderAndBackground: function() {
|
||||
let width = this.timeHeaderEl.offsetWidth;
|
||||
let scale = width / (TimeScale.maxEndTime - TimeScale.minStartTime);
|
||||
drawGraphElementBackground(this.win.document, "time-graduations", width, scale);
|
||||
drawGraphElementBackground(this.win.document, "time-graduations",
|
||||
width, scale);
|
||||
|
||||
// And the time graduation header.
|
||||
this.timeHeaderEl.innerHTML = "";
|
||||
|
@ -16,8 +16,10 @@ const TIME_INTERVAL_SCALES = 3;
|
||||
const TIME_GRADUATION_MIN_SPACING = 10;
|
||||
// RGB color for the time interval background.
|
||||
const TIME_INTERVAL_COLOR = [128, 136, 144];
|
||||
const TIME_INTERVAL_OPACITY_MIN = 32; // byte
|
||||
const TIME_INTERVAL_OPACITY_ADD = 32; // byte
|
||||
// byte
|
||||
const TIME_INTERVAL_OPACITY_MIN = 32;
|
||||
// byte
|
||||
const TIME_INTERVAL_OPACITY_ADD = 32;
|
||||
|
||||
/**
|
||||
* DOM node creation helper function.
|
||||
|
@ -14,6 +14,8 @@ const DARK_BG = "#14171a";
|
||||
setTheme("dark");
|
||||
Services.prefs.setBoolPref(MEMORY_PREF, false);
|
||||
|
||||
requestLongerTimeout(2);
|
||||
|
||||
function* spawnTest() {
|
||||
let { panel } = yield initPerformance(SIMPLE_URL);
|
||||
let { EVENTS, $, OverviewView, document: doc } = panel.panelWin;
|
||||
|
@ -7,7 +7,7 @@ const { ViewHelpers, Heritage } = require("resource:///modules/devtools/ViewHelp
|
||||
const { AbstractCanvasGraph, CanvasGraphUtils } = require("devtools/shared/widgets/Graphs");
|
||||
|
||||
const HTML_NS = "http://www.w3.org/1999/xhtml";
|
||||
const L10N = new ViewHelpers.L10N();
|
||||
const L10N = new ViewHelpers.L10N("chrome://browser/locale/devtools/graphs.properties");
|
||||
|
||||
// Line graph constants.
|
||||
|
||||
@ -76,11 +76,11 @@ this.LineGraphWidget = function(parent, options = {}, ...args) {
|
||||
// are changed later
|
||||
this._gutter = this._createGutter();
|
||||
this._maxGutterLine = this._createGutterLine("maximum");
|
||||
this._maxTooltip = this._createTooltip("maximum", "start", "max", metric);
|
||||
this._maxTooltip = this._createTooltip("maximum", "start", L10N.getStr("graphs.label.maximum"), metric);
|
||||
this._minGutterLine = this._createGutterLine("minimum");
|
||||
this._minTooltip = this._createTooltip("minimum", "start", "min", metric);
|
||||
this._minTooltip = this._createTooltip("minimum", "start", L10N.getStr("graphs.label.minimum"), metric);
|
||||
this._avgGutterLine = this._createGutterLine("average");
|
||||
this._avgTooltip = this._createTooltip("average", "end", "avg", metric);
|
||||
this._avgTooltip = this._createTooltip("average", "end", L10N.getStr("graphs.label.average"), metric);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
# LOCALIZATION NOTE These strings are used inside the Performance Tools
|
||||
# which is available from the Web Developer sub-menu -> 'Performance'.
|
||||
# The correct localization of this file might be to keep it in
|
||||
# English, or another language commonly spoken among web developers.
|
||||
# You want to make that choice consistent across the developer tools.
|
||||
# A good criteria is the language in which you'd find the best
|
||||
# documentation on web development on the web. These strings
|
||||
# are specifically for marker names in the performance tool.
|
||||
|
||||
# LOCALIZATION NOTE (graphs.label.average):
|
||||
# This string is displayed on graphs when showing an average.
|
||||
graphs.label.average=avg
|
||||
|
||||
# LOCALIZATION NOTE (graphs.label.minimum):
|
||||
# This string is displayed on graphs when showing a minimum.
|
||||
graphs.label.minimum=min
|
||||
|
||||
# LOCALIZATION NOTE (graphs.label.maximum):
|
||||
# This string is displayed on graphs when showing a maximum.
|
||||
graphs.label.maximum=max
|
@ -46,10 +46,6 @@
|
||||
- on a button that opens a dialog to import a saved profile data file. -->
|
||||
<!ENTITY performanceUI.importButton "Import…">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.exportButton): This string is displayed
|
||||
- on a button that opens a dialog to export a saved profile data file. -->
|
||||
<!ENTITY performanceUI.exportButton "Save">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.clearButton): This string is displayed
|
||||
- on a button that removes all the recordings. -->
|
||||
<!ENTITY performanceUI.clearButton "Clear">
|
||||
@ -57,17 +53,14 @@
|
||||
<!-- LOCALIZATION NOTE (performanceUI.toolbar.*): These strings are displayed
|
||||
- in the toolbar on buttons that select which view is currently shown. -->
|
||||
<!ENTITY performanceUI.toolbar.waterfall "Waterfall">
|
||||
<!ENTITY performanceUI.toolbar.js-calltree "Call Tree">
|
||||
<!ENTITY performanceUI.toolbar.memory-calltree "Allocations">
|
||||
<!ENTITY performanceUI.toolbar.js-flamegraph "JS Flame Chart">
|
||||
<!ENTITY performanceUI.toolbar.memory-flamegraph "Allocations Flame Chart">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.toolbar.*.tooltiptext): These strings are
|
||||
- displayed as tooltips on buttons that select which view is shown. -->
|
||||
<!ENTITY performanceUI.toolbar.waterfall.tooltiptext "Shows the different operations the browser is performing during the recording, laid out sequentially as a waterfall.">
|
||||
<!ENTITY performanceUI.toolbar.js-calltree "Call Tree">
|
||||
<!ENTITY performanceUI.toolbar.js-calltree.tooltiptext "Highlights JavaScript functions where the browser spent most time during the recording.">
|
||||
<!ENTITY performanceUI.toolbar.js-flamegraph.tooltiptext "Shows the JavaScript call stack over the course of the recording.">
|
||||
<!ENTITY performanceUI.toolbar.memory-calltree "Allocations">
|
||||
<!ENTITY performanceUI.toolbar.allocations.tooltiptext "Shows where memory was allocated during the recording.">
|
||||
<!ENTITY performanceUI.toolbar.js-flamegraph "JS Flame Chart">
|
||||
<!ENTITY performanceUI.toolbar.js-flamegraph.tooltiptext "Shows the JavaScript call stack over the course of the recording.">
|
||||
<!ENTITY performanceUI.toolbar.memory-flamegraph "Allocations Flame Chart">
|
||||
|
||||
<!-- LOCALIZATION NOTE (performanceUI.table.*): These strings are displayed
|
||||
- in the call tree headers for a recording. -->
|
||||
|
@ -63,6 +63,7 @@
|
||||
locale/browser/devtools/promisedebugger.properties (%chrome/browser/devtools/promisedebugger.properties)
|
||||
locale/browser/devtools/performance.dtd (%chrome/browser/devtools/performance.dtd)
|
||||
locale/browser/devtools/performance.properties (%chrome/browser/devtools/performance.properties)
|
||||
locale/browser/devtools/graphs.properties (%chrome/browser/devtools/graphs.properties)
|
||||
locale/browser/devtools/layoutview.dtd (%chrome/browser/devtools/layoutview.dtd)
|
||||
locale/browser/devtools/responsiveUI.properties (%chrome/browser/devtools/responsiveUI.properties)
|
||||
locale/browser/devtools/toolbox.dtd (%chrome/browser/devtools/toolbox.dtd)
|
||||
|
@ -142,7 +142,7 @@ toolbarbutton.bookmark-item[open="true"] {
|
||||
-moz-padding-end: 2px;
|
||||
}
|
||||
|
||||
.bookmark-item:not(#home-button) > .toolbarbutton-icon,
|
||||
.bookmark-item > .toolbarbutton-icon,
|
||||
#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
@ -1108,8 +1108,7 @@ notification[value="loop-sharing-notification"] .messageImage {
|
||||
|
||||
.ac-result-type-bookmark,
|
||||
.autocomplete-treebody::-moz-tree-image(bookmark, treecolAutoCompleteImage) {
|
||||
list-style-image: url("chrome://browser/skin/places/star-icons.png");
|
||||
-moz-image-region: rect(0px 32px 16px 16px);
|
||||
list-style-image: url("chrome://browser/skin/places/autocomplete-star.png");
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
@ -190,6 +190,7 @@ browser.jar:
|
||||
skin/classic/browser/panic-panel/header-small@2x.png (../shared/panic-panel/header-small@2x.png)
|
||||
skin/classic/browser/panic-panel/icons.png (../shared/panic-panel/icons.png)
|
||||
skin/classic/browser/panic-panel/icons@2x.png (../shared/panic-panel/icons@2x.png)
|
||||
skin/classic/browser/places/autocomplete-star.png (places/autocomplete-star.png)
|
||||
skin/classic/browser/places/bookmarksMenu.png (places/bookmarksMenu.png)
|
||||
skin/classic/browser/places/bookmarksToolbar.png (places/bookmarksToolbar.png)
|
||||
skin/classic/browser/places/bookmarksToolbar-menuPanel.png (places/bookmarksToolbar-menuPanel.png)
|
||||
@ -198,7 +199,6 @@ browser.jar:
|
||||
skin/classic/browser/places/calendar.png (places/calendar.png)
|
||||
* skin/classic/browser/places/editBookmarkOverlay.css (places/editBookmarkOverlay.css)
|
||||
skin/classic/browser/places/livemark-item.png (places/livemark-item.png)
|
||||
skin/classic/browser/places/star-icons.png (places/star-icons.png)
|
||||
skin/classic/browser/places/starred48.png (places/starred48.png)
|
||||
skin/classic/browser/places/unstarred48.png (places/unstarred48.png)
|
||||
skin/classic/browser/places/places.css (places/places.css)
|
||||
|
BIN
browser/themes/linux/places/autocomplete-star.png
Normal file
BIN
browser/themes/linux/places/autocomplete-star.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 636 B |
Binary file not shown.
Before Width: | Height: | Size: 978 B |
@ -294,7 +294,7 @@ toolbarbutton.chevron:-moz-locale-dir(rtl) > .toolbarbutton-icon {
|
||||
|
||||
/* ----- BOOKMARK BUTTONS ----- */
|
||||
|
||||
toolbarbutton.bookmark-item:not(.subviewbutton):not(#bookmarks-menu-button),
|
||||
toolbarbutton.bookmark-item:not(.subviewbutton),
|
||||
#personal-bookmarks[cui-areatype="toolbar"]:not([overflowedItem=true]) > #bookmarks-toolbar-placeholder {
|
||||
border: 0;
|
||||
border-radius: 10000px;
|
||||
@ -330,7 +330,7 @@ toolbarbutton.bookmark-item:not(.subviewbutton):not(#bookmarks-menu-button),
|
||||
display: -moz-box !important; /* Force the display of the label for bookmarks */
|
||||
}
|
||||
|
||||
toolbarbutton.bookmark-item:not(.subviewbutton):not(#bookmarks-menu-button):hover {
|
||||
toolbarbutton.bookmark-item:not(.subviewbutton):hover {
|
||||
background-color: rgba(0, 0, 0, .205);
|
||||
}
|
||||
|
||||
@ -352,8 +352,8 @@ toolbarbutton.bookmark-item[open="true"]:not(.subviewbutton) {
|
||||
}
|
||||
}
|
||||
|
||||
toolbarbutton.bookmark-item:not(.subviewbutton):not(#bookmarks-menu-button):active:hover,
|
||||
toolbarbutton.bookmark-item:not(.subviewbutton):not(#bookmarks-menu-button)[open="true"] {
|
||||
toolbarbutton.bookmark-item:not(.subviewbutton):active:hover,
|
||||
toolbarbutton.bookmark-item:not(.subviewbutton)[open="true"] {
|
||||
box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.4), 0 1px rgba(255, 255, 255, 0.4);
|
||||
background-color: rgba(0, 0, 0, .5);
|
||||
}
|
||||
@ -363,7 +363,7 @@ toolbarbutton.bookmark-item > menupopup {
|
||||
-moz-margin-start: 3px;
|
||||
}
|
||||
|
||||
.bookmark-item:not(#home-button) > .toolbarbutton-icon,
|
||||
.bookmark-item > .toolbarbutton-icon,
|
||||
#personal-bookmarks[cui-areatype="toolbar"] > #bookmarks-toolbar-placeholder > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
min-height: 16px;
|
||||
@ -1427,21 +1427,6 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||
list-style-image: url("chrome://browser/skin/menu-forward.png") !important;
|
||||
}
|
||||
|
||||
/* home button */
|
||||
|
||||
#home-button.bookmark-item {
|
||||
/* We need to use !important here, because other selectors that apply padding
|
||||
are more specific. */
|
||||
padding-top: 0 !important;
|
||||
padding-bottom: 0 !important;
|
||||
}
|
||||
|
||||
#home-button.bookmark-item > .toolbarbutton-icon {
|
||||
display: -moz-box !important;
|
||||
-moz-margin-start: -2px;
|
||||
-moz-margin-end: 3px;
|
||||
}
|
||||
|
||||
/* tabview menu item */
|
||||
|
||||
#menu_tabview {
|
||||
@ -1805,8 +1790,13 @@ toolbarbutton[constrain-size="true"][cui-areatype="toolbar"] > .toolbarbutton-ba
|
||||
|
||||
.ac-result-type-bookmark,
|
||||
.autocomplete-treebody::-moz-tree-image(bookmark, treecolAutoCompleteImage) {
|
||||
list-style-image: url("chrome://browser/skin/places/star-icons.png");
|
||||
-moz-image-region: rect(0, 48px, 16px, 32px);
|
||||
list-style-image: url("chrome://browser/skin/places/autocomplete-star.png");
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
richlistitem[selected="true"][current="true"] > .ac-title-box > .ac-result-type-bookmark,
|
||||
.autocomplete-treebody::-moz-tree-image(selected, current, bookmark, treecolAutoCompleteImage) {
|
||||
-moz-image-region: rect(0, 32px, 16px, 16px);
|
||||
}
|
||||
|
||||
.ac-result-type-keyword,
|
||||
@ -1823,12 +1813,6 @@ richlistitem[type~="action"][actiontype="searchengine"][selected="true"] > .ac-t
|
||||
list-style-image: url(chrome://global/skin/icons/autocomplete-search.svg#search-icon-inverted);
|
||||
}
|
||||
|
||||
richlistitem[selected="true"][current="true"] > .ac-title-box > .ac-result-type-bookmark,
|
||||
.autocomplete-treebody::-moz-tree-image(selected, current, bookmark, treecolAutoCompleteImage) {
|
||||
list-style-image: url("chrome://browser/skin/places/star-icons.png");
|
||||
-moz-image-region: rect(0, 64px, 16px, 48px);
|
||||
}
|
||||
|
||||
.ac-result-type-tag,
|
||||
.autocomplete-treebody::-moz-tree-image(tag, treecolAutoCompleteImage) {
|
||||
list-style-image: url("chrome://browser/skin/places/tag.png");
|
||||
@ -1856,15 +1840,15 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
|
||||
-moz-image-region: rect(11px, 16px, 22px, 0);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.ac-result-type-bookmark {
|
||||
list-style-image: url("chrome://browser/skin/places/star-icons@2x.png");
|
||||
-moz-image-region: rect(0, 64px, 32px, 32px);
|
||||
list-style-image: url("chrome://browser/skin/places/autocomplete-star@2x.png");
|
||||
-moz-image-region: rect(0, 32px, 32px, 0);
|
||||
}
|
||||
|
||||
richlistitem[selected="true"][current="true"] > .ac-title-box > .ac-result-type-bookmark {
|
||||
list-style-image: url("chrome://browser/skin/places/star-icons@2x.png");
|
||||
-moz-image-region: rect(0, 128px, 32px, 96px);
|
||||
list-style-image: url("chrome://browser/skin/places/autocomplete-star@2x.png");
|
||||
-moz-image-region: rect(0, 64px, 32px, 32px);
|
||||
}
|
||||
|
||||
.ac-result-type-tag {
|
||||
@ -2103,38 +2087,6 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
|
||||
-moz-image-region: rect(0, 16px, 16px, 0);
|
||||
}
|
||||
|
||||
/* bookmarks menu-button */
|
||||
|
||||
#bookmarks-menu-button.bookmark-item,
|
||||
#bookmarks-menu-button.bookmark-item[open] {
|
||||
list-style-image: url("chrome://browser/skin/places/star-icons.png");
|
||||
-moz-image-region: rect(0px 16px 16px 0px);
|
||||
}
|
||||
|
||||
#bookmarks-menu-button.bookmark-item[starred] {
|
||||
-moz-image-region: rect(0px 32px 16px 16px);
|
||||
}
|
||||
|
||||
#bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#bookmarks-menu-button.bookmark-item,
|
||||
#bookmarks-menu-button.bookmark-item[open] {
|
||||
list-style-image: url("chrome://browser/skin/places/star-icons@2x.png");
|
||||
-moz-image-region: rect(0px 32px 32px 0px);
|
||||
}
|
||||
|
||||
#bookmarks-menu-button.bookmark-item[starred] {
|
||||
-moz-image-region: rect(0px 64px 32px 32px);
|
||||
}
|
||||
|
||||
#bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* BOOKMARKING PANEL */
|
||||
#editBookmarkPanelStarIcon {
|
||||
list-style-image: url("chrome://browser/skin/places/starred48.png");
|
||||
|
@ -250,6 +250,8 @@ browser.jar:
|
||||
skin/classic/browser/panic-panel/icons.png (../shared/panic-panel/icons.png)
|
||||
skin/classic/browser/panic-panel/icons@2x.png (../shared/panic-panel/icons@2x.png)
|
||||
skin/classic/browser/places/allBookmarks.png (places/allBookmarks.png)
|
||||
skin/classic/browser/places/autocomplete-star.png (places/autocomplete-star.png)
|
||||
skin/classic/browser/places/autocomplete-star@2x.png (places/autocomplete-star@2x.png)
|
||||
* skin/classic/browser/places/places.css (places/places.css)
|
||||
* skin/classic/browser/places/organizer.css (places/organizer.css)
|
||||
skin/classic/browser/places/query.png (places/query.png)
|
||||
@ -263,8 +265,6 @@ browser.jar:
|
||||
skin/classic/browser/places/bookmarksToolbar-menuPanel@2x.png (places/bookmarksToolbar-menuPanel@2x.png)
|
||||
skin/classic/browser/places/history.png (places/history.png)
|
||||
skin/classic/browser/places/history@2x.png (places/history@2x.png)
|
||||
skin/classic/browser/places/star-icons.png (places/star-icons.png)
|
||||
skin/classic/browser/places/star-icons@2x.png (places/star-icons@2x.png)
|
||||
skin/classic/browser/places/toolbar.png (places/toolbar.png)
|
||||
skin/classic/browser/places/toolbarDropMarker.png (places/toolbarDropMarker.png)
|
||||
skin/classic/browser/places/folderDropArrow.png (places/folderDropArrow.png)
|
||||
|
BIN
browser/themes/osx/places/autocomplete-star.png
Normal file
BIN
browser/themes/osx/places/autocomplete-star.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 653 B |
BIN
browser/themes/osx/places/autocomplete-star@2x.png
Normal file
BIN
browser/themes/osx/places/autocomplete-star@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Binary file not shown.
Before Width: | Height: | Size: 1.4 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.5 KiB |
@ -1453,16 +1453,6 @@ html|*.urlbar-input:-moz-lwtheme::-moz-placeholder,
|
||||
|
||||
/* identity box */
|
||||
|
||||
#identity-box:-moz-locale-dir(ltr) {
|
||||
border-top-left-radius: 1.5px;
|
||||
border-bottom-left-radius: 1.5px;
|
||||
}
|
||||
|
||||
#identity-box:-moz-locale-dir(rtl) {
|
||||
border-top-right-radius: 1.5px;
|
||||
border-bottom-right-radius: 1.5px;
|
||||
}
|
||||
|
||||
#identity-box.verifiedIdentity:not(:-moz-lwtheme):not(:hover):not([open=true]) {
|
||||
background-color: var(--identity-box-verified-background-color);
|
||||
}
|
||||
@ -1876,11 +1866,7 @@ richlistitem[type~="action"][actiontype="switchtab"] > .ac-url-box > .ac-action-
|
||||
|
||||
/* bookmarks menu-button */
|
||||
|
||||
#bookmarks-menu-button.bookmark-item > .toolbarbutton-menubutton-button > .toolbarbutton-icon {
|
||||
-moz-margin-start: 5px;
|
||||
}
|
||||
|
||||
#bookmarks-menu-button[cui-areatype="toolbar"]:not(.bookmark-item):not([overflowedItem=true]) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
#nav-bar #bookmarks-menu-button[cui-areatype="toolbar"]:not([overflowedItem=true]) > .toolbarbutton-menubutton-dropmarker > .dropmarker-icon {
|
||||
padding-top: var(--toolbarbutton-vertical-inner-padding);
|
||||
padding-bottom: var(--toolbarbutton-vertical-inner-padding);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
/*** Main indicator icon ***/
|
||||
|
||||
@media not all and (min-resolution: 1.1dppx) {
|
||||
#downloads-indicator-icon {
|
||||
#downloads-button {
|
||||
--downloads-indicator-icon: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"), 0, 198, 18, 180);
|
||||
--downloads-indicator-icon-attention: -moz-image-rect(url("chrome://browser/skin/Toolbar.png"), 18, 198, 36, 180);
|
||||
--downloads-indicator-icon-inverted: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 198, 18, 180);
|
||||
@ -29,7 +29,7 @@
|
||||
}
|
||||
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
#downloads-indicator-icon {
|
||||
#downloads-button {
|
||||
--downloads-indicator-icon: -moz-image-rect(url("chrome://browser/skin/Toolbar@2x.png"), 0, 396, 36, 360);
|
||||
--downloads-indicator-icon-attention: -moz-image-rect(url("chrome://browser/skin/Toolbar@2x.png"), 36, 396, 72, 360);
|
||||
--downloads-indicator-icon-inverted: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted@2x.png"), 0, 396, 36, 360);
|
||||
|
@ -31,3 +31,4 @@ redo.pth:python/redo
|
||||
requests.pth:python/requests
|
||||
rsa.pth:python/rsa
|
||||
futures.pth:python/futures
|
||||
ecc.pth:python/PyECC
|
||||
|
@ -33,13 +33,20 @@ architecture_independent = set([ 'generic' ])
|
||||
all_architecture_names = set([ 'x86', 'x64', 'arm', 'arm64', 'mips32' ])
|
||||
all_shared_architecture_names = set([ 'x86_shared', 'arm', 'arm64', 'mips32' ])
|
||||
|
||||
reBeforeArg = "(?<=[(,\s])"
|
||||
reArgType = "(?P<type>[\w\s:*&]+)"
|
||||
reArgName = "(?P<name>\s\w+)"
|
||||
reArgDefault = "(?P<default>(?:\s=[^,)]+)?)"
|
||||
reAfterArg = "(?=[,)])"
|
||||
reMatchArg = re.compile(reBeforeArg + reArgType + reArgName + reArgDefault + reAfterArg)
|
||||
|
||||
def get_normalized_signatures(signature, fileAnnot = None):
|
||||
# Remove semicolon.
|
||||
signature = signature.replace(';', ' ')
|
||||
# Normalize spaces.
|
||||
signature = re.sub(r'\s+', ' ', signature).strip()
|
||||
# Remove argument names.
|
||||
signature = re.sub(r'(?P<type>(?:[(]|,\s)[\w\s:*&]+)(?P<name>\s\w+)(?=[,)])', '\g<type>', signature)
|
||||
# Match arguments, and keep only the type.
|
||||
signature = reMatchArg.sub('\g<type>', signature)
|
||||
# Remove class name
|
||||
signature = signature.replace('MacroAssembler::', '')
|
||||
|
||||
@ -74,11 +81,16 @@ def get_normalized_signatures(signature, fileAnnot = None):
|
||||
signature = re.sub(r'inline\s+', '', signature)
|
||||
inline = True
|
||||
|
||||
return [
|
||||
{ 'arch': a, 'sig': 'inline ' + signature }
|
||||
inlinePrefx = ''
|
||||
if inline:
|
||||
inlinePrefx = 'inline '
|
||||
signatures = [
|
||||
{ 'arch': a, 'sig': inlinePrefx + signature }
|
||||
for a in archs
|
||||
]
|
||||
|
||||
return signatures
|
||||
|
||||
file_suffixes = set([
|
||||
a.replace('_', '-') for a in
|
||||
all_architecture_names.union(all_shared_architecture_names)
|
||||
|
@ -9,15 +9,10 @@ fetch("audio.ogg").then(response => {
|
||||
var src = ac.createBufferSource();
|
||||
src.buffer = ab;
|
||||
src.loop = true;
|
||||
src.loopStart = 0;
|
||||
src.loopEnd = ab.duration;
|
||||
src.start();
|
||||
src.connect(ac.destination);
|
||||
setTimeout(() => {
|
||||
if (ac.state == "running") {
|
||||
parent.runTest();
|
||||
} else {
|
||||
setTimeout(arguments.callee, 0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
var suspendPromise;
|
||||
|
@ -304,6 +304,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1
|
||||
[test_noAudioNotificationOnMutedElement.html]
|
||||
[test_noAudioNotificationOnMutedOrVolume0Element.html]
|
||||
[test_noAudioNotificationOnVolume0Element.html]
|
||||
[test_noWebAudioNotification.html]
|
||||
[test_openDialogChromeOnly.html]
|
||||
[test_open_null_features.html]
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Fails on b2g-desktop, tracked in bug 1011874
|
||||
|
66
dom/base/test/test_noWebAudioNotification.html
Normal file
66
dom/base/test/test_noWebAudioNotification.html
Normal file
@ -0,0 +1,66 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for video controller in windows</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
|
||||
<script type="application/javascript">
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SimpleTest.requestFlakyTimeout("Testing an event not happening");
|
||||
|
||||
var observer = {
|
||||
observe: function(subject, topic, data) {
|
||||
ok(false, "should not receive audio-playback notification!");
|
||||
}
|
||||
};
|
||||
|
||||
var observerService = SpecialPowers.Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(SpecialPowers.Ci.nsIObserverService);
|
||||
|
||||
var ac;
|
||||
|
||||
var tests = [
|
||||
function() {
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelService", true]]}, runTest);
|
||||
},
|
||||
|
||||
function() {
|
||||
observerService.addObserver(observer, "audio-playback", false);
|
||||
ok(true, "Observer set");
|
||||
runTest();
|
||||
},
|
||||
|
||||
function() {
|
||||
ac = new AudioContext();
|
||||
setTimeout(runTest, 100);
|
||||
},
|
||||
|
||||
function() {
|
||||
observerService.removeObserver(observer, "audio-playback");
|
||||
ok(true, "Observer removed");
|
||||
runTest();
|
||||
}
|
||||
];
|
||||
|
||||
function runTest() {
|
||||
if (!tests.length) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
var test = tests.shift();
|
||||
test();
|
||||
}
|
||||
|
||||
runTest();
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -34,16 +34,17 @@ var tests = [
|
||||
SpecialPowers.pushPrefEnv({"set": [["media.useAudioChannelService", true]]}, runTest);
|
||||
},
|
||||
|
||||
function() {
|
||||
iframe.src = "file_webaudioLoop.html";
|
||||
},
|
||||
|
||||
function() {
|
||||
observerService.addObserver(observer, "audio-playback", false);
|
||||
ok(true, "Observer set");
|
||||
runTest();
|
||||
},
|
||||
|
||||
function() {
|
||||
iframe.src = "file_webaudioLoop.html";
|
||||
expectedNotification = 'active';
|
||||
},
|
||||
|
||||
function() {
|
||||
expectedNotification = 'inactive';
|
||||
iframe.contentWindow.suspendAC();
|
||||
|
@ -855,7 +855,7 @@ AudioContext::Suspend(ErrorResult& aRv)
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
Destination()->DestroyAudioChannelAgent();
|
||||
Destination()->Suspend();
|
||||
|
||||
MediaStream* ds = DestinationStream();
|
||||
if (ds) {
|
||||
@ -895,7 +895,7 @@ AudioContext::Resume(ErrorResult& aRv)
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
Destination()->CreateAudioChannelAgent();
|
||||
Destination()->Resume();
|
||||
|
||||
MediaStream* ds = DestinationStream();
|
||||
if (ds) {
|
||||
|
@ -243,7 +243,8 @@ public:
|
||||
explicit DestinationNodeEngine(AudioDestinationNode* aNode)
|
||||
: AudioNodeEngine(aNode)
|
||||
, mVolume(1.0f)
|
||||
, mLastInputMuted(false)
|
||||
, mLastInputMuted(true)
|
||||
, mSuspended(false)
|
||||
{
|
||||
MOZ_ASSERT(aNode);
|
||||
}
|
||||
@ -256,6 +257,10 @@ public:
|
||||
*aOutput = aInput;
|
||||
aOutput->mVolume *= mVolume;
|
||||
|
||||
if (mSuspended) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool newInputMuted = aInput.IsNull() || aInput.IsMuted();
|
||||
if (newInputMuted != mLastInputMuted) {
|
||||
mLastInputMuted = newInputMuted;
|
||||
@ -274,8 +279,19 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void SetInt32Parameter(uint32_t aIndex, int32_t aParam) override
|
||||
{
|
||||
if (aIndex == SUSPENDED) {
|
||||
mSuspended = !!aParam;
|
||||
if (mSuspended) {
|
||||
mLastInputMuted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum Parameters {
|
||||
VOLUME,
|
||||
SUSPENDED,
|
||||
};
|
||||
|
||||
virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override
|
||||
@ -286,6 +302,7 @@ public:
|
||||
private:
|
||||
float mVolume;
|
||||
bool mLastInputMuted;
|
||||
bool mSuspended;
|
||||
};
|
||||
|
||||
static bool UseAudioChannelService()
|
||||
@ -451,6 +468,20 @@ AudioDestinationNode::Unmute()
|
||||
SendDoubleParameterToStream(DestinationNodeEngine::VOLUME, 1.0f);
|
||||
}
|
||||
|
||||
void
|
||||
AudioDestinationNode::Suspend()
|
||||
{
|
||||
DestroyAudioChannelAgent();
|
||||
SendInt32ParameterToStream(DestinationNodeEngine::SUSPENDED, 1);
|
||||
}
|
||||
|
||||
void
|
||||
AudioDestinationNode::Resume()
|
||||
{
|
||||
CreateAudioChannelAgent();
|
||||
SendInt32ParameterToStream(DestinationNodeEngine::SUSPENDED, 0);
|
||||
}
|
||||
|
||||
void
|
||||
AudioDestinationNode::OfflineShutdown()
|
||||
{
|
||||
@ -512,7 +543,12 @@ AudioDestinationNode::WindowAudioCaptureChanged()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool captured = GetOwner()->GetAudioCaptured();
|
||||
nsCOMPtr<nsPIDOMWindow> ownerWindow = GetOwner();
|
||||
if (!ownerWindow) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool captured = ownerWindow->GetAudioCaptured();
|
||||
|
||||
if (captured != mCaptured) {
|
||||
if (captured) {
|
||||
@ -613,10 +649,6 @@ AudioDestinationNode::CreateAudioChannelAgent()
|
||||
static_cast<int32_t>(mAudioChannel),
|
||||
this);
|
||||
|
||||
// The AudioChannelAgent must start playing immediately in order to avoid
|
||||
// race conditions with mozinterruptbegin/end events.
|
||||
InputMuted(false);
|
||||
|
||||
WindowAudioCaptureChanged();
|
||||
}
|
||||
|
||||
@ -692,7 +724,10 @@ AudioDestinationNode::InputMuted(bool aMuted)
|
||||
MOZ_ASSERT(Context() && !Context()->IsOffline());
|
||||
|
||||
if (!mAudioChannelAgent) {
|
||||
return;
|
||||
if (aMuted) {
|
||||
return;
|
||||
}
|
||||
CreateAudioChannelAgent();
|
||||
}
|
||||
|
||||
if (aMuted) {
|
||||
|
@ -53,6 +53,9 @@ public:
|
||||
void Mute();
|
||||
void Unmute();
|
||||
|
||||
void Suspend();
|
||||
void Resume();
|
||||
|
||||
void StartRendering(Promise* aPromise);
|
||||
|
||||
void OfflineShutdown();
|
||||
|
@ -52,11 +52,6 @@ ServiceWorker::ServiceWorker(nsPIDOMWindow* aWindow,
|
||||
MOZ_ASSERT(aInfo);
|
||||
MOZ_ASSERT(mSharedWorker);
|
||||
|
||||
if (aWindow) {
|
||||
mDocument = aWindow->GetExtantDoc();
|
||||
mWindow = aWindow->GetOuterWindow();
|
||||
}
|
||||
|
||||
// This will update our state too.
|
||||
mInfo->AppendWorker(this);
|
||||
}
|
||||
@ -74,7 +69,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorker)
|
||||
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorker, DOMEventTargetHelper,
|
||||
mSharedWorker, mDocument, mWindow)
|
||||
mSharedWorker)
|
||||
|
||||
JSObject*
|
||||
ServiceWorker::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
@ -95,20 +90,22 @@ ServiceWorker::PostMessage(JSContext* aCx, JS::Handle<JS::Value> aMessage,
|
||||
const Optional<Sequence<JS::Value>>& aTransferable,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
if (State() == ServiceWorkerState::Redundant) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mDocument && mWindow,
|
||||
"Cannot call PostMessage on a ServiceWorker object that doesn't "
|
||||
"have a window");
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(GetParentObject());
|
||||
if (!window || !window->GetExtantDoc()) {
|
||||
NS_WARNING("Trying to call post message from an invalid dom object.");
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoPtr<ServiceWorkerClientInfo> clientInfo(
|
||||
new ServiceWorkerClientInfo(mDocument, mWindow));
|
||||
WorkerPrivate* workerPrivate = GetWorkerPrivate();
|
||||
MOZ_ASSERT(workerPrivate);
|
||||
|
||||
nsAutoPtr<ServiceWorkerClientInfo> clientInfo(new ServiceWorkerClientInfo(window->GetExtantDoc()));
|
||||
|
||||
workerPrivate->PostMessageToServiceWorker(aCx, aMessage, aTransferable,
|
||||
clientInfo, aRv);
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "mozilla/dom/BindingDeclarations.h"
|
||||
#include "mozilla/dom/ServiceWorkerBinding.h" // For ServiceWorkerState.
|
||||
|
||||
class nsIDocument;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
@ -92,10 +91,6 @@ private:
|
||||
// can be released and recreated as required rather than re-implement some of
|
||||
// the SharedWorker logic.
|
||||
nsRefPtr<SharedWorker> mSharedWorker;
|
||||
// We need to keep the document and window alive for PostMessage to be able
|
||||
// to access them.
|
||||
nsCOMPtr<nsIDocument> mDocument;
|
||||
nsCOMPtr<nsPIDOMWindow> mWindow;
|
||||
};
|
||||
|
||||
} // namespace workers
|
||||
|
@ -29,8 +29,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerClient)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc,
|
||||
nsPIDOMWindow* aWindow)
|
||||
ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc)
|
||||
: mWindowId(0)
|
||||
{
|
||||
MOZ_ASSERT(aDoc);
|
||||
@ -55,7 +54,7 @@ ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc,
|
||||
NS_WARNING("Failed to get focus information.");
|
||||
}
|
||||
|
||||
nsRefPtr<nsGlobalWindow> outerWindow = static_cast<nsGlobalWindow*>(aWindow);
|
||||
nsRefPtr<nsGlobalWindow> outerWindow = static_cast<nsGlobalWindow*>(aDoc->GetWindow());
|
||||
MOZ_ASSERT(outerWindow);
|
||||
if (!outerWindow->IsTopLevelWindow()) {
|
||||
mFrameType = FrameType::Nested;
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "mozilla/dom/ClientBinding.h"
|
||||
|
||||
class nsIDocument;
|
||||
class nsPIDOMWindow;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
@ -32,7 +31,7 @@ class ServiceWorkerClientInfo final
|
||||
friend class ServiceWorkerWindowClient;
|
||||
|
||||
public:
|
||||
ServiceWorkerClientInfo(nsIDocument* aDoc, nsPIDOMWindow* aWindow);
|
||||
explicit ServiceWorkerClientInfo(nsIDocument* aDoc);
|
||||
|
||||
private:
|
||||
nsString mClientId;
|
||||
|
@ -3896,7 +3896,7 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut
|
||||
MOZ_ASSERT(aDoc);
|
||||
aRv = GetDocumentController(aDoc->GetInnerWindow(), failRunnable,
|
||||
getter_AddRefs(serviceWorker));
|
||||
clientInfo = new ServiceWorkerClientInfo(aDoc, aDoc->GetWindow());
|
||||
clientInfo = new ServiceWorkerClientInfo(aDoc);
|
||||
} else {
|
||||
nsCOMPtr<nsIChannel> internalChannel;
|
||||
aRv = aChannel->GetChannel(getter_AddRefs(internalChannel));
|
||||
@ -4276,7 +4276,7 @@ EnumControlledDocuments(nsISupports* aKey,
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
ServiceWorkerClientInfo clientInfo(document, document->GetWindow());
|
||||
ServiceWorkerClientInfo clientInfo(document);
|
||||
data->mDocuments.AppendElement(clientInfo);
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
|
@ -90,9 +90,14 @@ public:
|
||||
UniquePtr<ServiceWorkerClientInfo> clientInfo;
|
||||
|
||||
if (window) {
|
||||
nsContentUtils::DispatchChromeEvent(window->GetExtantDoc(), window->GetOuterWindow(), NS_LITERAL_STRING("DOMServiceWorkerFocusClient"), true, true);
|
||||
clientInfo.reset(new ServiceWorkerClientInfo(window->GetDocument(),
|
||||
window->GetOuterWindow()));
|
||||
nsCOMPtr<nsIDocument> doc = window->GetDocument();
|
||||
if (doc) {
|
||||
nsContentUtils::DispatchChromeEvent(doc,
|
||||
window->GetOuterWindow(),
|
||||
NS_LITERAL_STRING("DOMServiceWorkerFocusClient"),
|
||||
true, true);
|
||||
clientInfo.reset(new ServiceWorkerClientInfo(doc));
|
||||
}
|
||||
}
|
||||
|
||||
DispatchResult(Move(clientInfo));
|
||||
|
@ -223,7 +223,12 @@ IMETextTxn::SetIMESelection(nsEditor& aEditor,
|
||||
static_cast<uint32_t>(caretOffset) <= maxOffset);
|
||||
rv = selection->Collapse(aTextNode, caretOffset);
|
||||
setCaret = setCaret || NS_SUCCEEDED(rv);
|
||||
NS_ASSERTION(setCaret, "Failed to collapse normal selection");
|
||||
if (NS_WARN_IF(!setCaret)) {
|
||||
continue;
|
||||
}
|
||||
// If caret range is specified explicitly, we should show the caret if
|
||||
// it should be so.
|
||||
aEditor.HideCaret(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -292,6 +297,8 @@ IMETextTxn::SetIMESelection(nsEditor& aEditor,
|
||||
rv = selection->Collapse(aTextNode, caretOffset);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv),
|
||||
"Failed to set caret at the end of composition string");
|
||||
// If caret range isn't specified explicitly, we should hide the caret.
|
||||
aEditor.HideCaret(true);
|
||||
}
|
||||
|
||||
rv = selection->EndBatchChanges();
|
||||
|
@ -147,6 +147,7 @@ nsEditor::nsEditor()
|
||||
, mDidPostCreate(false)
|
||||
, mDispatchInputEvent(true)
|
||||
, mIsInEditAction(false)
|
||||
, mHidingCaret(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -158,6 +159,8 @@ nsEditor::~nsEditor()
|
||||
mComposition->OnEditorDestroyed();
|
||||
mComposition = nullptr;
|
||||
}
|
||||
// If this editor is still hiding the caret, we need to restore it.
|
||||
HideCaret(false);
|
||||
mTxnMgr = nullptr;
|
||||
|
||||
delete mPhonetic;
|
||||
@ -464,6 +467,8 @@ nsEditor::PreDestroy(bool aDestroyingFrames)
|
||||
|
||||
// Unregister event listeners
|
||||
RemoveEventListeners();
|
||||
// If this editor is still hiding the caret, we need to restore it.
|
||||
HideCaret(false);
|
||||
mActionListeners.Clear();
|
||||
mEditorObservers.Clear();
|
||||
mDocStateListeners.Clear();
|
||||
@ -2065,6 +2070,10 @@ nsEditor::EndIMEComposition()
|
||||
}
|
||||
}
|
||||
|
||||
// Composition string may have hidden the caret. Therefore, we need to
|
||||
// cancel it here.
|
||||
HideCaret(false);
|
||||
|
||||
/* reset the data we need to construct a transaction */
|
||||
mIMETextNode = nullptr;
|
||||
mIMETextOffset = 0;
|
||||
@ -5258,3 +5267,23 @@ nsEditor::GetIMESelectionStartOffsetIn(nsINode* aTextNode)
|
||||
}
|
||||
return minOffset < INT32_MAX ? minOffset : -1;
|
||||
}
|
||||
|
||||
void
|
||||
nsEditor::HideCaret(bool aHide)
|
||||
{
|
||||
if (mHidingCaret == aHide) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPresShell> presShell = GetPresShell();
|
||||
NS_ENSURE_TRUE_VOID(presShell);
|
||||
nsRefPtr<nsCaret> caret = presShell->GetCaret();
|
||||
NS_ENSURE_TRUE_VOID(caret);
|
||||
|
||||
mHidingCaret = aHide;
|
||||
if (aHide) {
|
||||
caret->AddForceHide();
|
||||
} else {
|
||||
caret->RemoveForceHide();
|
||||
}
|
||||
}
|
||||
|
@ -824,6 +824,13 @@ public:
|
||||
void FindBetterInsertionPoint(nsCOMPtr<nsINode>& aNode,
|
||||
int32_t& aOffset);
|
||||
|
||||
/**
|
||||
* HideCaret() hides caret with nsCaret::AddForceHide() or may show carent
|
||||
* with nsCaret::RemoveForceHide(). This does NOT set visibility of
|
||||
* nsCaret. Therefore, this is stateless.
|
||||
*/
|
||||
void HideCaret(bool aHide);
|
||||
|
||||
protected:
|
||||
enum Tristate {
|
||||
eTriUnset,
|
||||
@ -883,6 +890,7 @@ protected:
|
||||
bool mDidPostCreate; // whether PostCreate has been called
|
||||
bool mDispatchInputEvent;
|
||||
bool mIsInEditAction; // true while the instance is handling an edit action
|
||||
bool mHidingCaret; // whether caret is hidden forcibly.
|
||||
|
||||
friend bool NSCanUnload(nsISupports* serviceMgr);
|
||||
friend class nsAutoTxnsConserveSelection;
|
||||
|
@ -716,11 +716,14 @@ APZCTreeManager::ProcessTouchInput(MultiTouchInput& aInput,
|
||||
uint64_t* aOutInputBlockId)
|
||||
{
|
||||
if (aInput.mType == MultiTouchInput::MULTITOUCH_START) {
|
||||
// If we are in an overscrolled state and a second finger goes down,
|
||||
// If we are panned into overscroll and a second finger goes down,
|
||||
// ignore that second touch point completely. The touch-start for it is
|
||||
// dropped completely; subsequent touch events until the touch-end for it
|
||||
// will have this touch point filtered out.
|
||||
if (mApzcForInputBlock && BuildOverscrollHandoffChain(mApzcForInputBlock)->HasOverscrolledApzc()) {
|
||||
// (By contrast, if we're in overscroll but not panning, such as after
|
||||
// putting two fingers down during an overscroll animation, we process the
|
||||
// second touch and proceed to pinch.)
|
||||
if (mApzcForInputBlock && BuildOverscrollHandoffChain(mApzcForInputBlock)->HasApzcPannedIntoOverscroll()) {
|
||||
if (mRetainedTouchIdentifier == -1) {
|
||||
mRetainedTouchIdentifier = mApzcForInputBlock->GetLastTouchIdentifier();
|
||||
}
|
||||
|
@ -1042,6 +1042,10 @@ public:
|
||||
return mX.IsOverscrolled() || mY.IsOverscrolled();
|
||||
}
|
||||
|
||||
bool IsPannedIntoOverscroll() const {
|
||||
return IsOverscrolled() && IsInPanningState();
|
||||
}
|
||||
|
||||
private:
|
||||
/* This is the cumulative CSS transform for all the layers from (and including)
|
||||
* the parent APZC down to (but excluding) this one. */
|
||||
|
@ -162,9 +162,9 @@ OverscrollHandoffChain::CanScrollInDirection(const AsyncPanZoomController* aApzc
|
||||
}
|
||||
|
||||
bool
|
||||
OverscrollHandoffChain::HasOverscrolledApzc() const
|
||||
OverscrollHandoffChain::HasApzcPannedIntoOverscroll() const
|
||||
{
|
||||
return AnyApzc(&AsyncPanZoomController::IsOverscrolled);
|
||||
return AnyApzc(&AsyncPanZoomController::IsPannedIntoOverscroll);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -80,8 +80,8 @@ public:
|
||||
bool CanScrollInDirection(const AsyncPanZoomController* aApzc,
|
||||
Layer::ScrollDirection aDirection) const;
|
||||
|
||||
// Determine whether any APZC along this handoff chain is overscrolled.
|
||||
bool HasOverscrolledApzc() const;
|
||||
// Determine whether any APZC along this handoff chain is panned into overscroll.
|
||||
bool HasApzcPannedIntoOverscroll() const;
|
||||
|
||||
// Determine whether any APZC along this handoff chain has been flung fast.
|
||||
bool HasFastFlungApzc() const;
|
||||
|
@ -10987,6 +10987,11 @@ GenerateEntry(ModuleCompiler& m, unsigned exportIndex)
|
||||
case ABIArg::GPR:
|
||||
masm.load32(src, iter->gpr());
|
||||
break;
|
||||
#ifdef JS_CODEGEN_REGISTER_PAIR
|
||||
case ABIArg::GPR_PAIR:
|
||||
MOZ_CRASH("AsmJS uses hardfp for function calls.");
|
||||
break;
|
||||
#endif
|
||||
case ABIArg::FPU: {
|
||||
static_assert(sizeof(AsmJSModule::EntryArg) >= jit::Simd128DataSize,
|
||||
"EntryArg must be big enough to store SIMD values");
|
||||
@ -11099,6 +11104,11 @@ FillArgumentArray(ModuleCompiler& m, const VarTypeVector& argTypes,
|
||||
case ABIArg::GPR:
|
||||
masm.storeValue(JSVAL_TYPE_INT32, i->gpr(), dstAddr);
|
||||
break;
|
||||
#ifdef JS_CODEGEN_REGISTER_PAIR
|
||||
case ABIArg::GPR_PAIR:
|
||||
MOZ_CRASH("AsmJS uses hardfp for function calls.");
|
||||
break;
|
||||
#endif
|
||||
case ABIArg::FPU:
|
||||
masm.canonicalizeDouble(i->fpu());
|
||||
masm.storeDouble(i->fpu(), dstAddr);
|
||||
|
@ -346,6 +346,7 @@ function isOverridableField(initialCSU, csu, field)
|
||||
|
||||
function listGCTypes() {
|
||||
return [
|
||||
'js::gc::Cell',
|
||||
'JSObject',
|
||||
'JSString',
|
||||
'JSFatInlineString',
|
||||
|
@ -402,7 +402,7 @@ NativeRegExpMacroAssembler::GenerateCode(JSContext* cx, bool match_only)
|
||||
volatileRegs.takeUnchecked(temp1);
|
||||
masm.PushRegsInMask(volatileRegs);
|
||||
|
||||
masm.setupUnalignedABICall(1, temp0);
|
||||
masm.setupUnalignedABICall(temp0);
|
||||
masm.passABIArg(temp1);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, GrowBacktrackStack));
|
||||
masm.storeCallResult(temp0);
|
||||
@ -814,7 +814,7 @@ NativeRegExpMacroAssembler::CheckNotBackReferenceIgnoreCase(int start_reg, Label
|
||||
// Address byte_offset1 - Address captured substring's start.
|
||||
// Address byte_offset2 - Address of current character position.
|
||||
// size_t byte_length - length of capture in bytes(!)
|
||||
masm.setupUnalignedABICall(3, temp0);
|
||||
masm.setupUnalignedABICall(temp0);
|
||||
masm.passABIArg(current_character);
|
||||
masm.passABIArg(current_position);
|
||||
masm.passABIArg(temp1);
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
#include "vm/Interpreter-inl.h"
|
||||
#include "vm/NativeObject-inl.h"
|
||||
|
||||
@ -491,7 +492,7 @@ BaselineCompiler::emitOutOfLinePostBarrierSlot()
|
||||
#endif
|
||||
masm.pushValue(R0);
|
||||
|
||||
masm.setupUnalignedABICall(2, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.movePtr(ImmPtr(cx->runtime()), scratch);
|
||||
masm.passABIArg(scratch);
|
||||
masm.passABIArg(objReg);
|
||||
@ -586,7 +587,7 @@ BaselineCompiler::emitIsDebuggeeCheck()
|
||||
{
|
||||
if (compileDebugInstrumentation_) {
|
||||
masm.Push(BaselineFrameReg);
|
||||
masm.setupUnalignedABICall(1, R0.scratchReg());
|
||||
masm.setupUnalignedABICall(R0.scratchReg());
|
||||
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
|
||||
masm.passABIArg(R0.scratchReg());
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::FrameIsDebuggeeCheck));
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "jit/PerfSpewer.h"
|
||||
|
||||
#include "jit/JitFrames-inl.h"
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
#include "vm/Stack-inl.h"
|
||||
|
||||
using namespace js;
|
||||
@ -1079,7 +1080,7 @@ EmitBaselineDebugModeOSRHandlerTail(MacroAssembler& masm, Register temp, bool re
|
||||
masm.push(Address(temp, offsetof(BaselineDebugModeOSRInfo, resumeAddr)));
|
||||
|
||||
// Call a stub to free the allocated info.
|
||||
masm.setupUnalignedABICall(1, temp);
|
||||
masm.setupUnalignedABICall(temp);
|
||||
masm.loadBaselineFramePtr(BaselineFrameReg, temp);
|
||||
masm.passABIArg(temp);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, FinishBaselineDebugModeOSR));
|
||||
@ -1131,7 +1132,7 @@ JitRuntime::generateBaselineDebugModeOSRHandler(JSContext* cx, uint32_t* noFrame
|
||||
masm.push(BaselineFrameReg);
|
||||
|
||||
// Call a stub to fully initialize the info.
|
||||
masm.setupUnalignedABICall(3, temp);
|
||||
masm.setupUnalignedABICall(temp);
|
||||
masm.loadBaselineFramePtr(BaselineFrameReg, temp);
|
||||
masm.passABIArg(temp);
|
||||
masm.passABIArg(syncedStackStart);
|
||||
|
@ -1812,7 +1812,7 @@ ICToBool_Object::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
EmitReturnFromIC(masm);
|
||||
|
||||
masm.bind(&slowPath);
|
||||
masm.setupUnalignedABICall(1, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.passABIArg(objReg);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::EmulatesUndefined));
|
||||
masm.convertBoolToInt32(ReturnReg, ReturnReg);
|
||||
@ -2265,7 +2265,7 @@ ICBinaryArith_Double::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
masm.divDouble(FloatReg1, FloatReg0);
|
||||
break;
|
||||
case JSOP_MOD:
|
||||
masm.setupUnalignedABICall(2, R0.scratchReg());
|
||||
masm.setupUnalignedABICall(R0.scratchReg());
|
||||
masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
|
||||
masm.passABIArg(FloatReg1, MoveOp::DOUBLE);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, NumberMod), MoveOp::DOUBLE);
|
||||
@ -2393,7 +2393,7 @@ ICBinaryArith_DoubleWithInt32::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
|
||||
masm.bind(&truncateABICall);
|
||||
masm.push(intReg);
|
||||
masm.setupUnalignedABICall(1, scratchReg);
|
||||
masm.setupUnalignedABICall(scratchReg);
|
||||
masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
|
||||
masm.callWithABI(mozilla::BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32));
|
||||
masm.storeCallResult(scratchReg);
|
||||
@ -2545,7 +2545,7 @@ ICUnaryArith_Double::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
masm.jump(&doneTruncate);
|
||||
|
||||
masm.bind(&truncateABICall);
|
||||
masm.setupUnalignedABICall(1, scratchReg);
|
||||
masm.setupUnalignedABICall(scratchReg);
|
||||
masm.passABIArg(FloatReg0, MoveOp::DOUBLE);
|
||||
masm.callWithABI(BitwiseCast<void*, int32_t(*)(double)>(JS::ToInt32));
|
||||
masm.storeCallResult(scratchReg);
|
||||
@ -11027,7 +11027,7 @@ ICCall_Native::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
masm.enterFakeExitFrame(NativeExitFrameLayout::Token());
|
||||
|
||||
// Execute call.
|
||||
masm.setupUnalignedABICall(3, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.loadJSContext(scratch);
|
||||
masm.passABIArg(scratch);
|
||||
masm.passABIArg(argcReg);
|
||||
@ -11125,7 +11125,7 @@ ICCall_ClassHook::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
masm.enterFakeExitFrame(NativeExitFrameLayout::Token());
|
||||
|
||||
// Execute call.
|
||||
masm.setupUnalignedABICall(3, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.loadJSContext(scratch);
|
||||
masm.passABIArg(scratch);
|
||||
masm.passABIArg(argcReg);
|
||||
@ -11528,7 +11528,7 @@ ICTableSwitch::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
masm.pushValue(R0);
|
||||
masm.moveStackPtrTo(R0.scratchReg());
|
||||
|
||||
masm.setupUnalignedABICall(1, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.passABIArg(R0.scratchReg());
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, DoubleValueToInt32ForSwitch));
|
||||
|
||||
|
@ -383,7 +383,7 @@ CodeGenerator::emitOOLTestObject(Register objreg,
|
||||
Register scratch)
|
||||
{
|
||||
saveVolatile(scratch);
|
||||
masm.setupUnalignedABICall(1, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.passABIArg(objreg);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::EmulatesUndefined));
|
||||
masm.storeCallResult(scratch);
|
||||
@ -1147,7 +1147,7 @@ PrepareAndExecuteRegExp(JSContext* cx, MacroAssembler& masm, Register regexp, Re
|
||||
// Execute the RegExp.
|
||||
masm.computeEffectiveAddress(Address(masm.getStackPointer(), inputOutputDataStartOffset), temp2);
|
||||
masm.PushRegsInMask(volatileRegs);
|
||||
masm.setupUnalignedABICall(1, temp3);
|
||||
masm.setupUnalignedABICall(temp3);
|
||||
masm.passABIArg(temp2);
|
||||
masm.callWithABI(codePointer);
|
||||
masm.PopRegsInMask(volatileRegs);
|
||||
@ -2721,7 +2721,7 @@ CodeGenerator::visitOutOfLineCallPostWriteBarrier(OutOfLineCallPostWriteBarrier*
|
||||
masm.mov(ImmPtr(GetJitContext()->runtime), runtimereg);
|
||||
|
||||
void (*fun)(JSRuntime*, JSObject*) = isGlobal ? PostGlobalWriteBarrier : PostWriteBarrier;
|
||||
masm.setupUnalignedABICall(2, regs.takeAny());
|
||||
masm.setupUnalignedABICall(regs.takeAny());
|
||||
masm.passABIArg(runtimereg);
|
||||
masm.passABIArg(objreg);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, fun));
|
||||
@ -2823,7 +2823,7 @@ CodeGenerator::visitCallNative(LCallNative* call)
|
||||
markSafepointAt(safepointOffset, call);
|
||||
|
||||
// Construct and execute call.
|
||||
masm.setupUnalignedABICall(3, tempReg);
|
||||
masm.setupUnalignedABICall(tempReg);
|
||||
masm.passABIArg(argContextReg);
|
||||
masm.passABIArg(argUintNReg);
|
||||
masm.passABIArg(argVpReg);
|
||||
@ -2942,7 +2942,7 @@ CodeGenerator::visitCallDOMNative(LCallDOMNative* call)
|
||||
markSafepointAt(safepointOffset, call);
|
||||
|
||||
// Construct and execute call.
|
||||
masm.setupUnalignedABICall(4, argJSContext);
|
||||
masm.setupUnalignedABICall(argJSContext);
|
||||
|
||||
masm.loadJSContext(argJSContext);
|
||||
|
||||
@ -3483,7 +3483,7 @@ CodeGenerator::visitGetDynamicName(LGetDynamicName* lir)
|
||||
masm.adjustStack(-int32_t(sizeof(Value)));
|
||||
masm.moveStackPtrTo(temp2);
|
||||
|
||||
masm.setupUnalignedABICall(4, temp1);
|
||||
masm.setupUnalignedABICall(temp1);
|
||||
masm.passABIArg(temp3);
|
||||
masm.passABIArg(scopeChain);
|
||||
masm.passABIArg(name);
|
||||
@ -3506,7 +3506,7 @@ CodeGenerator::emitFilterArgumentsOrEval(LInstruction* lir, Register string,
|
||||
{
|
||||
masm.loadJSContext(temp2);
|
||||
|
||||
masm.setupUnalignedABICall(2, temp1);
|
||||
masm.setupUnalignedABICall(temp1);
|
||||
masm.passABIArg(temp2);
|
||||
masm.passABIArg(string);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, FilterArgumentsOrEval));
|
||||
@ -3883,7 +3883,7 @@ CodeGenerator::emitAssertObjectOrStringResult(Register input, MIRType type, cons
|
||||
|
||||
// Check that we have a valid GC pointer.
|
||||
saveVolatile();
|
||||
masm.setupUnalignedABICall(2, temp);
|
||||
masm.setupUnalignedABICall(temp);
|
||||
masm.loadJSContext(temp);
|
||||
masm.passABIArg(temp);
|
||||
masm.passABIArg(input);
|
||||
@ -3956,7 +3956,7 @@ CodeGenerator::emitAssertResultV(const ValueOperand input, const TemporaryTypeSe
|
||||
masm.pushValue(input);
|
||||
masm.moveStackPtrTo(temp1);
|
||||
|
||||
masm.setupUnalignedABICall(2, temp2);
|
||||
masm.setupUnalignedABICall(temp2);
|
||||
masm.loadJSContext(temp2);
|
||||
masm.passABIArg(temp2);
|
||||
masm.passABIArg(temp1);
|
||||
@ -4218,7 +4218,7 @@ CodeGenerator::visitAtan2D(LAtan2D* lir)
|
||||
FloatRegister y = ToFloatRegister(lir->y());
|
||||
FloatRegister x = ToFloatRegister(lir->x());
|
||||
|
||||
masm.setupUnalignedABICall(2, temp);
|
||||
masm.setupUnalignedABICall(temp);
|
||||
masm.passABIArg(y, MoveOp::DOUBLE);
|
||||
masm.passABIArg(x, MoveOp::DOUBLE);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ecmaAtan2), MoveOp::DOUBLE);
|
||||
@ -4231,7 +4231,7 @@ CodeGenerator::visitHypot(LHypot* lir)
|
||||
{
|
||||
Register temp = ToRegister(lir->temp());
|
||||
uint32_t numArgs = lir->numArgs();
|
||||
masm.setupUnalignedABICall(numArgs, temp);
|
||||
masm.setupUnalignedABICall(temp);
|
||||
|
||||
for (uint32_t i = 0 ; i < numArgs; ++i)
|
||||
masm.passABIArg(ToFloatRegister(lir->getOperand(i)), MoveOp::DOUBLE);
|
||||
@ -5100,7 +5100,7 @@ CodeGenerator::visitSetDisjointTypedElements(LSetDisjointTypedElements* lir)
|
||||
|
||||
Register temp = ToRegister(lir->temp());
|
||||
|
||||
masm.setupUnalignedABICall(3, temp);
|
||||
masm.setupUnalignedABICall(temp);
|
||||
masm.passABIArg(target);
|
||||
masm.passABIArg(targetOffset);
|
||||
masm.passABIArg(source);
|
||||
@ -5231,10 +5231,7 @@ CodeGenerator::visitPowI(LPowI* ins)
|
||||
|
||||
MOZ_ASSERT(power != temp);
|
||||
|
||||
// In all implementations, setupUnalignedABICall() relinquishes use of
|
||||
// its scratch register. We can therefore save an input register by
|
||||
// reusing the scratch register to pass constants to callWithABI.
|
||||
masm.setupUnalignedABICall(2, temp);
|
||||
masm.setupUnalignedABICall(temp);
|
||||
masm.passABIArg(value, MoveOp::DOUBLE);
|
||||
masm.passABIArg(power);
|
||||
|
||||
@ -5249,7 +5246,7 @@ CodeGenerator::visitPowD(LPowD* ins)
|
||||
FloatRegister power = ToFloatRegister(ins->power());
|
||||
Register temp = ToRegister(ins->temp());
|
||||
|
||||
masm.setupUnalignedABICall(2, temp);
|
||||
masm.setupUnalignedABICall(temp);
|
||||
masm.passABIArg(value, MoveOp::DOUBLE);
|
||||
masm.passABIArg(power, MoveOp::DOUBLE);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ecmaPow), MoveOp::DOUBLE);
|
||||
@ -5264,9 +5261,9 @@ CodeGenerator::visitMathFunctionD(LMathFunctionD* ins)
|
||||
FloatRegister input = ToFloatRegister(ins->input());
|
||||
MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
|
||||
|
||||
const MathCache* mathCache = ins->mir()->cache();
|
||||
masm.setupUnalignedABICall(temp);
|
||||
|
||||
masm.setupUnalignedABICall(mathCache ? 2 : 1, temp);
|
||||
const MathCache* mathCache = ins->mir()->cache();
|
||||
if (mathCache) {
|
||||
masm.movePtr(ImmPtr(mathCache), temp);
|
||||
masm.passABIArg(temp);
|
||||
@ -5365,7 +5362,7 @@ CodeGenerator::visitMathFunctionF(LMathFunctionF* ins)
|
||||
FloatRegister input = ToFloatRegister(ins->input());
|
||||
MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnFloat32Reg);
|
||||
|
||||
masm.setupUnalignedABICall(1, temp);
|
||||
masm.setupUnalignedABICall(temp);
|
||||
masm.passABIArg(input, MoveOp::FLOAT32);
|
||||
|
||||
void* funptr = nullptr;
|
||||
@ -5389,7 +5386,7 @@ CodeGenerator::visitModD(LModD* ins)
|
||||
|
||||
MOZ_ASSERT(ToFloatRegister(ins->output()) == ReturnDoubleReg);
|
||||
|
||||
masm.setupUnalignedABICall(2, temp);
|
||||
masm.setupUnalignedABICall(temp);
|
||||
masm.passABIArg(lhs, MoveOp::DOUBLE);
|
||||
masm.passABIArg(rhs, MoveOp::DOUBLE);
|
||||
|
||||
@ -6217,7 +6214,7 @@ JitRuntime::generateMallocStub(JSContext* cx)
|
||||
const Register regRuntime = regTemp;
|
||||
MOZ_ASSERT(regTemp != regNBytes);
|
||||
|
||||
masm.setupUnalignedABICall(2, regTemp);
|
||||
masm.setupUnalignedABICall(regTemp);
|
||||
masm.movePtr(ImmPtr(cx->runtime()), regRuntime);
|
||||
masm.passABIArg(regRuntime);
|
||||
masm.passABIArg(regNBytes);
|
||||
@ -6255,7 +6252,7 @@ JitRuntime::generateFreeStub(JSContext* cx)
|
||||
const Register regTemp = regs.takeAnyGeneral();
|
||||
MOZ_ASSERT(regTemp != regSlots);
|
||||
|
||||
masm.setupUnalignedABICall(1, regTemp);
|
||||
masm.setupUnalignedABICall(regTemp);
|
||||
masm.passABIArg(regSlots);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js_free));
|
||||
|
||||
@ -6296,7 +6293,7 @@ JitRuntime::generateLazyLinkStub(JSContext* cx)
|
||||
masm.enterFakeExitFrame(LazyLinkExitFrameLayout::Token());
|
||||
masm.PushStubCode();
|
||||
|
||||
masm.setupUnalignedABICall(1, temp0);
|
||||
masm.setupUnalignedABICall(temp0);
|
||||
masm.loadJSContext(temp0);
|
||||
masm.passABIArg(temp0);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, LazyLinkTopActivation));
|
||||
@ -7094,7 +7091,7 @@ CodeGenerator::emitArrayPopShift(LInstruction* lir, const MArrayPopShift* mir, R
|
||||
temps.add(lengthTemp);
|
||||
|
||||
saveVolatile(temps);
|
||||
masm.setupUnalignedABICall(1, lengthTemp);
|
||||
masm.setupUnalignedABICall(lengthTemp);
|
||||
masm.passABIArg(obj);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, js::ArrayShiftMoveElements));
|
||||
restoreVolatile(temps);
|
||||
@ -8848,7 +8845,7 @@ CodeGenerator::visitOutOfLineTypeOfV(OutOfLineTypeOfV* ool)
|
||||
Register obj = masm.extractObject(input, temp);
|
||||
|
||||
saveVolatile(output);
|
||||
masm.setupUnalignedABICall(2, output);
|
||||
masm.setupUnalignedABICall(output);
|
||||
masm.passABIArg(obj);
|
||||
masm.movePtr(ImmPtr(GetJitContext()->runtime), output);
|
||||
masm.passABIArg(output);
|
||||
@ -9667,7 +9664,7 @@ CodeGenerator::visitGetDOMProperty(LGetDOMProperty* ins)
|
||||
|
||||
markSafepointAt(safepointOffset, ins);
|
||||
|
||||
masm.setupUnalignedABICall(4, JSContextReg);
|
||||
masm.setupUnalignedABICall(JSContextReg);
|
||||
|
||||
masm.loadJSContext(JSContextReg);
|
||||
|
||||
@ -9757,7 +9754,7 @@ CodeGenerator::visitSetDOMProperty(LSetDOMProperty* ins)
|
||||
|
||||
markSafepointAt(safepointOffset, ins);
|
||||
|
||||
masm.setupUnalignedABICall(4, JSContextReg);
|
||||
masm.setupUnalignedABICall(JSContextReg);
|
||||
|
||||
masm.loadJSContext(JSContextReg);
|
||||
|
||||
@ -9825,7 +9822,7 @@ CodeGenerator::visitOutOfLineIsCallable(OutOfLineIsCallable* ool)
|
||||
Register output = ToRegister(ins->output());
|
||||
|
||||
saveVolatile(output);
|
||||
masm.setupUnalignedABICall(1, output);
|
||||
masm.setupUnalignedABICall(output);
|
||||
masm.passABIArg(object);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, ObjectIsCallable));
|
||||
masm.storeCallResult(output);
|
||||
@ -10192,7 +10189,7 @@ CodeGenerator::visitDebugger(LDebugger* ins)
|
||||
Register temp = ToRegister(ins->getTemp(1));
|
||||
|
||||
masm.loadJSContext(cx);
|
||||
masm.setupUnalignedABICall(1, temp);
|
||||
masm.setupUnalignedABICall(temp);
|
||||
masm.passABIArg(cx);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, GlobalHasLiveOnDebuggerStatement));
|
||||
|
||||
|
@ -948,7 +948,7 @@ EmitGetterCall(JSContext* cx, MacroAssembler& masm,
|
||||
masm.enterFakeExitFrame(IonOOLNativeExitFrameLayout::Token());
|
||||
|
||||
// Construct and execute call.
|
||||
masm.setupUnalignedABICall(3, scratchReg);
|
||||
masm.setupUnalignedABICall(scratchReg);
|
||||
masm.passABIArg(argJSContextReg);
|
||||
masm.passABIArg(argUintNReg);
|
||||
masm.passABIArg(argVpReg);
|
||||
@ -1006,7 +1006,7 @@ EmitGetterCall(JSContext* cx, MacroAssembler& masm,
|
||||
masm.enterFakeExitFrame(IonOOLPropertyOpExitFrameLayout::Token());
|
||||
|
||||
// Make the call.
|
||||
masm.setupUnalignedABICall(4, scratchReg);
|
||||
masm.setupUnalignedABICall(scratchReg);
|
||||
masm.passABIArg(argJSContextReg);
|
||||
masm.passABIArg(argObjReg);
|
||||
masm.passABIArg(argIdReg);
|
||||
@ -1586,7 +1586,7 @@ EmitCallProxyGet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& at
|
||||
masm.enterFakeExitFrame(IonOOLProxyExitFrameLayout::Token());
|
||||
|
||||
// Make the call.
|
||||
masm.setupUnalignedABICall(5, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.passABIArg(argJSContextReg);
|
||||
masm.passABIArg(argProxyReg);
|
||||
masm.passABIArg(argProxyReg);
|
||||
@ -2222,7 +2222,7 @@ EmitObjectOpResultCheck(MacroAssembler& masm, Label* failure, bool strict,
|
||||
masm.computeEffectiveAddress(
|
||||
Address(masm.getStackPointer(), FrameLayout::offsetOfObjectOpResult()),
|
||||
argResultReg);
|
||||
masm.setupUnalignedABICall(5, scratchReg);
|
||||
masm.setupUnalignedABICall(scratchReg);
|
||||
masm.passABIArg(argJSContextReg);
|
||||
masm.passABIArg(argObjReg);
|
||||
masm.passABIArg(argIdReg);
|
||||
@ -2297,7 +2297,7 @@ EmitCallProxySet(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& at
|
||||
masm.enterFakeExitFrame(IonOOLProxyExitFrameLayout::Token());
|
||||
|
||||
// Make the call.
|
||||
masm.setupUnalignedABICall(5, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.passABIArg(argJSContextReg);
|
||||
masm.passABIArg(argProxyReg);
|
||||
masm.passABIArg(argIdReg);
|
||||
@ -2506,7 +2506,7 @@ GenerateCallSetter(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
||||
masm.enterFakeExitFrame(IonOOLNativeExitFrameLayout::Token());
|
||||
|
||||
// Make the call
|
||||
masm.setupUnalignedABICall(3, scratchReg);
|
||||
masm.setupUnalignedABICall(scratchReg);
|
||||
masm.passABIArg(argJSContextReg);
|
||||
masm.passABIArg(argUintNReg);
|
||||
masm.passABIArg(argVpReg);
|
||||
@ -2570,7 +2570,7 @@ GenerateCallSetter(JSContext* cx, IonScript* ion, MacroAssembler& masm,
|
||||
masm.enterFakeExitFrame(IonOOLSetterOpExitFrameLayout::Token());
|
||||
|
||||
// Make the call.
|
||||
masm.setupUnalignedABICall(5, scratchReg);
|
||||
masm.setupUnalignedABICall(scratchReg);
|
||||
masm.passABIArg(argJSContextReg);
|
||||
masm.passABIArg(argObjReg);
|
||||
masm.passABIArg(argIdReg);
|
||||
@ -2815,7 +2815,7 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att
|
||||
masm.loadPtr(Address(object, UnboxedPlainObject::offsetOfExpando()), object);
|
||||
}
|
||||
|
||||
masm.setupUnalignedABICall(3, temp1);
|
||||
masm.setupUnalignedABICall(temp1);
|
||||
masm.loadJSContext(temp1);
|
||||
masm.passABIArg(temp1);
|
||||
masm.passABIArg(object);
|
||||
@ -3463,7 +3463,7 @@ GetElementIC::attachGetProp(JSContext* cx, HandleScript outerScript, IonScript*
|
||||
if (!volatileRegs.has(objReg))
|
||||
masm.push(objReg);
|
||||
|
||||
masm.setupUnalignedABICall(2, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.movePtr(ImmGCPtr(name), objReg);
|
||||
masm.passABIArg(objReg);
|
||||
masm.unboxString(val, scratch);
|
||||
@ -3820,7 +3820,7 @@ GenerateGetTypedOrUnboxedArrayElement(JSContext* cx, MacroAssembler& masm,
|
||||
|
||||
Register temp = regs.takeAnyGeneral();
|
||||
|
||||
masm.setupUnalignedABICall(1, temp);
|
||||
masm.setupUnalignedABICall(temp);
|
||||
masm.passABIArg(str);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, GetIndexFromString));
|
||||
masm.mov(ReturnReg, indexReg);
|
||||
|
@ -76,6 +76,82 @@ MacroAssembler::call(const CallSiteDesc& desc, Label* label)
|
||||
append(desc, currentOffset(), framePushed());
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// ABI function calls.
|
||||
|
||||
void
|
||||
MacroAssembler::passABIArg(Register reg)
|
||||
{
|
||||
passABIArg(MoveOperand(reg), MoveOp::GENERAL);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::passABIArg(FloatRegister reg, MoveOp::Type type)
|
||||
{
|
||||
passABIArg(MoveOperand(reg), type);
|
||||
}
|
||||
|
||||
template <typename T> void
|
||||
MacroAssembler::callWithABI(const T& fun, MoveOp::Type result)
|
||||
{
|
||||
profilerPreCall();
|
||||
callWithABINoProfiler(fun, result);
|
||||
profilerPostReturn();
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::appendSignatureType(MoveOp::Type type)
|
||||
{
|
||||
#ifdef JS_SIMULATOR
|
||||
signature_ <<= ArgType_Shift;
|
||||
switch (type) {
|
||||
case MoveOp::GENERAL: signature_ |= ArgType_General; break;
|
||||
case MoveOp::DOUBLE: signature_ |= ArgType_Double; break;
|
||||
case MoveOp::FLOAT32: signature_ |= ArgType_Float32; break;
|
||||
default: MOZ_CRASH("Invalid argument type");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ABIFunctionType
|
||||
MacroAssembler::signature() const
|
||||
{
|
||||
#ifdef JS_SIMULATOR
|
||||
#ifdef DEBUG
|
||||
switch (signature_) {
|
||||
case Args_General0:
|
||||
case Args_General1:
|
||||
case Args_General2:
|
||||
case Args_General3:
|
||||
case Args_General4:
|
||||
case Args_General5:
|
||||
case Args_General6:
|
||||
case Args_General7:
|
||||
case Args_General8:
|
||||
case Args_Double_None:
|
||||
case Args_Int_Double:
|
||||
case Args_Float32_Float32:
|
||||
case Args_Double_Double:
|
||||
case Args_Double_Int:
|
||||
case Args_Double_DoubleInt:
|
||||
case Args_Double_DoubleDouble:
|
||||
case Args_Double_IntDouble:
|
||||
case Args_Int_IntDouble:
|
||||
case Args_Double_DoubleDoubleDouble:
|
||||
case Args_Double_DoubleDoubleDoubleDouble:
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected type");
|
||||
}
|
||||
#endif // DEBUG
|
||||
|
||||
return ABIFunctionType(signature_);
|
||||
#else
|
||||
// No simulator enabled.
|
||||
MOZ_CRASH("Only available for making calls within a simulator.");
|
||||
#endif
|
||||
}
|
||||
|
||||
//}}} check_macroassembler_style
|
||||
// ===============================================================
|
||||
|
||||
|
@ -1486,7 +1486,7 @@ MacroAssembler::initGCThing(Register obj, Register temp, JSObject* templateObj,
|
||||
regs.takeUnchecked(obj);
|
||||
Register temp = regs.takeAnyGeneral();
|
||||
|
||||
setupUnalignedABICall(2, temp);
|
||||
setupUnalignedABICall(temp);
|
||||
passABIArg(obj);
|
||||
movePtr(ImmGCPtr(templateObj->type()), temp);
|
||||
passABIArg(temp);
|
||||
@ -1624,7 +1624,7 @@ MacroAssembler::generateBailoutTail(Register scratch, Register bailoutInfo)
|
||||
// Fall-through: overrecursed.
|
||||
{
|
||||
loadJSContext(ReturnReg);
|
||||
setupUnalignedABICall(1, scratch);
|
||||
setupUnalignedABICall(scratch);
|
||||
passABIArg(ReturnReg);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void*, BailoutReportOverRecursed));
|
||||
jump(exceptionLabel());
|
||||
@ -1688,7 +1688,7 @@ MacroAssembler::generateBailoutTail(Register scratch, Register bailoutInfo)
|
||||
push(Address(bailoutInfo, offsetof(BaselineBailoutInfo, monitorStub)));
|
||||
|
||||
// Call a stub to free allocated memory and create arguments objects.
|
||||
setupUnalignedABICall(1, temp);
|
||||
setupUnalignedABICall(temp);
|
||||
passABIArg(bailoutInfo);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void*, FinishBailoutToBaseline));
|
||||
branchTest32(Zero, ReturnReg, ReturnReg, exceptionLabel());
|
||||
@ -1726,7 +1726,7 @@ MacroAssembler::generateBailoutTail(Register scratch, Register bailoutInfo)
|
||||
push(Address(bailoutInfo, offsetof(BaselineBailoutInfo, resumeAddr)));
|
||||
|
||||
// Call a stub to free allocated memory and create arguments objects.
|
||||
setupUnalignedABICall(1, temp);
|
||||
setupUnalignedABICall(temp);
|
||||
passABIArg(bailoutInfo);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void*, FinishBailoutToBaseline));
|
||||
branchTest32(Zero, ReturnReg, ReturnReg, exceptionLabel());
|
||||
@ -1801,7 +1801,7 @@ MacroAssembler::assumeUnreachable(const char* output)
|
||||
PushRegsInMask(save);
|
||||
Register temp = regs.takeAnyGeneral();
|
||||
|
||||
setupUnalignedABICall(1, temp);
|
||||
setupUnalignedABICall(temp);
|
||||
movePtr(ImmPtr(output), temp);
|
||||
passABIArg(temp);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void*, AssumeUnreachable_));
|
||||
@ -1844,7 +1844,7 @@ MacroAssembler::printf(const char* output)
|
||||
|
||||
Register temp = regs.takeAnyGeneral();
|
||||
|
||||
setupUnalignedABICall(1, temp);
|
||||
setupUnalignedABICall(temp);
|
||||
movePtr(ImmPtr(output), temp);
|
||||
passABIArg(temp);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void*, Printf0_));
|
||||
@ -1870,7 +1870,7 @@ MacroAssembler::printf(const char* output, Register value)
|
||||
|
||||
Register temp = regs.takeAnyGeneral();
|
||||
|
||||
setupUnalignedABICall(2, temp);
|
||||
setupUnalignedABICall(temp);
|
||||
movePtr(ImmPtr(output), temp);
|
||||
passABIArg(temp);
|
||||
passABIArg(value);
|
||||
@ -1893,7 +1893,7 @@ MacroAssembler::tracelogStartId(Register logger, uint32_t textId, bool force)
|
||||
|
||||
Register temp = regs.takeAnyGeneral();
|
||||
|
||||
setupUnalignedABICall(2, temp);
|
||||
setupUnalignedABICall(temp);
|
||||
passABIArg(logger);
|
||||
move32(Imm32(textId), temp);
|
||||
passABIArg(temp);
|
||||
@ -1913,7 +1913,7 @@ MacroAssembler::tracelogStartId(Register logger, Register textId)
|
||||
|
||||
Register temp = regs.takeAnyGeneral();
|
||||
|
||||
setupUnalignedABICall(2, temp);
|
||||
setupUnalignedABICall(temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(textId);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogStartEventPrivate));
|
||||
@ -1934,7 +1934,7 @@ MacroAssembler::tracelogStartEvent(Register logger, Register event)
|
||||
|
||||
Register temp = regs.takeAnyGeneral();
|
||||
|
||||
setupUnalignedABICall(2, temp);
|
||||
setupUnalignedABICall(temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(event);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogFunc));
|
||||
@ -1955,7 +1955,7 @@ MacroAssembler::tracelogStopId(Register logger, uint32_t textId, bool force)
|
||||
|
||||
Register temp = regs.takeAnyGeneral();
|
||||
|
||||
setupUnalignedABICall(2, temp);
|
||||
setupUnalignedABICall(temp);
|
||||
passABIArg(logger);
|
||||
move32(Imm32(textId), temp);
|
||||
passABIArg(temp);
|
||||
@ -1976,7 +1976,7 @@ MacroAssembler::tracelogStopId(Register logger, Register textId)
|
||||
|
||||
Register temp = regs.takeAnyGeneral();
|
||||
|
||||
setupUnalignedABICall(2, temp);
|
||||
setupUnalignedABICall(temp);
|
||||
passABIArg(logger);
|
||||
passABIArg(textId);
|
||||
callWithABI(JS_FUNC_TO_DATA_PTR(void*, TraceLogStopEventPrivate));
|
||||
@ -2548,6 +2548,9 @@ MacroAssembler::MacroAssembler(JSContext* cx, IonScript* ion,
|
||||
JSScript* script, jsbytecode* pc)
|
||||
: emitProfilingInstrumentation_(false),
|
||||
framePushed_(0)
|
||||
#ifdef DEBUG
|
||||
, inCall_(false)
|
||||
#endif
|
||||
{
|
||||
constructRoot(cx);
|
||||
jitContext_.emplace(cx, (js::jit::TempAllocator*)nullptr);
|
||||
@ -2764,4 +2767,108 @@ MacroAssembler::freeStack(Register amount)
|
||||
addToStackPtr(amount);
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// ABI function calls.
|
||||
|
||||
void
|
||||
MacroAssembler::setupABICall()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(!inCall_);
|
||||
inCall_ = true;
|
||||
#endif
|
||||
|
||||
#ifdef JS_SIMULATOR
|
||||
signature_ = 0;
|
||||
#endif
|
||||
|
||||
// Reinitialize the ABIArg generator.
|
||||
abiArgs_ = ABIArgGenerator();
|
||||
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
// On ARM, we need to know what ABI we are using, either in the
|
||||
// simulator, or based on the configure flags.
|
||||
#if defined(JS_SIMULATOR_ARM)
|
||||
abiArgs_.setUseHardFp(UseHardFpABI());
|
||||
#elif defined(JS_CODEGEN_ARM_HARDFP)
|
||||
abiArgs_.setUseHardFp(true);
|
||||
#else
|
||||
abiArgs_.setUseHardFp(false);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(JS_CODEGEN_MIPS32)
|
||||
// On MIPS, the system ABI use general registers pairs to encode double
|
||||
// arguments, after one or 2 integer-like arguments. Unfortunately, the
|
||||
// Lowering phase is not capable to express it at the moment. So we enforce
|
||||
// the system ABI here.
|
||||
abiArgs_.enforceO32ABI();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::setupAlignedABICall()
|
||||
{
|
||||
setupABICall();
|
||||
dynamicAlignment_ = false;
|
||||
assertStackAlignment(ABIStackAlignment);
|
||||
|
||||
#if defined(JS_CODEGEN_ARM64)
|
||||
MOZ_CRASH("Not supported on arm64");
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::passABIArg(const MoveOperand& from, MoveOp::Type type)
|
||||
{
|
||||
MOZ_ASSERT(inCall_);
|
||||
appendSignatureType(type);
|
||||
|
||||
ABIArg arg;
|
||||
switch (type) {
|
||||
case MoveOp::FLOAT32:
|
||||
arg = abiArgs_.next(MIRType_Float32);
|
||||
break;
|
||||
case MoveOp::DOUBLE:
|
||||
arg = abiArgs_.next(MIRType_Double);
|
||||
break;
|
||||
case MoveOp::GENERAL:
|
||||
arg = abiArgs_.next(MIRType_Pointer);
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected argument type");
|
||||
}
|
||||
|
||||
MoveOperand to(*this, arg);
|
||||
if (from == to)
|
||||
return;
|
||||
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
enoughMemory_ = moveResolver_.addMove(from, to, type);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABINoProfiler(void* fun, MoveOp::Type result)
|
||||
{
|
||||
appendSignatureType(result);
|
||||
#ifdef JS_SIMULATOR
|
||||
fun = Simulator::RedirectNativeFunction(fun, signature());
|
||||
#endif
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(ImmPtr(fun));
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABINoProfiler(AsmJSImmPtr imm, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust, /* callFromAsmJS = */ true);
|
||||
call(imm);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
//}}} check_macroassembler_style
|
||||
|
@ -332,6 +332,9 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
MacroAssembler()
|
||||
: emitProfilingInstrumentation_(false),
|
||||
framePushed_(0)
|
||||
#ifdef DEBUG
|
||||
, inCall_(false)
|
||||
#endif
|
||||
{
|
||||
JitContext* jcx = GetJitContext();
|
||||
JSContext* cx = jcx->cx;
|
||||
@ -364,6 +367,9 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
explicit MacroAssembler(AsmJSToken)
|
||||
: emitProfilingInstrumentation_(false),
|
||||
framePushed_(0)
|
||||
#ifdef DEBUG
|
||||
, inCall_(false)
|
||||
#endif
|
||||
{
|
||||
#if defined(JS_CODEGEN_ARM)
|
||||
initWithAllocator();
|
||||
@ -473,6 +479,79 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
inline void call(const CallSiteDesc& desc, const Register reg);
|
||||
inline void call(const CallSiteDesc& desc, Label* label);
|
||||
|
||||
public:
|
||||
// ===============================================================
|
||||
// ABI function calls.
|
||||
|
||||
// Setup a call to C/C++ code, given the assumption that the framePushed
|
||||
// accruately define the state of the stack, and that the top of the stack
|
||||
// was properly aligned. Note that this only supports cdecl.
|
||||
void setupAlignedABICall(); // CRASH_ON(arm64)
|
||||
|
||||
// Setup an ABI call for when the alignment is not known. This may need a
|
||||
// scratch register.
|
||||
void setupUnalignedABICall(Register scratch) PER_ARCH;
|
||||
|
||||
// Arguments must be assigned to a C/C++ call in order. They are moved
|
||||
// in parallel immediately before performing the call. This process may
|
||||
// temporarily use more stack, in which case esp-relative addresses will be
|
||||
// automatically adjusted. It is extremely important that esp-relative
|
||||
// addresses are computed *after* setupABICall(). Furthermore, no
|
||||
// operations should be emitted while setting arguments.
|
||||
void passABIArg(const MoveOperand& from, MoveOp::Type type);
|
||||
inline void passABIArg(Register reg);
|
||||
inline void passABIArg(FloatRegister reg, MoveOp::Type type);
|
||||
|
||||
template <typename T>
|
||||
inline void callWithABI(const T& fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
|
||||
private:
|
||||
// Reinitialize the variables which have to be cleared before making a call
|
||||
// with callWithABI.
|
||||
void setupABICall();
|
||||
|
||||
// Reserve the stack and resolve the arguments move.
|
||||
void callWithABIPre(uint32_t* stackAdjust, bool callFromAsmJS = false) PER_ARCH;
|
||||
|
||||
// Emits a call to a C/C++ function, resolving all argument moves.
|
||||
void callWithABINoProfiler(void* fun, MoveOp::Type result);
|
||||
void callWithABINoProfiler(AsmJSImmPtr imm, MoveOp::Type result);
|
||||
void callWithABINoProfiler(Register fun, MoveOp::Type result) PER_ARCH;
|
||||
void callWithABINoProfiler(const Address& fun, MoveOp::Type result) PER_ARCH;
|
||||
|
||||
// Restore the stack to its state before the setup function call.
|
||||
void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result) PER_ARCH;
|
||||
|
||||
// Create the signature to be able to decode the arguments of a native
|
||||
// function, when calling a function within the simulator.
|
||||
inline void appendSignatureType(MoveOp::Type type);
|
||||
inline ABIFunctionType signature() const;
|
||||
|
||||
// Private variables used to handle moves between registers given as
|
||||
// arguments to passABIArg and the list of ABI registers expected for the
|
||||
// signature of the function.
|
||||
MoveResolver moveResolver_;
|
||||
|
||||
// Architecture specific implementation which specify how registers & stack
|
||||
// offsets are used for calling a function.
|
||||
ABIArgGenerator abiArgs_;
|
||||
|
||||
#ifdef DEBUG
|
||||
// Flag use to assert that we use ABI function in the right context.
|
||||
bool inCall_;
|
||||
#endif
|
||||
|
||||
// If set by setupUnalignedABICall then callWithABI will pop the stack
|
||||
// register which is on the stack.
|
||||
bool dynamicAlignment_;
|
||||
|
||||
#ifdef JS_SIMULATOR
|
||||
// The signature is used to accumulate all types of arguments which are used
|
||||
// by the caller. This is used by the simulators to decode the arguments
|
||||
// properly, and cast the function pointer to the right type.
|
||||
uint32_t signature_;
|
||||
#endif
|
||||
|
||||
//}}} check_macroassembler_style
|
||||
public:
|
||||
|
||||
@ -1002,13 +1081,6 @@ class MacroAssembler : public MacroAssemblerSpecific
|
||||
// they are returning the offset of the assembler just after the call has
|
||||
// been made so that a safepoint can be made at that location.
|
||||
|
||||
template <typename T>
|
||||
void callWithABI(const T& fun, MoveOp::Type result = MoveOp::GENERAL) {
|
||||
profilerPreCall();
|
||||
MacroAssemblerSpecific::callWithABI(fun, result);
|
||||
profilerPostReturn();
|
||||
}
|
||||
|
||||
// see above comment for what is returned
|
||||
uint32_t callJit(Register callee) {
|
||||
profilerPreCall();
|
||||
|
@ -5,11 +5,40 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "jit/MoveResolver.h"
|
||||
|
||||
#include "jit/MacroAssembler.h"
|
||||
#include "jit/RegisterSets.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
MoveOperand::MoveOperand(MacroAssembler& masm, const ABIArg& arg)
|
||||
{
|
||||
switch (arg.kind()) {
|
||||
case ABIArg::GPR:
|
||||
kind_ = REG;
|
||||
code_ = arg.gpr().code();
|
||||
break;
|
||||
#ifdef JS_CODEGEN_REGISTER_PAIR
|
||||
case ABIArg::GPR_PAIR:
|
||||
kind_ = REG_PAIR;
|
||||
code_ = arg.evenGpr().code();
|
||||
MOZ_ASSERT(code_ % 2 == 0);
|
||||
MOZ_ASSERT(code_ + 1 == arg.oddGpr().code());
|
||||
break;
|
||||
#endif
|
||||
case ABIArg::FPU:
|
||||
kind_ = FLOAT_REG;
|
||||
code_ = arg.fpu().code();
|
||||
break;
|
||||
case ABIArg::Stack:
|
||||
kind_ = MEMORY;
|
||||
code_ = masm.getStackPointer().code();
|
||||
disp_ = arg.offsetFromArgBase();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MoveResolver::MoveResolver()
|
||||
: numCycles_(0), curCycles_(0)
|
||||
{
|
||||
|
@ -14,6 +14,8 @@
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
class MacroAssembler;
|
||||
|
||||
// This is similar to Operand, but carries more information. We're also not
|
||||
// guaranteed that Operand looks like this on all ISAs.
|
||||
class MoveOperand
|
||||
@ -22,6 +24,12 @@ class MoveOperand
|
||||
enum Kind {
|
||||
// A register in the "integer", aka "general purpose", class.
|
||||
REG,
|
||||
#ifdef JS_CODEGEN_REGISTER_PAIR
|
||||
// Two consecutive "integer" register (aka "general purpose"). The even
|
||||
// register contains the lower part, the odd register has the high bits
|
||||
// of the content.
|
||||
REG_PAIR,
|
||||
#endif
|
||||
// A register in the "float" register class.
|
||||
FLOAT_REG,
|
||||
// A memory region.
|
||||
@ -53,6 +61,7 @@ class MoveOperand
|
||||
if (disp == 0 && kind_ == EFFECTIVE_ADDRESS)
|
||||
kind_ = REG;
|
||||
}
|
||||
MoveOperand(MacroAssembler& masm, const ABIArg& arg);
|
||||
MoveOperand(const MoveOperand& other)
|
||||
: kind_(other.kind_),
|
||||
code_(other.code_),
|
||||
@ -64,6 +73,13 @@ class MoveOperand
|
||||
bool isGeneralReg() const {
|
||||
return kind_ == REG;
|
||||
}
|
||||
bool isGeneralRegPair() const {
|
||||
#ifdef JS_CODEGEN_REGISTER_PAIR
|
||||
return kind_ == REG_PAIR;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
bool isMemory() const {
|
||||
return kind_ == MEMORY;
|
||||
}
|
||||
@ -77,6 +93,14 @@ class MoveOperand
|
||||
MOZ_ASSERT(isGeneralReg());
|
||||
return Register::FromCode(code_);
|
||||
}
|
||||
Register evenReg() const {
|
||||
MOZ_ASSERT(isGeneralRegPair());
|
||||
return Register::FromCode(code_);
|
||||
}
|
||||
Register oddReg() const {
|
||||
MOZ_ASSERT(isGeneralRegPair());
|
||||
return Register::FromCode(code_ + 1);
|
||||
}
|
||||
FloatRegister floatReg() const {
|
||||
MOZ_ASSERT(isFloatReg());
|
||||
return FloatRegister::FromCode(code_);
|
||||
@ -101,6 +125,30 @@ class MoveOperand
|
||||
MOZ_ASSERT_IF(other.isMemoryOrEffectiveAddress() && isGeneralReg(),
|
||||
other.base() != reg());
|
||||
|
||||
// Check if one of the operand is a registe rpair, in which case, we
|
||||
// have to check any other register, or register pair.
|
||||
if (isGeneralRegPair() || other.isGeneralRegPair()) {
|
||||
if (isGeneralRegPair() && other.isGeneralRegPair()) {
|
||||
// Assume that register pairs are aligned on even registers.
|
||||
MOZ_ASSERT(!evenReg().aliases(other.oddReg()));
|
||||
MOZ_ASSERT(!oddReg().aliases(other.evenReg()));
|
||||
// Pair of registers are composed of consecutive registers, thus
|
||||
// if the first registers are aliased, then the second registers
|
||||
// are aliased too.
|
||||
MOZ_ASSERT(evenReg().aliases(other.evenReg()) == oddReg().aliases(other.oddReg()));
|
||||
return evenReg().aliases(other.evenReg());
|
||||
} else if (other.isGeneralReg()) {
|
||||
MOZ_ASSERT(isGeneralRegPair());
|
||||
return evenReg().aliases(other.reg()) ||
|
||||
oddReg().aliases(other.reg());
|
||||
} else if (isGeneralReg()) {
|
||||
MOZ_ASSERT(other.isGeneralRegPair());
|
||||
return other.evenReg().aliases(reg()) ||
|
||||
other.oddReg().aliases(reg());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (kind_ != other.kind_)
|
||||
return false;
|
||||
if (kind_ == FLOAT_REG)
|
||||
|
@ -1220,7 +1220,14 @@ class AnyRegisterIterator
|
||||
class ABIArg
|
||||
{
|
||||
public:
|
||||
enum Kind { GPR, FPU, Stack };
|
||||
enum Kind {
|
||||
GPR,
|
||||
#ifdef JS_CODEGEN_REGISTER_PAIR
|
||||
GPR_PAIR,
|
||||
#endif
|
||||
FPU,
|
||||
Stack
|
||||
};
|
||||
|
||||
private:
|
||||
Kind kind_;
|
||||
@ -1233,11 +1240,39 @@ class ABIArg
|
||||
public:
|
||||
ABIArg() : kind_(Kind(-1)) { u.offset_ = -1; }
|
||||
explicit ABIArg(Register gpr) : kind_(GPR) { u.gpr_ = gpr.code(); }
|
||||
explicit ABIArg(Register gprLow, Register gprHigh)
|
||||
{
|
||||
#if defined(JS_CODEGEN_REGISTER_PAIR)
|
||||
kind_ = GPR_PAIR;
|
||||
#else
|
||||
MOZ_CRASH("Unsupported type of ABI argument.");
|
||||
#endif
|
||||
u.gpr_ = gprLow.code();
|
||||
MOZ_ASSERT(u.gpr_ % 2 == 0);
|
||||
MOZ_ASSERT(u.gpr_ + 1 == gprHigh.code());
|
||||
}
|
||||
explicit ABIArg(FloatRegister fpu) : kind_(FPU) { u.fpu_ = fpu.code(); }
|
||||
explicit ABIArg(uint32_t offset) : kind_(Stack) { u.offset_ = offset; }
|
||||
|
||||
Kind kind() const { return kind_; }
|
||||
Register gpr() const { MOZ_ASSERT(kind() == GPR); return Register::FromCode(u.gpr_); }
|
||||
#ifdef JS_CODEGEN_REGISTER_PAIR
|
||||
bool isGeneralRegPair() const { return kind_ == GPR_PAIR; }
|
||||
#else
|
||||
bool isGeneralRegPair() const { return false; }
|
||||
#endif
|
||||
|
||||
Register gpr() const {
|
||||
MOZ_ASSERT(kind() == GPR);
|
||||
return Register::FromCode(u.gpr_);
|
||||
}
|
||||
Register evenGpr() const {
|
||||
MOZ_ASSERT(isGeneralRegPair());
|
||||
return Register::FromCode(u.gpr_);
|
||||
}
|
||||
Register oddGpr() const {
|
||||
MOZ_ASSERT(isGeneralRegPair());
|
||||
return Register::FromCode(u.gpr_ + 1);
|
||||
}
|
||||
FloatRegister fpu() const { MOZ_ASSERT(kind() == FPU); return FloatRegister::FromCode(u.fpu_); }
|
||||
uint32_t offsetFromArgBase() const { MOZ_ASSERT(kind() == Stack); return u.offset_; }
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
#endif
|
||||
#include "jit/VMFunctions.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
@ -807,7 +809,7 @@ ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler& masm, Register obj, Val
|
||||
#endif
|
||||
saveRegs.set() = GeneralRegisterSet::Intersect(saveRegs.set(), GeneralRegisterSet::Volatile());
|
||||
masm.PushRegsInMask(saveRegs);
|
||||
masm.setupUnalignedABICall(2, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.movePtr(ImmPtr(cx->runtime()), scratch);
|
||||
masm.passABIArg(scratch);
|
||||
masm.passABIArg(obj);
|
||||
|
@ -639,6 +639,10 @@ static inline bool UseHardFpABI()
|
||||
}
|
||||
#endif
|
||||
|
||||
// In order to handle SoftFp ABI calls, we need to be able to express that we
|
||||
// have ABIArg which are represented by pair of general purpose registers.
|
||||
#define JS_CODEGEN_REGISTER_PAIR 1
|
||||
|
||||
// See the comments above AsmJSMappedSize in AsmJSValidate.h for more info.
|
||||
// TODO: Implement this for ARM. Note that it requires Codegen to respect the
|
||||
// offset field of AsmJSHeapAccess.
|
||||
|
@ -24,17 +24,67 @@ using mozilla::CountLeadingZeroes32;
|
||||
|
||||
void dbg_break() {}
|
||||
|
||||
// Note this is used for inter-AsmJS calls and may pass arguments and results in
|
||||
// floating point registers even if the system ABI does not.
|
||||
// The ABIArgGenerator is used for making system ABI calls and for inter-AsmJS
|
||||
// calls. The system ABI can either be SoftFp or HardFp, and inter-AsmJS calls
|
||||
// are always HardFp calls. The initialization defaults to HardFp, and the ABI
|
||||
// choice is made before any system ABI calls with the method "setUseHardFp".
|
||||
ABIArgGenerator::ABIArgGenerator()
|
||||
: intRegIndex_(0),
|
||||
floatRegIndex_(0),
|
||||
stackOffset_(0),
|
||||
current_()
|
||||
current_(),
|
||||
useHardFp_(true)
|
||||
{ }
|
||||
|
||||
// See the "Parameter Passing" section of the "Procedure Call Standard for the
|
||||
// ARM Architecture" documentation.
|
||||
ABIArg
|
||||
ABIArgGenerator::next(MIRType type)
|
||||
ABIArgGenerator::softNext(MIRType type)
|
||||
{
|
||||
switch (type) {
|
||||
case MIRType_Int32:
|
||||
case MIRType_Pointer:
|
||||
if (intRegIndex_ == NumIntArgRegs) {
|
||||
current_ = ABIArg(stackOffset_);
|
||||
stackOffset_ += sizeof(uint32_t);
|
||||
break;
|
||||
}
|
||||
current_ = ABIArg(Register::FromCode(intRegIndex_));
|
||||
intRegIndex_++;
|
||||
break;
|
||||
case MIRType_Float32:
|
||||
if (intRegIndex_ == NumIntArgRegs) {
|
||||
current_ = ABIArg(stackOffset_);
|
||||
stackOffset_ += sizeof(uint32_t);
|
||||
break;
|
||||
}
|
||||
current_ = ABIArg(Register::FromCode(intRegIndex_));
|
||||
intRegIndex_++;
|
||||
break;
|
||||
case MIRType_Double:
|
||||
// Make sure to use an even register index. Increase to next even number
|
||||
// when odd.
|
||||
intRegIndex_ = (intRegIndex_ + 1) & ~1;
|
||||
if (intRegIndex_ == NumIntArgRegs) {
|
||||
// Align the stack on 8 bytes.
|
||||
static const int align = sizeof(double) - 1;
|
||||
stackOffset_ = (stackOffset_ + align) & ~align;
|
||||
current_ = ABIArg(stackOffset_);
|
||||
stackOffset_ += sizeof(double);
|
||||
break;
|
||||
}
|
||||
current_ = ABIArg(Register::FromCode(intRegIndex_), Register::FromCode(intRegIndex_ + 1));
|
||||
intRegIndex_ += 2;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected argument type");
|
||||
}
|
||||
|
||||
return current_;
|
||||
}
|
||||
|
||||
ABIArg
|
||||
ABIArgGenerator::hardNext(MIRType type)
|
||||
{
|
||||
switch (type) {
|
||||
case MIRType_Int32:
|
||||
@ -59,7 +109,9 @@ ABIArgGenerator::next(MIRType type)
|
||||
floatRegIndex_++;
|
||||
break;
|
||||
case MIRType_Double:
|
||||
// Bump the number of used registers up to the next multiple of two.
|
||||
// Double register are composed of 2 float registers, thus we have to
|
||||
// skip any float register which cannot be used in a pair of float
|
||||
// registers in which a double value can be stored.
|
||||
floatRegIndex_ = (floatRegIndex_ + 1) & ~1;
|
||||
if (floatRegIndex_ == NumFloatArgRegs) {
|
||||
static const int align = sizeof(double) - 1;
|
||||
@ -69,7 +121,7 @@ ABIArgGenerator::next(MIRType type)
|
||||
break;
|
||||
}
|
||||
current_ = ABIArg(VFPRegister(floatRegIndex_ >> 1, VFPRegister::Double));
|
||||
floatRegIndex_+=2;
|
||||
floatRegIndex_ += 2;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected argument type");
|
||||
@ -78,6 +130,14 @@ ABIArgGenerator::next(MIRType type)
|
||||
return current_;
|
||||
}
|
||||
|
||||
ABIArg
|
||||
ABIArgGenerator::next(MIRType type)
|
||||
{
|
||||
if (useHardFp_)
|
||||
return hardNext(type);
|
||||
return softNext(type);
|
||||
}
|
||||
|
||||
const Register ABIArgGenerator::NonArgReturnReg0 = r4;
|
||||
const Register ABIArgGenerator::NonArgReturnReg1 = r5;
|
||||
const Register ABIArgGenerator::NonReturn_VolatileReg0 = r2;
|
||||
|
@ -72,9 +72,23 @@ class ABIArgGenerator
|
||||
uint32_t stackOffset_;
|
||||
ABIArg current_;
|
||||
|
||||
// ARM can either use HardFp (use float registers for float arguments), or
|
||||
// SoftFp (use general registers for float arguments) ABI. We keep this
|
||||
// switch as a runtime switch because AsmJS always use the HardFp back-end
|
||||
// while the calls to native functions have to use the one provided by the
|
||||
// system.
|
||||
bool useHardFp_;
|
||||
|
||||
ABIArg softNext(MIRType argType);
|
||||
ABIArg hardNext(MIRType argType);
|
||||
|
||||
public:
|
||||
ABIArgGenerator();
|
||||
|
||||
void setUseHardFp(bool useHardFp) {
|
||||
MOZ_ASSERT(intRegIndex_ == 0 && floatRegIndex_ == 0);
|
||||
useHardFp_ = useHardFp;
|
||||
}
|
||||
ABIArg next(MIRType argType);
|
||||
ABIArg& current() { return current_; }
|
||||
uint32_t stackBytesConsumedSoFar() const { return stackOffset_; }
|
||||
|
@ -10,6 +10,8 @@
|
||||
#include "jit/Linker.h"
|
||||
#include "jit/SharedICHelpers.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
@ -137,7 +139,7 @@ ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
|
||||
MOZ_ASSERT(R0 == ValueOperand(r3, r2));
|
||||
masm.moveValue(R0, savedValue);
|
||||
|
||||
masm.setupAlignedABICall(2);
|
||||
masm.setupAlignedABICall();
|
||||
masm.passABIArg(R0.payloadReg());
|
||||
masm.passABIArg(R1.payloadReg());
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, __aeabi_idivmod));
|
||||
|
@ -573,7 +573,7 @@ CodeGeneratorARM::visitSoftDivI(LSoftDivI* ins)
|
||||
Label done;
|
||||
divICommon(mir, lhs, rhs, output, ins->snapshot(), done);
|
||||
|
||||
masm.setupAlignedABICall(2);
|
||||
masm.setupAlignedABICall();
|
||||
masm.passABIArg(lhs);
|
||||
masm.passABIArg(rhs);
|
||||
if (gen->compilingAsmJS())
|
||||
@ -734,7 +734,7 @@ CodeGeneratorARM::visitSoftModI(LSoftModI* ins)
|
||||
|
||||
modICommon(mir, lhs, rhs, output, ins->snapshot(), done);
|
||||
|
||||
masm.setupAlignedABICall(2);
|
||||
masm.setupAlignedABICall();
|
||||
masm.passABIArg(lhs);
|
||||
masm.passABIArg(rhs);
|
||||
if (gen->compilingAsmJS())
|
||||
@ -1916,7 +1916,7 @@ CodeGeneratorARM::visitAsmJSCompareExchangeCallout(LAsmJSCompareExchangeCallout*
|
||||
|
||||
MOZ_ASSERT(ToRegister(ins->output()) == ReturnReg);
|
||||
|
||||
masm.setupAlignedABICall(4);
|
||||
masm.setupAlignedABICall();
|
||||
masm.ma_mov(Imm32(viewType), ScratchRegister);
|
||||
masm.passABIArg(ScratchRegister);
|
||||
masm.passABIArg(ptr);
|
||||
@ -1969,7 +1969,7 @@ CodeGeneratorARM::visitAsmJSAtomicExchangeCallout(LAsmJSAtomicExchangeCallout* i
|
||||
|
||||
MOZ_ASSERT(ToRegister(ins->output()) == ReturnReg);
|
||||
|
||||
masm.setupAlignedABICall(3);
|
||||
masm.setupAlignedABICall();
|
||||
masm.ma_mov(Imm32(viewType), ScratchRegister);
|
||||
masm.passABIArg(ScratchRegister);
|
||||
masm.passABIArg(ptr);
|
||||
@ -2066,7 +2066,7 @@ CodeGeneratorARM::visitAsmJSAtomicBinopCallout(LAsmJSAtomicBinopCallout* ins)
|
||||
Register ptr = ToRegister(ins->ptr());
|
||||
Register value = ToRegister(ins->value());
|
||||
|
||||
masm.setupAlignedABICall(3);
|
||||
masm.setupAlignedABICall();
|
||||
masm.ma_mov(Imm32(viewType), ScratchRegister);
|
||||
masm.passABIArg(ScratchRegister);
|
||||
masm.passABIArg(ptr);
|
||||
@ -2193,7 +2193,7 @@ CodeGeneratorARM::visitSoftUDivOrMod(LSoftUDivOrMod* ins)
|
||||
generateUDivModZeroCheck(rhs, output, &done, ins->snapshot(), div);
|
||||
generateUDivModZeroCheck(rhs, output, &done, ins->snapshot(), mod);
|
||||
|
||||
masm.setupAlignedABICall(2);
|
||||
masm.setupAlignedABICall();
|
||||
masm.passABIArg(lhs);
|
||||
masm.passABIArg(rhs);
|
||||
if (gen->compilingAsmJS())
|
||||
@ -2336,7 +2336,7 @@ CodeGeneratorARM::visitRandom(LRandom* ins)
|
||||
|
||||
masm.loadJSContext(temp);
|
||||
|
||||
masm.setupUnalignedABICall(1, temp2);
|
||||
masm.setupUnalignedABICall(temp2);
|
||||
masm.passABIArg(temp);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE);
|
||||
|
||||
|
@ -1702,6 +1702,12 @@ MacroAssemblerARM::ma_vxfer(FloatRegister src, Register dest1, Register dest2, C
|
||||
as_vxfer(dest1, dest2, VFPRegister(src), FloatToCore, cc);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARM::ma_vxfer(Register src, FloatRegister dest, Condition cc)
|
||||
{
|
||||
as_vxfer(src, InvalidReg, VFPRegister(dest).singleOverlay(), CoreToFloat, cc);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARM::ma_vxfer(Register src1, Register src2, FloatRegister dest, Condition cc)
|
||||
{
|
||||
@ -3745,409 +3751,9 @@ MacroAssemblerARMCompat::breakpoint(Condition cc)
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::setupABICall(uint32_t args)
|
||||
MacroAssemblerARMCompat::checkStackAlignment()
|
||||
{
|
||||
MOZ_ASSERT(!inCall_);
|
||||
inCall_ = true;
|
||||
args_ = args;
|
||||
passedArgs_ = 0;
|
||||
passedArgTypes_ = 0;
|
||||
usedIntSlots_ = 0;
|
||||
#if defined(JS_CODEGEN_ARM_HARDFP) || defined(JS_SIMULATOR_ARM)
|
||||
usedFloatSlots_ = 0;
|
||||
usedFloat32_ = false;
|
||||
padding_ = 0;
|
||||
#endif
|
||||
floatArgsInGPR[0] = MoveOperand();
|
||||
floatArgsInGPR[1] = MoveOperand();
|
||||
floatArgsInGPR[2] = MoveOperand();
|
||||
floatArgsInGPR[3] = MoveOperand();
|
||||
floatArgsInGPRValid[0] = false;
|
||||
floatArgsInGPRValid[1] = false;
|
||||
floatArgsInGPRValid[2] = false;
|
||||
floatArgsInGPRValid[3] = false;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::setupAlignedABICall(uint32_t args)
|
||||
{
|
||||
setupABICall(args);
|
||||
|
||||
dynamicAlignment_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::setupUnalignedABICall(uint32_t args, Register scratch)
|
||||
{
|
||||
setupABICall(args);
|
||||
dynamicAlignment_ = true;
|
||||
|
||||
ma_mov(sp, scratch);
|
||||
|
||||
// Force sp to be aligned.
|
||||
ma_and(Imm32(~(ABIStackAlignment - 1)), sp, sp);
|
||||
ma_push(scratch);
|
||||
}
|
||||
|
||||
#if defined(JS_CODEGEN_ARM_HARDFP) || defined(JS_SIMULATOR_ARM)
|
||||
void
|
||||
MacroAssemblerARMCompat::passHardFpABIArg(const MoveOperand& from, MoveOp::Type type)
|
||||
{
|
||||
MoveOperand to;
|
||||
++passedArgs_;
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
switch (type) {
|
||||
case MoveOp::FLOAT32: {
|
||||
FloatRegister fr;
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Float32;
|
||||
if (GetFloat32ArgReg(usedIntSlots_, usedFloatSlots_, &fr)) {
|
||||
if (from.isFloatReg() && from.floatReg() == fr) {
|
||||
// Nothing to do; the value is in the right register already.
|
||||
usedFloatSlots_++;
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Float32;
|
||||
return;
|
||||
}
|
||||
to = MoveOperand(fr);
|
||||
} else {
|
||||
// If (and only if) the integer registers have started spilling, do
|
||||
// we need to take the register's alignment into account.
|
||||
uint32_t disp = GetFloat32ArgStackDisp(usedIntSlots_, usedFloatSlots_, &padding_);
|
||||
to = MoveOperand(sp, disp);
|
||||
}
|
||||
usedFloatSlots_++;
|
||||
break;
|
||||
}
|
||||
|
||||
case MoveOp::DOUBLE: {
|
||||
FloatRegister fr;
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Double;
|
||||
usedFloatSlots_ = (usedFloatSlots_ + 1) & -2;
|
||||
if (GetDoubleArgReg(usedIntSlots_, usedFloatSlots_, &fr)) {
|
||||
if (from.isFloatReg() && from.floatReg() == fr) {
|
||||
// Nothing to do; the value is in the right register already.
|
||||
usedFloatSlots_ += 2;
|
||||
return;
|
||||
}
|
||||
to = MoveOperand(fr);
|
||||
} else {
|
||||
// If (and only if) the integer registers have started spilling, do we
|
||||
// need to take the register's alignment into account
|
||||
uint32_t disp = GetDoubleArgStackDisp(usedIntSlots_, usedFloatSlots_, &padding_);
|
||||
to = MoveOperand(sp, disp);
|
||||
}
|
||||
usedFloatSlots_+=2;
|
||||
break;
|
||||
}
|
||||
case MoveOp::GENERAL: {
|
||||
Register r;
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_General;
|
||||
if (GetIntArgReg(usedIntSlots_, usedFloatSlots_, &r)) {
|
||||
if (from.isGeneralReg() && from.reg() == r) {
|
||||
// Nothing to do; the value is in the right register already.
|
||||
usedIntSlots_++;
|
||||
return;
|
||||
}
|
||||
to = MoveOperand(r);
|
||||
} else {
|
||||
uint32_t disp = GetIntArgStackDisp(usedIntSlots_, usedFloatSlots_, &padding_);
|
||||
to = MoveOperand(sp, disp);
|
||||
}
|
||||
usedIntSlots_++;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Unexpected argument type");
|
||||
}
|
||||
|
||||
enoughMemory_ = moveResolver_.addMove(from, to, type);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(JS_CODEGEN_ARM_HARDFP) || defined(JS_SIMULATOR_ARM)
|
||||
void
|
||||
MacroAssemblerARMCompat::passSoftFpABIArg(const MoveOperand& from, MoveOp::Type type)
|
||||
{
|
||||
MoveOperand to;
|
||||
uint32_t increment = 1;
|
||||
bool useResolver = true;
|
||||
++passedArgs_;
|
||||
switch (type) {
|
||||
case MoveOp::DOUBLE:
|
||||
// Double arguments need to be rounded up to the nearest doubleword
|
||||
// boundary, even if it is in a register!
|
||||
usedIntSlots_ = (usedIntSlots_ + 1) & ~1;
|
||||
increment = 2;
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Double;
|
||||
break;
|
||||
case MoveOp::FLOAT32:
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Float32;
|
||||
break;
|
||||
case MoveOp::GENERAL:
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_General;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected argument type");
|
||||
}
|
||||
|
||||
Register destReg;
|
||||
MoveOperand dest;
|
||||
if (GetIntArgReg(usedIntSlots_, 0, &destReg)) {
|
||||
if (type == MoveOp::DOUBLE || type == MoveOp::FLOAT32) {
|
||||
floatArgsInGPR[destReg.code()] = from;
|
||||
floatArgsInGPRValid[destReg.code()] = true;
|
||||
useResolver = false;
|
||||
} else if (from.isGeneralReg() && from.reg() == destReg) {
|
||||
// No need to move anything.
|
||||
useResolver = false;
|
||||
} else {
|
||||
dest = MoveOperand(destReg);
|
||||
}
|
||||
} else {
|
||||
uint32_t disp = GetArgStackDisp(usedIntSlots_);
|
||||
dest = MoveOperand(sp, disp);
|
||||
}
|
||||
|
||||
if (useResolver)
|
||||
enoughMemory_ = enoughMemory_ && moveResolver_.addMove(from, dest, type);
|
||||
usedIntSlots_ += increment;
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::passABIArg(const MoveOperand& from, MoveOp::Type type)
|
||||
{
|
||||
#if defined(JS_SIMULATOR_ARM)
|
||||
if (UseHardFpABI())
|
||||
MacroAssemblerARMCompat::passHardFpABIArg(from, type);
|
||||
else
|
||||
MacroAssemblerARMCompat::passSoftFpABIArg(from, type);
|
||||
#elif defined(JS_CODEGEN_ARM_HARDFP)
|
||||
MacroAssemblerARMCompat::passHardFpABIArg(from, type);
|
||||
#else
|
||||
MacroAssemblerARMCompat::passSoftFpABIArg(from, type);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::passABIArg(Register reg)
|
||||
{
|
||||
passABIArg(MoveOperand(reg), MoveOp::GENERAL);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::passABIArg(FloatRegister freg, MoveOp::Type type)
|
||||
{
|
||||
passABIArg(MoveOperand(freg), type);
|
||||
}
|
||||
|
||||
void MacroAssemblerARMCompat::checkStackAlignment()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
ma_tst(sp, Imm32(ABIStackAlignment - 1));
|
||||
breakpoint(NonZero);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::callWithABIPre(uint32_t* stackAdjust, bool callFromAsmJS)
|
||||
{
|
||||
MOZ_ASSERT(inCall_);
|
||||
|
||||
*stackAdjust = ((usedIntSlots_ > NumIntArgRegs) ? usedIntSlots_ - NumIntArgRegs : 0) * sizeof(intptr_t);
|
||||
#if defined(JS_CODEGEN_ARM_HARDFP) || defined(JS_SIMULATOR_ARM)
|
||||
if (UseHardFpABI())
|
||||
*stackAdjust += 2*((usedFloatSlots_ > NumFloatArgRegs) ? usedFloatSlots_ - NumFloatArgRegs : 0) * sizeof(intptr_t);
|
||||
#endif
|
||||
uint32_t alignmentAtPrologue = callFromAsmJS ? sizeof(AsmJSFrame) : 0;
|
||||
|
||||
if (!dynamicAlignment_) {
|
||||
*stackAdjust += ComputeByteAlignment(asMasm().framePushed() + *stackAdjust + alignmentAtPrologue,
|
||||
ABIStackAlignment);
|
||||
} else {
|
||||
// sizeof(intptr_t) accounts for the saved stack pointer pushed by
|
||||
// setupUnalignedABICall.
|
||||
*stackAdjust += ComputeByteAlignment(*stackAdjust + sizeof(intptr_t), ABIStackAlignment);
|
||||
}
|
||||
|
||||
asMasm().reserveStack(*stackAdjust);
|
||||
|
||||
// Position all arguments.
|
||||
{
|
||||
enoughMemory_ = enoughMemory_ && moveResolver_.resolve();
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
|
||||
MoveEmitter emitter(asMasm());
|
||||
emitter.emit(moveResolver_);
|
||||
emitter.finish();
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (floatArgsInGPRValid[i]) {
|
||||
MoveOperand from = floatArgsInGPR[i];
|
||||
Register to0 = Register::FromCode(i);
|
||||
Register to1;
|
||||
|
||||
if (!from.isFloatReg() || from.floatReg().isDouble()) {
|
||||
// Doubles need to be moved into a pair of aligned registers
|
||||
// whether they come from the stack, or VFP registers.
|
||||
to1 = Register::FromCode(i + 1);
|
||||
MOZ_ASSERT(i % 2 == 0);
|
||||
}
|
||||
|
||||
if (from.isFloatReg()) {
|
||||
if (from.floatReg().isDouble())
|
||||
ma_vxfer(from.floatReg(), to0, to1);
|
||||
else
|
||||
ma_vxfer(from.floatReg(), to0);
|
||||
} else {
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
// Note: We can safely use the MoveOperand's displacement here,
|
||||
// even if the base is SP: MoveEmitter::toOperand adjusts
|
||||
// SP-relative operands by the difference between the current
|
||||
// stack usage and stackAdjust, which emitter.finish() resets to
|
||||
// 0.
|
||||
//
|
||||
// Warning: if the offset isn't within [-255,+255] then this
|
||||
// will assert-fail (or, if non-debug, load the wrong words).
|
||||
// Nothing uses such an offset at the time of this writing.
|
||||
ma_ldrd(EDtrAddr(from.base(), EDtrOffImm(from.disp())), to0, to1);
|
||||
}
|
||||
}
|
||||
}
|
||||
checkStackAlignment();
|
||||
|
||||
// Save the lr register if we need to preserve it.
|
||||
if (secondScratchReg_ != lr)
|
||||
ma_mov(lr, secondScratchReg_);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
|
||||
{
|
||||
if (secondScratchReg_ != lr)
|
||||
ma_mov(secondScratchReg_, lr);
|
||||
|
||||
switch (result) {
|
||||
case MoveOp::DOUBLE:
|
||||
if (!UseHardFpABI()) {
|
||||
// Move double from r0/r1 to ReturnFloatReg.
|
||||
as_vxfer(r0, r1, ReturnDoubleReg, CoreToFloat);
|
||||
break;
|
||||
}
|
||||
case MoveOp::FLOAT32:
|
||||
if (!UseHardFpABI()) {
|
||||
// Move float32 from r0 to ReturnFloatReg.
|
||||
as_vxfer(r0, InvalidReg, ReturnFloat32Reg.singleOverlay(), CoreToFloat);
|
||||
break;
|
||||
}
|
||||
case MoveOp::GENERAL:
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("unexpected callWithABI result");
|
||||
}
|
||||
|
||||
asMasm().freeStack(stackAdjust);
|
||||
|
||||
if (dynamicAlignment_) {
|
||||
// While the x86 supports pop esp, on ARM that isn't well defined, so
|
||||
// just do it manually.
|
||||
as_dtr(IsLoad, 32, Offset, sp, DTRAddr(sp, DtrOffImm(0)));
|
||||
}
|
||||
|
||||
MOZ_ASSERT(inCall_);
|
||||
inCall_ = false;
|
||||
}
|
||||
|
||||
#if defined(DEBUG) && defined(JS_SIMULATOR_ARM)
|
||||
static void
|
||||
AssertValidABIFunctionType(uint32_t passedArgTypes)
|
||||
{
|
||||
switch (passedArgTypes) {
|
||||
case Args_General0:
|
||||
case Args_General1:
|
||||
case Args_General2:
|
||||
case Args_General3:
|
||||
case Args_General4:
|
||||
case Args_General5:
|
||||
case Args_General6:
|
||||
case Args_General7:
|
||||
case Args_General8:
|
||||
case Args_Double_None:
|
||||
case Args_Int_Double:
|
||||
case Args_Float32_Float32:
|
||||
case Args_Double_Double:
|
||||
case Args_Double_Int:
|
||||
case Args_Double_DoubleInt:
|
||||
case Args_Double_DoubleDouble:
|
||||
case Args_Double_IntDouble:
|
||||
case Args_Int_IntDouble:
|
||||
case Args_Double_DoubleDoubleDouble:
|
||||
case Args_Double_DoubleDoubleDoubleDouble:
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected type");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::callWithABI(void* fun, MoveOp::Type result)
|
||||
{
|
||||
#ifdef JS_SIMULATOR_ARM
|
||||
MOZ_ASSERT(passedArgs_ <= 15);
|
||||
passedArgTypes_ <<= ArgType_Shift;
|
||||
switch (result) {
|
||||
case MoveOp::GENERAL: passedArgTypes_ |= ArgType_General; break;
|
||||
case MoveOp::DOUBLE: passedArgTypes_ |= ArgType_Double; break;
|
||||
case MoveOp::FLOAT32: passedArgTypes_ |= ArgType_Float32; break;
|
||||
default: MOZ_CRASH("Invalid return type");
|
||||
}
|
||||
#ifdef DEBUG
|
||||
AssertValidABIFunctionType(passedArgTypes_);
|
||||
#endif
|
||||
ABIFunctionType type = ABIFunctionType(passedArgTypes_);
|
||||
fun = Simulator::RedirectNativeFunction(fun, type);
|
||||
#endif
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
ma_call(ImmPtr(fun));
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::callWithABI(AsmJSImmPtr imm, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust, /* callFromAsmJS = */ true);
|
||||
asMasm().call(imm);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::callWithABI(const Address& fun, MoveOp::Type result)
|
||||
{
|
||||
// Load the callee in r12, no instruction between the ldr and call should
|
||||
// clobber it. Note that we can't use fun.base because it may be one of the
|
||||
// IntArg registers clobbered before the call.
|
||||
ma_ldr(fun, r12);
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(r12);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerARMCompat::callWithABI(Register fun, MoveOp::Type result)
|
||||
{
|
||||
// Load the callee in r12, as above.
|
||||
ma_mov(fun, r12);
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(r12);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
asMasm().assertStackAlignment(ABIStackAlignment);
|
||||
}
|
||||
|
||||
void
|
||||
@ -4160,9 +3766,9 @@ MacroAssemblerARMCompat::handleFailureWithHandlerTail(void* handler)
|
||||
ma_mov(sp, r0);
|
||||
|
||||
// Call the handler.
|
||||
setupUnalignedABICall(1, r1);
|
||||
passABIArg(r0);
|
||||
callWithABI(handler);
|
||||
asMasm().setupUnalignedABICall(r1);
|
||||
asMasm().passABIArg(r0);
|
||||
asMasm().callWithABI(handler);
|
||||
|
||||
Label entryFrame;
|
||||
Label catch_;
|
||||
@ -5374,4 +4980,122 @@ MacroAssembler::call(JitCode* c)
|
||||
ma_callJitHalfPush(ScratchRegister);
|
||||
}
|
||||
|
||||
|
||||
// ===============================================================
|
||||
// ABI function calls.
|
||||
|
||||
void
|
||||
MacroAssembler::setupUnalignedABICall(Register scratch)
|
||||
{
|
||||
setupABICall();
|
||||
dynamicAlignment_ = true;
|
||||
|
||||
ma_mov(sp, scratch);
|
||||
// Force sp to be aligned.
|
||||
ma_and(Imm32(~(ABIStackAlignment - 1)), sp, sp);
|
||||
ma_push(scratch);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABIPre(uint32_t* stackAdjust, bool callFromAsmJS)
|
||||
{
|
||||
MOZ_ASSERT(inCall_);
|
||||
uint32_t stackForCall = abiArgs_.stackBytesConsumedSoFar();
|
||||
|
||||
if (dynamicAlignment_) {
|
||||
// sizeof(intptr_t) accounts for the saved stack pointer pushed by
|
||||
// setupUnalignedABICall.
|
||||
stackForCall += ComputeByteAlignment(stackForCall + sizeof(intptr_t),
|
||||
ABIStackAlignment);
|
||||
} else {
|
||||
uint32_t alignmentAtPrologue = callFromAsmJS ? sizeof(AsmJSFrame) : 0;
|
||||
stackForCall += ComputeByteAlignment(stackForCall + framePushed() + alignmentAtPrologue,
|
||||
ABIStackAlignment);
|
||||
}
|
||||
|
||||
*stackAdjust = stackForCall;
|
||||
reserveStack(stackForCall);
|
||||
|
||||
// Position all arguments.
|
||||
{
|
||||
enoughMemory_ = enoughMemory_ && moveResolver_.resolve();
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
|
||||
MoveEmitter emitter(*this);
|
||||
emitter.emit(moveResolver_);
|
||||
emitter.finish();
|
||||
}
|
||||
|
||||
assertStackAlignment(ABIStackAlignment);
|
||||
|
||||
// Save the lr register if we need to preserve it.
|
||||
if (secondScratchReg_ != lr)
|
||||
ma_mov(lr, secondScratchReg_);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
|
||||
{
|
||||
if (secondScratchReg_ != lr)
|
||||
ma_mov(secondScratchReg_, lr);
|
||||
|
||||
switch (result) {
|
||||
case MoveOp::DOUBLE:
|
||||
if (!UseHardFpABI()) {
|
||||
// Move double from r0/r1 to ReturnFloatReg.
|
||||
ma_vxfer(r0, r1, ReturnDoubleReg);
|
||||
break;
|
||||
}
|
||||
case MoveOp::FLOAT32:
|
||||
if (!UseHardFpABI()) {
|
||||
// Move float32 from r0 to ReturnFloatReg.
|
||||
ma_vxfer(r0, ReturnFloat32Reg.singleOverlay());
|
||||
break;
|
||||
}
|
||||
case MoveOp::GENERAL:
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("unexpected callWithABI result");
|
||||
}
|
||||
|
||||
freeStack(stackAdjust);
|
||||
|
||||
if (dynamicAlignment_) {
|
||||
// While the x86 supports pop esp, on ARM that isn't well defined, so
|
||||
// just do it manually.
|
||||
as_dtr(IsLoad, 32, Offset, sp, DTRAddr(sp, DtrOffImm(0)));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(inCall_);
|
||||
inCall_ = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABINoProfiler(Register fun, MoveOp::Type result)
|
||||
{
|
||||
// Load the callee in r12, as above.
|
||||
ma_mov(fun, r12);
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(r12);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result)
|
||||
{
|
||||
// Load the callee in r12, no instruction between the ldr and call should
|
||||
// clobber it. Note that we can't use fun.base because it may be one of the
|
||||
// IntArg registers clobbered before the call.
|
||||
ma_ldr(fun, r12);
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(r12);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
//}}} check_macroassembler_style
|
||||
|
@ -401,9 +401,14 @@ class MacroAssemblerARM : public Assembler
|
||||
void ma_vcvt_U32_F32(FloatRegister src, FloatRegister dest, Condition cc = Always);
|
||||
|
||||
|
||||
// Transfer (do not coerce) a float into a gpr.
|
||||
void ma_vxfer(VFPRegister src, Register dest, Condition cc = Always);
|
||||
// Transfer (do not coerce) a double into a couple of gpr.
|
||||
void ma_vxfer(VFPRegister src, Register dest1, Register dest2, Condition cc = Always);
|
||||
|
||||
// Transfer (do not coerce) a gpr into a float
|
||||
void ma_vxfer(Register src, FloatRegister dest, Condition cc = Always);
|
||||
// Transfer (do not coerce) a couple of gpr into a double
|
||||
void ma_vxfer(Register src1, Register src2, FloatRegister dest, Condition cc = Always);
|
||||
|
||||
BufferOffset ma_vdtr(LoadStore ls, const Address& addr, VFPRegister dest, Condition cc = Always);
|
||||
@ -493,48 +498,8 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
MacroAssembler& asMasm();
|
||||
const MacroAssembler& asMasm() const;
|
||||
|
||||
private:
|
||||
bool inCall_;
|
||||
// Number of bytes the stack is adjusted inside a call to C. Calls to C may
|
||||
// not be nested.
|
||||
uint32_t args_;
|
||||
// The actual number of arguments that were passed, used to assert that the
|
||||
// initial number of arguments declared was correct.
|
||||
uint32_t passedArgs_;
|
||||
uint32_t passedArgTypes_;
|
||||
|
||||
// ARM treats arguments as a vector in registers/memory, that looks like:
|
||||
// { r0, r1, r2, r3, [sp], [sp,+4], [sp,+8] ... }
|
||||
// usedIntSlots_ keeps track of how many of these have been used. It bears a
|
||||
// passing resemblance to passedArgs_, but a single argument can effectively
|
||||
// use between one and three slots depending on its size and alignment
|
||||
// requirements.
|
||||
uint32_t usedIntSlots_;
|
||||
#if defined(JS_CODEGEN_ARM_HARDFP) || defined(JS_SIMULATOR_ARM)
|
||||
uint32_t usedFloatSlots_;
|
||||
bool usedFloat32_;
|
||||
uint32_t padding_;
|
||||
#endif
|
||||
bool dynamicAlignment_;
|
||||
|
||||
// Used to work around the move resolver's lack of support for moving into
|
||||
// register pairs, which the softfp ABI needs.
|
||||
mozilla::Array<MoveOperand, 4> floatArgsInGPR;
|
||||
mozilla::Array<bool, 4> floatArgsInGPRValid;
|
||||
|
||||
// Compute space needed for the function call and set the properties of the
|
||||
// callee. It returns the space which has to be allocated for calling the
|
||||
// function.
|
||||
//
|
||||
// arg Number of arguments of the function.
|
||||
void setupABICall(uint32_t arg);
|
||||
|
||||
protected:
|
||||
MoveResolver moveResolver_;
|
||||
|
||||
public:
|
||||
MacroAssemblerARMCompat()
|
||||
: inCall_(false)
|
||||
{ }
|
||||
|
||||
public:
|
||||
@ -1752,47 +1717,10 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
|
||||
emitSet(cond, dest);
|
||||
}
|
||||
|
||||
// Setup a call to C/C++ code, given the number of general arguments it
|
||||
// takes. Note that this only supports cdecl.
|
||||
//
|
||||
// In order for alignment to work correctly, the MacroAssembler must have a
|
||||
// consistent view of the stack displacement. It is okay to call "push"
|
||||
// manually, however, if the stack alignment were to change, the macro
|
||||
// assembler should be notified before starting a call.
|
||||
void setupAlignedABICall(uint32_t args);
|
||||
|
||||
// Sets up an ABI call for when the alignment is not known. This may need a
|
||||
// scratch register.
|
||||
void setupUnalignedABICall(uint32_t args, Register scratch);
|
||||
|
||||
// Arguments must be assigned in a left-to-right order. This process may
|
||||
// temporarily use more stack, in which case esp-relative addresses will be
|
||||
// automatically adjusted. It is extremely important that esp-relative
|
||||
// addresses are computed *after* setupABICall(). Furthermore, no operations
|
||||
// should be emitted while setting arguments.
|
||||
void passABIArg(const MoveOperand& from, MoveOp::Type type);
|
||||
void passABIArg(Register reg);
|
||||
void passABIArg(FloatRegister reg, MoveOp::Type type);
|
||||
void passABIArg(const ValueOperand& regs);
|
||||
|
||||
private:
|
||||
void passHardFpABIArg(const MoveOperand& from, MoveOp::Type type);
|
||||
void passSoftFpABIArg(const MoveOperand& from, MoveOp::Type type);
|
||||
|
||||
protected:
|
||||
bool buildOOLFakeExitFrame(void* fakeReturnAddr);
|
||||
|
||||
private:
|
||||
void callWithABIPre(uint32_t* stackAdjust, bool callFromAsmJS = false);
|
||||
void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result);
|
||||
|
||||
public:
|
||||
// Emits a call to a C/C++ function, resolving all argument moves.
|
||||
void callWithABI(void* fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(const Address& fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(Register fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
|
||||
CodeOffsetLabel labelForPatch() {
|
||||
return CodeOffsetLabel(nextOffset().getOffset());
|
||||
}
|
||||
|
@ -113,6 +113,11 @@ MoveEmitterARM::breakCycle(const MoveOperand& from, const MoveOperand& to,
|
||||
// just fill both of them with the same value.
|
||||
masm.ma_vstr(temp, cycleSlot(slotId, 0));
|
||||
masm.ma_vstr(temp, cycleSlot(slotId, 4));
|
||||
} else if (to.isGeneralReg()) {
|
||||
// Since it is uncertain if the load will be aligned or not
|
||||
// just fill both of them with the same value.
|
||||
masm.ma_str(to.reg(), cycleSlot(slotId, 0));
|
||||
masm.ma_str(to.reg(), cycleSlot(slotId, 4));
|
||||
} else {
|
||||
FloatRegister src = to.floatReg();
|
||||
// Just always store the largest possible size. Currently, this is
|
||||
@ -125,6 +130,10 @@ MoveEmitterARM::breakCycle(const MoveOperand& from, const MoveOperand& to,
|
||||
FloatRegister temp = ScratchDoubleReg;
|
||||
masm.ma_vldr(toAddress(to), temp);
|
||||
masm.ma_vstr(temp, cycleSlot(slotId, 0));
|
||||
} else if (to.isGeneralRegPair()) {
|
||||
FloatRegister reg = ScratchDoubleReg;
|
||||
masm.ma_vxfer(to.evenReg(), to.oddReg(), reg);
|
||||
masm.ma_vstr(reg, cycleSlot(slotId, 0));
|
||||
} else {
|
||||
masm.ma_vstr(to.floatReg().doubleOverlay(), cycleSlot(slotId, 0));
|
||||
}
|
||||
@ -166,6 +175,14 @@ MoveEmitterARM::completeCycle(const MoveOperand& from, const MoveOperand& to, Mo
|
||||
FloatRegister temp = ScratchDoubleReg;
|
||||
masm.ma_vldr(cycleSlot(slotId, 0), temp);
|
||||
masm.ma_vstr(temp, toAddress(to));
|
||||
} else if (to.isGeneralReg()) {
|
||||
MOZ_ASSERT(type == MoveOp::FLOAT32);
|
||||
masm.ma_ldr(toAddress(from), to.reg());
|
||||
} else if (to.isGeneralRegPair()) {
|
||||
MOZ_ASSERT(type == MoveOp::DOUBLE);
|
||||
FloatRegister reg = ScratchDoubleReg;
|
||||
masm.ma_vldr(toAddress(from), reg);
|
||||
masm.ma_vxfer(reg, to.evenReg(), to.oddReg());
|
||||
} else {
|
||||
uint32_t offset = 0;
|
||||
if ((!from.isMemory()) && from.floatReg().numAlignedAliased() == 1)
|
||||
@ -196,6 +213,10 @@ MoveEmitterARM::completeCycle(const MoveOperand& from, const MoveOperand& to, Mo
|
||||
void
|
||||
MoveEmitterARM::emitMove(const MoveOperand& from, const MoveOperand& to)
|
||||
{
|
||||
// Register pairs are used to store Double values during calls.
|
||||
MOZ_ASSERT(!from.isGeneralRegPair());
|
||||
MOZ_ASSERT(!to.isGeneralRegPair());
|
||||
|
||||
if (to.isGeneralReg() && to.reg() == spilledReg_) {
|
||||
// If the destination is the spilled register, make sure we
|
||||
// don't re-clobber its value.
|
||||
@ -236,13 +257,28 @@ MoveEmitterARM::emitMove(const MoveOperand& from, const MoveOperand& to)
|
||||
void
|
||||
MoveEmitterARM::emitFloat32Move(const MoveOperand& from, const MoveOperand& to)
|
||||
{
|
||||
// Register pairs are used to store Double values during calls.
|
||||
MOZ_ASSERT(!from.isGeneralRegPair());
|
||||
MOZ_ASSERT(!to.isGeneralRegPair());
|
||||
|
||||
if (from.isFloatReg()) {
|
||||
if (to.isFloatReg())
|
||||
masm.ma_vmov_f32(from.floatReg(), to.floatReg());
|
||||
else if (to.isGeneralReg())
|
||||
masm.ma_vxfer(from.floatReg(), to.reg());
|
||||
else
|
||||
masm.ma_vstr(VFPRegister(from.floatReg()).singleOverlay(), toAddress(to));
|
||||
} else if (from.isGeneralReg()) {
|
||||
if (to.isFloatReg())
|
||||
masm.ma_vxfer(from.reg(), to.floatReg());
|
||||
else if (to.isGeneralReg())
|
||||
masm.ma_mov(from.reg(), to.reg());
|
||||
else
|
||||
masm.ma_str(from.reg(), toAddress(to));
|
||||
} else if (to.isFloatReg()) {
|
||||
masm.ma_vldr(toAddress(from), VFPRegister(to.floatReg()).singleOverlay());
|
||||
} else if (to.isGeneralReg()) {
|
||||
masm.ma_ldr(toAddress(from), to.reg());
|
||||
} else {
|
||||
// Memory to memory move.
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
@ -255,13 +291,44 @@ MoveEmitterARM::emitFloat32Move(const MoveOperand& from, const MoveOperand& to)
|
||||
void
|
||||
MoveEmitterARM::emitDoubleMove(const MoveOperand& from, const MoveOperand& to)
|
||||
{
|
||||
// Registers are used to store pointers / int32 / float32 values.
|
||||
MOZ_ASSERT(!from.isGeneralReg());
|
||||
MOZ_ASSERT(!to.isGeneralReg());
|
||||
|
||||
if (from.isFloatReg()) {
|
||||
if (to.isFloatReg())
|
||||
masm.ma_vmov(from.floatReg(), to.floatReg());
|
||||
else if (to.isGeneralRegPair())
|
||||
masm.ma_vxfer(from.floatReg(), to.evenReg(), to.oddReg());
|
||||
else
|
||||
masm.ma_vstr(from.floatReg(), toAddress(to));
|
||||
} else if (from.isGeneralRegPair()) {
|
||||
if (to.isFloatReg())
|
||||
masm.ma_vxfer(from.evenReg(), from.oddReg(), to.floatReg());
|
||||
else if (to.isGeneralRegPair()) {
|
||||
MOZ_ASSERT(!from.aliases(to));
|
||||
masm.ma_mov(from.evenReg(), to.evenReg());
|
||||
masm.ma_mov(from.oddReg(), to.oddReg());
|
||||
} else {
|
||||
FloatRegister reg = ScratchDoubleReg;
|
||||
masm.ma_vxfer(from.evenReg(), from.oddReg(), reg);
|
||||
masm.ma_vstr(reg, toAddress(to));
|
||||
}
|
||||
} else if (to.isFloatReg()) {
|
||||
masm.ma_vldr(toAddress(from), to.floatReg());
|
||||
} else if (to.isGeneralRegPair()) {
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
Address src = toAddress(from);
|
||||
// Note: We can safely use the MoveOperand's displacement here,
|
||||
// even if the base is SP: MoveEmitter::toOperand adjusts
|
||||
// SP-relative operands by the difference between the current
|
||||
// stack usage and stackAdjust, which emitter.finish() resets to
|
||||
// 0.
|
||||
//
|
||||
// Warning: if the offset isn't within [-255,+255] then this
|
||||
// will assert-fail (or, if non-debug, load the wrong words).
|
||||
// Nothing uses such an offset at the time of this writing.
|
||||
masm.ma_ldrd(EDtrAddr(src.base, EDtrOffImm(src.offset)), to.evenReg(), to.oddReg());
|
||||
} else {
|
||||
// Memory to memory move.
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
|
@ -292,7 +292,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
||||
masm.push(framePtr); // BaselineFrame
|
||||
masm.push(r0); // jitcode
|
||||
|
||||
masm.setupUnalignedABICall(3, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.passABIArg(r11); // BaselineFrame
|
||||
masm.passABIArg(OsrFrameReg); // InterpreterFrame
|
||||
masm.passABIArg(numStackValues);
|
||||
@ -423,7 +423,7 @@ JitRuntime::generateInvalidator(JSContext* cx)
|
||||
const int sizeOfBailoutInfo = sizeof(void*)*2;
|
||||
masm.reserveStack(sizeOfBailoutInfo);
|
||||
masm.mov(sp, r2);
|
||||
masm.setupAlignedABICall(3);
|
||||
masm.setupAlignedABICall();
|
||||
masm.passABIArg(r0);
|
||||
masm.passABIArg(r1);
|
||||
masm.passABIArg(r2);
|
||||
@ -646,7 +646,7 @@ GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass)
|
||||
const int sizeOfBailoutInfo = sizeof(void*)*2;
|
||||
masm.reserveStack(sizeOfBailoutInfo);
|
||||
masm.mov(sp, r1);
|
||||
masm.setupAlignedABICall(2);
|
||||
masm.setupAlignedABICall();
|
||||
|
||||
// Decrement sp by another 4, so we keep alignment. Not Anymore! Pushing
|
||||
// both the snapshotoffset as well as the: masm.as_sub(sp, sp, Imm8(4));
|
||||
@ -817,7 +817,7 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
||||
break;
|
||||
}
|
||||
|
||||
masm.setupUnalignedABICall(f.argc(), regs.getAny());
|
||||
masm.setupUnalignedABICall(regs.getAny());
|
||||
masm.passABIArg(cxreg);
|
||||
|
||||
size_t argDisp = 0;
|
||||
@ -942,7 +942,7 @@ JitRuntime::generatePreBarrier(JSContext* cx, MIRType type)
|
||||
MOZ_ASSERT(PreBarrierReg == r1);
|
||||
masm.movePtr(ImmPtr(cx->runtime()), r0);
|
||||
|
||||
masm.setupUnalignedABICall(2, r2);
|
||||
masm.setupUnalignedABICall(r2);
|
||||
masm.passABIArg(r0);
|
||||
masm.passABIArg(r1);
|
||||
masm.callWithABI(IonMarkFunction(type));
|
||||
|
@ -12,6 +12,8 @@
|
||||
#include "jit/BaselineFrame.h"
|
||||
#include "jit/MacroAssembler.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
|
||||
namespace js {
|
||||
namespace jit {
|
||||
|
||||
@ -180,9 +182,9 @@ MacroAssemblerCompat::handleFailureWithHandlerTail(void* handler)
|
||||
Mov(x0, GetStackPointer64());
|
||||
|
||||
// Call the handler.
|
||||
setupUnalignedABICall(1, r1);
|
||||
passABIArg(r0);
|
||||
callWithABI(handler);
|
||||
asMasm().setupUnalignedABICall(r1);
|
||||
asMasm().passABIArg(r0);
|
||||
asMasm().callWithABI(handler);
|
||||
|
||||
Label entryFrame;
|
||||
Label catch_;
|
||||
@ -252,247 +254,6 @@ MacroAssemblerCompat::handleFailureWithHandlerTail(void* handler)
|
||||
Br(x1);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::setupABICall(uint32_t args)
|
||||
{
|
||||
MOZ_ASSERT(!inCall_);
|
||||
inCall_ = true;
|
||||
|
||||
args_ = args;
|
||||
usedOutParam_ = false;
|
||||
passedIntArgs_ = 0;
|
||||
passedFloatArgs_ = 0;
|
||||
passedArgTypes_ = 0;
|
||||
stackForCall_ = ShadowStackSpace;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::setupUnalignedABICall(uint32_t args, Register scratch)
|
||||
{
|
||||
setupABICall(args);
|
||||
dynamicAlignment_ = true;
|
||||
|
||||
int64_t alignment = ~(int64_t(ABIStackAlignment) - 1);
|
||||
ARMRegister scratch64(scratch, 64);
|
||||
|
||||
// Always save LR -- Baseline ICs assume that LR isn't modified.
|
||||
push(lr);
|
||||
|
||||
// Unhandled for sp -- needs slightly different logic.
|
||||
MOZ_ASSERT(!GetStackPointer64().Is(sp));
|
||||
|
||||
// Remember the stack address on entry.
|
||||
Mov(scratch64, GetStackPointer64());
|
||||
|
||||
// Make alignment, including the effective push of the previous sp.
|
||||
Sub(GetStackPointer64(), GetStackPointer64(), Operand(8));
|
||||
And(GetStackPointer64(), GetStackPointer64(), Operand(alignment));
|
||||
|
||||
// If the PseudoStackPointer is used, sp must be <= psp before a write is valid.
|
||||
syncStackPtr();
|
||||
|
||||
// Store previous sp to the top of the stack, aligned.
|
||||
Str(scratch64, MemOperand(GetStackPointer64(), 0));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::passABIArg(const MoveOperand& from, MoveOp::Type type)
|
||||
{
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
|
||||
Register activeSP = Register::FromCode(GetStackPointer64().code());
|
||||
if (type == MoveOp::GENERAL) {
|
||||
Register dest;
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_General;
|
||||
if (GetIntArgReg(passedIntArgs_++, passedFloatArgs_, &dest)) {
|
||||
if (!from.isGeneralReg() || from.reg() != dest)
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(dest), type);
|
||||
return;
|
||||
}
|
||||
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(activeSP, stackForCall_), type);
|
||||
stackForCall_ += sizeof(int64_t);
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(type == MoveOp::FLOAT32 || type == MoveOp::DOUBLE);
|
||||
if (type == MoveOp::FLOAT32)
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Float32;
|
||||
else
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Double;
|
||||
|
||||
FloatRegister fdest;
|
||||
if (GetFloatArgReg(passedIntArgs_, passedFloatArgs_++, &fdest)) {
|
||||
if (!from.isFloatReg() || from.floatReg() != fdest)
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(fdest), type);
|
||||
return;
|
||||
}
|
||||
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(activeSP, stackForCall_), type);
|
||||
switch (type) {
|
||||
case MoveOp::FLOAT32: stackForCall_ += sizeof(float); break;
|
||||
case MoveOp::DOUBLE: stackForCall_ += sizeof(double); break;
|
||||
default: MOZ_CRASH("Unexpected float register class argument type");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::passABIArg(Register reg)
|
||||
{
|
||||
passABIArg(MoveOperand(reg), MoveOp::GENERAL);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::passABIArg(FloatRegister reg, MoveOp::Type type)
|
||||
{
|
||||
passABIArg(MoveOperand(reg), type);
|
||||
}
|
||||
void
|
||||
MacroAssemblerCompat::passABIOutParam(Register reg)
|
||||
{
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
MOZ_ASSERT(!usedOutParam_);
|
||||
usedOutParam_ = true;
|
||||
if (reg == r8)
|
||||
return;
|
||||
enoughMemory_ = moveResolver_.addMove(MoveOperand(reg), MoveOperand(r8), MoveOp::GENERAL);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::callWithABIPre(uint32_t* stackAdjust)
|
||||
{
|
||||
*stackAdjust = stackForCall_;
|
||||
// ARM64 /really/ wants the stack to always be aligned. Since we're already tracking it
|
||||
// getting it aligned for an abi call is pretty easy.
|
||||
*stackAdjust += ComputeByteAlignment(*stackAdjust, StackAlignment);
|
||||
asMasm().reserveStack(*stackAdjust);
|
||||
{
|
||||
moveResolver_.resolve();
|
||||
MoveEmitter emitter(asMasm());
|
||||
emitter.emit(moveResolver_);
|
||||
emitter.finish();
|
||||
}
|
||||
|
||||
// Call boundaries communicate stack via sp.
|
||||
syncStackPtr();
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
|
||||
{
|
||||
// Call boundaries communicate stack via sp.
|
||||
if (!GetStackPointer64().Is(sp))
|
||||
Mov(GetStackPointer64(), sp);
|
||||
|
||||
inCall_ = false;
|
||||
asMasm().freeStack(stackAdjust);
|
||||
|
||||
// Restore the stack pointer from entry.
|
||||
if (dynamicAlignment_)
|
||||
Ldr(GetStackPointer64(), MemOperand(GetStackPointer64(), 0));
|
||||
|
||||
// Restore LR.
|
||||
pop(lr);
|
||||
|
||||
// TODO: This one shouldn't be necessary -- check that callers
|
||||
// aren't enforcing the ABI themselves!
|
||||
syncStackPtr();
|
||||
|
||||
// If the ABI's return regs are where ION is expecting them, then
|
||||
// no other work needs to be done.
|
||||
}
|
||||
|
||||
#if defined(DEBUG) && defined(JS_SIMULATOR_ARM64)
|
||||
static void
|
||||
AssertValidABIFunctionType(uint32_t passedArgTypes)
|
||||
{
|
||||
switch (passedArgTypes) {
|
||||
case Args_General0:
|
||||
case Args_General1:
|
||||
case Args_General2:
|
||||
case Args_General3:
|
||||
case Args_General4:
|
||||
case Args_General5:
|
||||
case Args_General6:
|
||||
case Args_General7:
|
||||
case Args_General8:
|
||||
case Args_Double_None:
|
||||
case Args_Int_Double:
|
||||
case Args_Float32_Float32:
|
||||
case Args_Double_Double:
|
||||
case Args_Double_Int:
|
||||
case Args_Double_DoubleInt:
|
||||
case Args_Double_DoubleDouble:
|
||||
case Args_Double_DoubleDoubleDouble:
|
||||
case Args_Double_DoubleDoubleDoubleDouble:
|
||||
case Args_Double_IntDouble:
|
||||
case Args_Int_IntDouble:
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected type");
|
||||
}
|
||||
}
|
||||
#endif // DEBUG && JS_SIMULATOR_ARM64
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::callWithABI(void* fun, MoveOp::Type result)
|
||||
{
|
||||
#ifdef JS_SIMULATOR_ARM64
|
||||
MOZ_ASSERT(passedIntArgs_ + passedFloatArgs_ <= 15);
|
||||
passedArgTypes_ <<= ArgType_Shift;
|
||||
switch (result) {
|
||||
case MoveOp::GENERAL: passedArgTypes_ |= ArgType_General; break;
|
||||
case MoveOp::DOUBLE: passedArgTypes_ |= ArgType_Double; break;
|
||||
case MoveOp::FLOAT32: passedArgTypes_ |= ArgType_Float32; break;
|
||||
default: MOZ_CRASH("Invalid return type");
|
||||
}
|
||||
# ifdef DEBUG
|
||||
AssertValidABIFunctionType(passedArgTypes_);
|
||||
# endif
|
||||
ABIFunctionType type = ABIFunctionType(passedArgTypes_);
|
||||
fun = vixl::Simulator::RedirectNativeFunction(fun, type);
|
||||
#endif // JS_SIMULATOR_ARM64
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(ImmPtr(fun));
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::callWithABI(Register fun, MoveOp::Type result)
|
||||
{
|
||||
movePtr(fun, ip0);
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(ip0);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::callWithABI(AsmJSImmPtr imm, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(imm);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::callWithABI(Address fun, MoveOp::Type result)
|
||||
{
|
||||
loadPtr(fun, ip0);
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(ip0);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerCompat::branchPtrInNurseryRange(Condition cond, Register ptr, Register temp,
|
||||
Label* label)
|
||||
@ -754,6 +515,116 @@ MacroAssembler::call(JitCode* c)
|
||||
blr(scratch64);
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// ABI function calls.
|
||||
|
||||
void
|
||||
MacroAssembler::setupUnalignedABICall(Register scratch)
|
||||
{
|
||||
setupABICall();
|
||||
dynamicAlignment_ = true;
|
||||
|
||||
int64_t alignment = ~(int64_t(ABIStackAlignment) - 1);
|
||||
ARMRegister scratch64(scratch, 64);
|
||||
|
||||
// Always save LR -- Baseline ICs assume that LR isn't modified.
|
||||
push(lr);
|
||||
|
||||
// Unhandled for sp -- needs slightly different logic.
|
||||
MOZ_ASSERT(!GetStackPointer64().Is(sp));
|
||||
|
||||
// Remember the stack address on entry.
|
||||
Mov(scratch64, GetStackPointer64());
|
||||
|
||||
// Make alignment, including the effective push of the previous sp.
|
||||
Sub(GetStackPointer64(), GetStackPointer64(), Operand(8));
|
||||
And(GetStackPointer64(), GetStackPointer64(), Operand(alignment));
|
||||
|
||||
// If the PseudoStackPointer is used, sp must be <= psp before a write is valid.
|
||||
syncStackPtr();
|
||||
|
||||
// Store previous sp to the top of the stack, aligned.
|
||||
Str(scratch64, MemOperand(GetStackPointer64(), 0));
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABIPre(uint32_t* stackAdjust, bool callFromAsmJS)
|
||||
{
|
||||
MOZ_ASSERT(inCall_);
|
||||
uint32_t stackForCall = abiArgs_.stackBytesConsumedSoFar();
|
||||
|
||||
// ARM64 /really/ wants the stack to always be aligned. Since we're already tracking it
|
||||
// getting it aligned for an abi call is pretty easy.
|
||||
MOZ_ASSERT(dynamicAlignment_);
|
||||
stackForCall += ComputeByteAlignment(stackForCall, StackAlignment);
|
||||
*stackAdjust = stackForCall;
|
||||
reserveStack(*stackAdjust);
|
||||
{
|
||||
moveResolver_.resolve();
|
||||
MoveEmitter emitter(*this);
|
||||
emitter.emit(moveResolver_);
|
||||
emitter.finish();
|
||||
}
|
||||
|
||||
// Call boundaries communicate stack via sp.
|
||||
syncStackPtr();
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
|
||||
{
|
||||
// Call boundaries communicate stack via sp.
|
||||
if (!GetStackPointer64().Is(sp))
|
||||
Mov(GetStackPointer64(), sp);
|
||||
|
||||
freeStack(stackAdjust);
|
||||
|
||||
// Restore the stack pointer from entry.
|
||||
if (dynamicAlignment_)
|
||||
Ldr(GetStackPointer64(), MemOperand(GetStackPointer64(), 0));
|
||||
|
||||
// Restore LR.
|
||||
pop(lr);
|
||||
|
||||
// TODO: This one shouldn't be necessary -- check that callers
|
||||
// aren't enforcing the ABI themselves!
|
||||
syncStackPtr();
|
||||
|
||||
// If the ABI's return regs are where ION is expecting them, then
|
||||
// no other work needs to be done.
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(inCall_);
|
||||
inCall_ = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABINoProfiler(Register fun, MoveOp::Type result)
|
||||
{
|
||||
vixl::UseScratchRegisterScope temps(this);
|
||||
const Register scratch = temps.AcquireX().asUnsized();
|
||||
movePtr(fun, scratch);
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(scratch);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result)
|
||||
{
|
||||
vixl::UseScratchRegisterScope temps(this);
|
||||
const Register scratch = temps.AcquireX().asUnsized();
|
||||
loadPtr(fun, scratch);
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(scratch);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
//}}} check_macroassembler_style
|
||||
|
||||
} // namespace jit
|
||||
|
@ -59,29 +59,10 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
|
||||
bool enoughMemory_;
|
||||
uint32_t framePushed_;
|
||||
|
||||
// TODO: Can this be moved out of the MacroAssembler and into some shared code?
|
||||
// TODO: All the code seems to be arch-independent, and it's weird to have this here.
|
||||
bool inCall_;
|
||||
bool usedOutParam_;
|
||||
uint32_t args_;
|
||||
uint32_t passedIntArgs_;
|
||||
uint32_t passedFloatArgs_;
|
||||
uint32_t passedArgTypes_;
|
||||
uint32_t stackForCall_;
|
||||
bool dynamicAlignment_;
|
||||
|
||||
MacroAssemblerCompat()
|
||||
: vixl::MacroAssembler(),
|
||||
enoughMemory_(true),
|
||||
framePushed_(0),
|
||||
inCall_(false),
|
||||
usedOutParam_(false),
|
||||
args_(0),
|
||||
passedIntArgs_(0),
|
||||
passedFloatArgs_(0),
|
||||
passedArgTypes_(0),
|
||||
stackForCall_(0),
|
||||
dynamicAlignment_(false)
|
||||
framePushed_(0)
|
||||
{ }
|
||||
|
||||
protected:
|
||||
@ -2650,47 +2631,7 @@ class MacroAssemblerCompat : public vixl::MacroAssembler
|
||||
Add(dest64, dest64, Operand(address.offset));
|
||||
}
|
||||
|
||||
private:
|
||||
void setupABICall(uint32_t args);
|
||||
|
||||
public:
|
||||
// Setup a call to C/C++ code, given the number of general arguments it
|
||||
// takes. Note that this only supports cdecl.
|
||||
//
|
||||
// In order for alignment to work correctly, the MacroAssembler must have a
|
||||
// consistent view of the stack displacement. It is okay to call "push"
|
||||
// manually, however, if the stack alignment were to change, the macro
|
||||
// assembler should be notified before starting a call.
|
||||
void setupAlignedABICall(uint32_t args) {
|
||||
MOZ_CRASH("setupAlignedABICall");
|
||||
}
|
||||
|
||||
// Sets up an ABI call for when the alignment is not known. This may need a
|
||||
// scratch register.
|
||||
void setupUnalignedABICall(uint32_t args, Register scratch);
|
||||
|
||||
// Arguments must be assigned to a C/C++ call in order. They are moved
|
||||
// in parallel immediately before performing the call. This process may
|
||||
// temporarily use more stack, in which case sp-relative addresses will be
|
||||
// automatically adjusted. It is extremely important that sp-relative
|
||||
// addresses are computed *after* setupABICall(). Furthermore, no
|
||||
// operations should be emitted while setting arguments.
|
||||
void passABIArg(const MoveOperand& from, MoveOp::Type type);
|
||||
void passABIArg(Register reg);
|
||||
void passABIArg(FloatRegister reg, MoveOp::Type type);
|
||||
void passABIOutParam(Register reg);
|
||||
|
||||
private:
|
||||
void callWithABIPre(uint32_t* stackAdjust);
|
||||
void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result);
|
||||
|
||||
public:
|
||||
// Emits a call to a C/C++ function, resolving all argument moves.
|
||||
void callWithABI(void* fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(Register fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(Address fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
|
||||
CodeOffsetLabel labelForPatch() {
|
||||
return CodeOffsetLabel(nextOffset().getOffset());
|
||||
}
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "jit/arm64/SharedICHelpers-arm64.h"
|
||||
#include "jit/VMFunctions.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
@ -192,7 +194,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
||||
masm.push(BaselineFrameReg, reg_code);
|
||||
|
||||
// Initialize the frame, including filling in the slots.
|
||||
masm.setupUnalignedABICall(3, r19);
|
||||
masm.setupUnalignedABICall(r19);
|
||||
masm.passABIArg(BaselineFrameReg); // BaselineFrame.
|
||||
masm.passABIArg(reg_osrFrame); // InterpreterFrame.
|
||||
masm.passABIArg(reg_osrNStack);
|
||||
@ -293,7 +295,7 @@ JitRuntime::generateInvalidator(JSContext* cx)
|
||||
masm.Sub(x2, masm.GetStackPointer64(), Operand(sizeof(size_t) + sizeof(void*)));
|
||||
masm.moveToStackPtr(r2);
|
||||
|
||||
masm.setupUnalignedABICall(3, r10);
|
||||
masm.setupUnalignedABICall(r10);
|
||||
masm.passABIArg(r0);
|
||||
masm.passABIArg(r1);
|
||||
masm.passABIArg(r2);
|
||||
@ -494,7 +496,7 @@ GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass)
|
||||
masm.reserveStack(sizeOfBailoutInfo);
|
||||
masm.moveStackPtrTo(r1);
|
||||
|
||||
masm.setupUnalignedABICall(2, r2);
|
||||
masm.setupUnalignedABICall(r2);
|
||||
masm.passABIArg(r0);
|
||||
masm.passABIArg(r1);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
|
||||
@ -634,7 +636,7 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
||||
break;
|
||||
}
|
||||
|
||||
masm.setupUnalignedABICall(f.argc(), regs.getAny());
|
||||
masm.setupUnalignedABICall(regs.getAny());
|
||||
masm.passABIArg(reg_cx);
|
||||
|
||||
size_t argDisp = 0;
|
||||
@ -761,7 +763,7 @@ JitRuntime::generatePreBarrier(JSContext* cx, MIRType type)
|
||||
MOZ_ASSERT(PreBarrierReg == r1);
|
||||
masm.movePtr(ImmPtr(cx->runtime()), r3);
|
||||
|
||||
masm.setupUnalignedABICall(2, r0);
|
||||
masm.setupUnalignedABICall(r0);
|
||||
masm.passABIArg(r3);
|
||||
masm.passABIArg(PreBarrierReg);
|
||||
masm.callWithABI(IonMarkFunction(type));
|
||||
|
@ -534,6 +534,12 @@ hasMultiAlias() {
|
||||
return true;
|
||||
}
|
||||
|
||||
// In order to handle functions such as int(*)(int, double) where the first
|
||||
// argument is a general purpose register, and the second argument is a floating
|
||||
// point register, we have to store the double content into 2 general purpose
|
||||
// registers, namely a2 and a3.
|
||||
#define JS_CODEGEN_REGISTER_PAIR 1
|
||||
|
||||
// See the comments above AsmJSMappedSize in AsmJSValidate.h for more info.
|
||||
// TODO: Implement this for MIPS. Note that it requires Codegen to respect the
|
||||
// offset field of AsmJSHeapAccess.
|
||||
|
@ -23,18 +23,18 @@ using namespace js::jit;
|
||||
|
||||
ABIArgGenerator::ABIArgGenerator()
|
||||
: usedArgSlots_(0),
|
||||
firstArgFloat(false),
|
||||
firstArgFloatSize_(0),
|
||||
useGPRForFloats_(false),
|
||||
current_()
|
||||
{}
|
||||
|
||||
ABIArg
|
||||
ABIArgGenerator::next(MIRType type)
|
||||
{
|
||||
FloatRegister::RegType regType;
|
||||
Register destReg;
|
||||
switch (type) {
|
||||
case MIRType_Int32:
|
||||
case MIRType_Pointer:
|
||||
Register destReg;
|
||||
if (GetIntArgReg(usedArgSlots_, &destReg))
|
||||
current_ = ABIArg(destReg);
|
||||
else
|
||||
@ -42,19 +42,34 @@ ABIArgGenerator::next(MIRType type)
|
||||
usedArgSlots_++;
|
||||
break;
|
||||
case MIRType_Float32:
|
||||
case MIRType_Double:
|
||||
regType = (type == MIRType_Double ? FloatRegister::Double : FloatRegister::Single);
|
||||
if (!usedArgSlots_) {
|
||||
current_ = ABIArg(FloatRegister(FloatRegisters::f12, regType));
|
||||
usedArgSlots_ += 2;
|
||||
firstArgFloat = true;
|
||||
} else if (usedArgSlots_ <= 2) {
|
||||
// NOTE: We will use f14 always. This is not compatible with
|
||||
// system ABI. We will have to introduce some infrastructure
|
||||
// changes if we have to use system ABI here.
|
||||
current_ = ABIArg(FloatRegister(FloatRegisters::f14, regType));
|
||||
current_ = ABIArg(f12.asSingle());
|
||||
firstArgFloatSize_ = 1;
|
||||
} else if (usedArgSlots_ == firstArgFloatSize_) {
|
||||
current_ = ABIArg(f14.asSingle());
|
||||
} else if (useGPRForFloats_ && GetIntArgReg(usedArgSlots_, &destReg)) {
|
||||
current_ = ABIArg(destReg);
|
||||
} else {
|
||||
if (usedArgSlots_ < NumIntArgRegs)
|
||||
usedArgSlots_ = NumIntArgRegs;
|
||||
current_ = ABIArg(usedArgSlots_ * sizeof(intptr_t));
|
||||
}
|
||||
usedArgSlots_++;
|
||||
break;
|
||||
case MIRType_Double:
|
||||
if (!usedArgSlots_) {
|
||||
current_ = ABIArg(f12);
|
||||
usedArgSlots_ = 2;
|
||||
firstArgFloatSize_ = 2;
|
||||
} else if (usedArgSlots_ == firstArgFloatSize_) {
|
||||
current_ = ABIArg(f14);
|
||||
usedArgSlots_ = 4;
|
||||
} else if (useGPRForFloats_ && usedArgSlots_ <= 2) {
|
||||
current_ = ABIArg(a2, a3);
|
||||
usedArgSlots_ = 4;
|
||||
} else {
|
||||
if (usedArgSlots_ < NumIntArgRegs)
|
||||
usedArgSlots_ = NumIntArgRegs;
|
||||
usedArgSlots_ += usedArgSlots_ % 2;
|
||||
current_ = ABIArg(usedArgSlots_ * sizeof(intptr_t));
|
||||
usedArgSlots_ += 2;
|
||||
@ -64,8 +79,8 @@ ABIArgGenerator::next(MIRType type)
|
||||
MOZ_CRASH("Unexpected argument type");
|
||||
}
|
||||
return current_;
|
||||
|
||||
}
|
||||
|
||||
const Register ABIArgGenerator::NonArgReturnReg0 = t0;
|
||||
const Register ABIArgGenerator::NonArgReturnReg1 = t1;
|
||||
const Register ABIArgGenerator::NonArg_VolatileReg = v0;
|
||||
|
@ -80,7 +80,10 @@ static const uint32_t NumCallTempNonArgRegs = mozilla::ArrayLength(CallTempNonAr
|
||||
class ABIArgGenerator
|
||||
{
|
||||
unsigned usedArgSlots_;
|
||||
bool firstArgFloat;
|
||||
unsigned firstArgFloatSize_;
|
||||
// Note: This is not compliant with the system ABI. The Lowering phase
|
||||
// expects to lower an MAsmJSParameter to only one register.
|
||||
bool useGPRForFloats_;
|
||||
ABIArg current_;
|
||||
|
||||
public:
|
||||
@ -88,6 +91,10 @@ class ABIArgGenerator
|
||||
ABIArg next(MIRType argType);
|
||||
ABIArg& current() { return current_; }
|
||||
|
||||
void enforceO32ABI() {
|
||||
useGPRForFloats_ = true;
|
||||
}
|
||||
|
||||
uint32_t stackBytesConsumedSoFar() const {
|
||||
if (usedArgSlots_ <= 4)
|
||||
return ShadowStackSpace;
|
||||
|
@ -2120,7 +2120,7 @@ CodeGeneratorMIPS::visitRandom(LRandom* ins)
|
||||
|
||||
masm.loadJSContext(temp);
|
||||
|
||||
masm.setupUnalignedABICall(1, temp2);
|
||||
masm.setupUnalignedABICall(temp2);
|
||||
masm.passABIArg(temp);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE);
|
||||
|
||||
|
@ -3148,133 +3148,6 @@ MacroAssemblerMIPSCompat::ensureDouble(const ValueOperand& source, FloatRegister
|
||||
bind(&done);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::setupABICall(uint32_t args)
|
||||
{
|
||||
MOZ_ASSERT(!inCall_);
|
||||
inCall_ = true;
|
||||
args_ = args;
|
||||
passedArgs_ = 0;
|
||||
passedArgTypes_ = 0;
|
||||
|
||||
usedArgSlots_ = 0;
|
||||
firstArgType = MoveOp::GENERAL;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::setupAlignedABICall(uint32_t args)
|
||||
{
|
||||
setupABICall(args);
|
||||
|
||||
dynamicAlignment_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::setupUnalignedABICall(uint32_t args, Register scratch)
|
||||
{
|
||||
setupABICall(args);
|
||||
dynamicAlignment_ = true;
|
||||
|
||||
ma_move(scratch, StackPointer);
|
||||
|
||||
// Force sp to be aligned
|
||||
ma_subu(StackPointer, StackPointer, Imm32(sizeof(uint32_t)));
|
||||
ma_and(StackPointer, StackPointer, Imm32(~(ABIStackAlignment - 1)));
|
||||
as_sw(scratch, StackPointer, 0);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::passABIArg(const MoveOperand& from, MoveOp::Type type)
|
||||
{
|
||||
++passedArgs_;
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
switch (type) {
|
||||
case MoveOp::FLOAT32:
|
||||
if (!usedArgSlots_) {
|
||||
if (from.floatReg() != f12)
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f12), type);
|
||||
firstArgType = MoveOp::FLOAT32;
|
||||
} else if ((usedArgSlots_ == 1 && firstArgType == MoveOp::FLOAT32) ||
|
||||
(usedArgSlots_ == 2 && firstArgType == MoveOp::DOUBLE)) {
|
||||
if (from.floatReg() != f14)
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f14), type);
|
||||
} else {
|
||||
Register destReg;
|
||||
if (GetIntArgReg(usedArgSlots_, &destReg)) {
|
||||
if (from.isGeneralReg() && from.reg() == destReg) {
|
||||
// Nothing to do. Value is in the right register already
|
||||
} else {
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(destReg), type);
|
||||
}
|
||||
} else {
|
||||
uint32_t disp = GetArgStackDisp(usedArgSlots_);
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), type);
|
||||
}
|
||||
}
|
||||
usedArgSlots_++;
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Float32;
|
||||
break;
|
||||
case MoveOp::DOUBLE:
|
||||
if (!usedArgSlots_) {
|
||||
if (from.floatReg() != f12)
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f12), type);
|
||||
usedArgSlots_ = 2;
|
||||
firstArgType = MoveOp::DOUBLE;
|
||||
} else if (usedArgSlots_ <= 2) {
|
||||
if ((usedArgSlots_ == 1 && firstArgType == MoveOp::FLOAT32) ||
|
||||
(usedArgSlots_ == 2 && firstArgType == MoveOp::DOUBLE)) {
|
||||
if (from.floatReg() != f14)
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(f14), type);
|
||||
} else {
|
||||
// Create two moves so that cycles are found. Move emitter
|
||||
// will have special case to handle this.
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(a2), type);
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(a3), type);
|
||||
}
|
||||
usedArgSlots_ = 4;
|
||||
} else {
|
||||
// Align if necessary
|
||||
usedArgSlots_ += usedArgSlots_ % 2;
|
||||
|
||||
uint32_t disp = GetArgStackDisp(usedArgSlots_);
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), type);
|
||||
usedArgSlots_ += 2;
|
||||
}
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_Double;
|
||||
break;
|
||||
case MoveOp::GENERAL:
|
||||
Register destReg;
|
||||
if (GetIntArgReg(usedArgSlots_, &destReg)) {
|
||||
if (from.isGeneralReg() && from.reg() == destReg) {
|
||||
// Nothing to do. Value is in the right register already
|
||||
} else {
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(destReg), type);
|
||||
}
|
||||
} else {
|
||||
uint32_t disp = GetArgStackDisp(usedArgSlots_);
|
||||
enoughMemory_ = moveResolver_.addMove(from, MoveOperand(sp, disp), type);
|
||||
}
|
||||
usedArgSlots_++;
|
||||
passedArgTypes_ = (passedArgTypes_ << ArgType_Shift) | ArgType_General;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected argument type");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::passABIArg(Register reg)
|
||||
{
|
||||
passABIArg(MoveOperand(reg), MoveOp::GENERAL);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::passABIArg(FloatRegister freg, MoveOp::Type type)
|
||||
{
|
||||
passABIArg(MoveOperand(freg), type);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::checkStackAlignment()
|
||||
{
|
||||
@ -3322,158 +3195,6 @@ MacroAssembler::restoreFrameAlignmentForICArguments(AfterICSaveLive& aic)
|
||||
freeStack(aic.alignmentPadding);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::callWithABIPre(uint32_t* stackAdjust, bool callFromAsmJS)
|
||||
{
|
||||
MOZ_ASSERT(inCall_);
|
||||
|
||||
// Reserve place for $ra.
|
||||
*stackAdjust = sizeof(intptr_t);
|
||||
|
||||
*stackAdjust += usedArgSlots_ > NumIntArgRegs ?
|
||||
usedArgSlots_ * sizeof(intptr_t) :
|
||||
NumIntArgRegs * sizeof(intptr_t);
|
||||
|
||||
uint32_t alignmentAtPrologue = callFromAsmJS ? sizeof(AsmJSFrame) : 0;
|
||||
|
||||
if (dynamicAlignment_) {
|
||||
*stackAdjust += ComputeByteAlignment(*stackAdjust, ABIStackAlignment);
|
||||
} else {
|
||||
*stackAdjust += ComputeByteAlignment(asMasm().framePushed() + alignmentAtPrologue + *stackAdjust,
|
||||
ABIStackAlignment);
|
||||
}
|
||||
|
||||
asMasm().reserveStack(*stackAdjust);
|
||||
|
||||
// Save $ra because call is going to clobber it. Restore it in
|
||||
// callWithABIPost. NOTE: This is needed for calls from BaselineIC.
|
||||
// Maybe we can do this differently.
|
||||
ma_sw(ra, Address(StackPointer, *stackAdjust - sizeof(intptr_t)));
|
||||
|
||||
// Position all arguments.
|
||||
{
|
||||
enoughMemory_ = enoughMemory_ && moveResolver_.resolve();
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
|
||||
MoveEmitter emitter(asMasm());
|
||||
emitter.emit(moveResolver_);
|
||||
emitter.finish();
|
||||
}
|
||||
|
||||
checkStackAlignment();
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
|
||||
{
|
||||
// Restore ra value (as stored in callWithABIPre()).
|
||||
ma_lw(ra, Address(StackPointer, stackAdjust - sizeof(intptr_t)));
|
||||
|
||||
if (dynamicAlignment_) {
|
||||
// Restore sp value from stack (as stored in setupUnalignedABICall()).
|
||||
ma_lw(StackPointer, Address(StackPointer, stackAdjust));
|
||||
// Use adjustFrame instead of freeStack because we already restored sp.
|
||||
asMasm().adjustFrame(-stackAdjust);
|
||||
} else {
|
||||
asMasm().freeStack(stackAdjust);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(inCall_);
|
||||
inCall_ = false;
|
||||
}
|
||||
|
||||
#if defined(DEBUG) && defined(JS_SIMULATOR_MIPS32)
|
||||
static void
|
||||
AssertValidABIFunctionType(uint32_t passedArgTypes)
|
||||
{
|
||||
switch (passedArgTypes) {
|
||||
case Args_General0:
|
||||
case Args_General1:
|
||||
case Args_General2:
|
||||
case Args_General3:
|
||||
case Args_General4:
|
||||
case Args_General5:
|
||||
case Args_General6:
|
||||
case Args_General7:
|
||||
case Args_General8:
|
||||
case Args_Double_None:
|
||||
case Args_Int_Double:
|
||||
case Args_Float32_Float32:
|
||||
case Args_Double_Double:
|
||||
case Args_Double_Int:
|
||||
case Args_Double_DoubleInt:
|
||||
case Args_Double_DoubleDouble:
|
||||
case Args_Double_IntDouble:
|
||||
case Args_Int_IntDouble:
|
||||
case Args_Double_DoubleDoubleDouble:
|
||||
case Args_Double_DoubleDoubleDoubleDouble:
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Unexpected type");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::callWithABI(void* fun, MoveOp::Type result)
|
||||
{
|
||||
#ifdef JS_SIMULATOR_MIPS32
|
||||
MOZ_ASSERT(passedArgs_ <= 15);
|
||||
passedArgTypes_ <<= ArgType_Shift;
|
||||
switch (result) {
|
||||
case MoveOp::GENERAL: passedArgTypes_ |= ArgType_General; break;
|
||||
case MoveOp::DOUBLE: passedArgTypes_ |= ArgType_Double; break;
|
||||
case MoveOp::FLOAT32: passedArgTypes_ |= ArgType_Float32; break;
|
||||
default: MOZ_CRASH("Invalid return type");
|
||||
}
|
||||
#ifdef DEBUG
|
||||
AssertValidABIFunctionType(passedArgTypes_);
|
||||
#endif
|
||||
ABIFunctionType type = ABIFunctionType(passedArgTypes_);
|
||||
fun = Simulator::RedirectNativeFunction(fun, type);
|
||||
#endif
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
ma_call(ImmPtr(fun));
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::callWithABI(AsmJSImmPtr imm, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust, /* callFromAsmJS = */ true);
|
||||
asMasm().call(imm);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::callWithABI(const Address& fun, MoveOp::Type result)
|
||||
{
|
||||
// Load the callee in t9, no instruction between the lw and call
|
||||
// should clobber it. Note that we can't use fun.base because it may
|
||||
// be one of the IntArg registers clobbered before the call.
|
||||
ma_lw(t9, Address(fun.base, fun.offset));
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(t9);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::callWithABI(Register fun, MoveOp::Type result)
|
||||
{
|
||||
// Load the callee in t9, as above.
|
||||
ma_move(t9, fun);
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(t9);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::handleFailureWithHandlerTail(void* handler)
|
||||
{
|
||||
@ -3483,9 +3204,9 @@ MacroAssemblerMIPSCompat::handleFailureWithHandlerTail(void* handler)
|
||||
ma_move(a0, StackPointer); // Use a0 since it is a first function argument
|
||||
|
||||
// Call the handler.
|
||||
setupUnalignedABICall(1, a1);
|
||||
passABIArg(a0);
|
||||
callWithABI(handler);
|
||||
asMasm().setupUnalignedABICall(a1);
|
||||
asMasm().passABIArg(a0);
|
||||
asMasm().callWithABI(handler);
|
||||
|
||||
Label entryFrame;
|
||||
Label catch_;
|
||||
@ -3824,4 +3545,105 @@ MacroAssembler::call(JitCode* c)
|
||||
ma_callJitHalfPush(ScratchRegister);
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// ABI function calls.
|
||||
|
||||
void
|
||||
MacroAssembler::setupUnalignedABICall(Register scratch)
|
||||
{
|
||||
setupABICall();
|
||||
dynamicAlignment_ = true;
|
||||
|
||||
ma_move(scratch, StackPointer);
|
||||
|
||||
// Force sp to be aligned
|
||||
ma_subu(StackPointer, StackPointer, Imm32(sizeof(uint32_t)));
|
||||
ma_and(StackPointer, StackPointer, Imm32(~(ABIStackAlignment - 1)));
|
||||
as_sw(scratch, StackPointer, 0);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABIPre(uint32_t* stackAdjust, bool callFromAsmJS)
|
||||
{
|
||||
MOZ_ASSERT(inCall_);
|
||||
uint32_t stackForCall = abiArgs_.stackBytesConsumedSoFar();
|
||||
|
||||
// Reserve place for $ra.
|
||||
stackForCall += sizeof(intptr_t);
|
||||
|
||||
if (dynamicAlignment_) {
|
||||
stackForCall += ComputeByteAlignment(stackForCall, ABIStackAlignment);
|
||||
} else {
|
||||
uint32_t alignmentAtPrologue = callFromAsmJS ? sizeof(AsmJSFrame) : 0;
|
||||
stackForCall += ComputeByteAlignment(stackForCall + framePushed() + alignmentAtPrologue,
|
||||
ABIStackAlignment);
|
||||
}
|
||||
|
||||
*stackAdjust = stackForCall;
|
||||
reserveStack(stackForCall);
|
||||
|
||||
// Save $ra because call is going to clobber it. Restore it in
|
||||
// callWithABIPost. NOTE: This is needed for calls from BaselineIC.
|
||||
// Maybe we can do this differently.
|
||||
ma_sw(ra, Address(StackPointer, stackForCall - sizeof(intptr_t)));
|
||||
|
||||
// Position all arguments.
|
||||
{
|
||||
enoughMemory_ = enoughMemory_ && moveResolver_.resolve();
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
|
||||
MoveEmitter emitter(*this);
|
||||
emitter.emit(moveResolver_);
|
||||
emitter.finish();
|
||||
}
|
||||
|
||||
assertStackAlignment(ABIStackAlignment);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
|
||||
{
|
||||
// Restore ra value (as stored in callWithABIPre()).
|
||||
ma_lw(ra, Address(StackPointer, stackAdjust - sizeof(intptr_t)));
|
||||
|
||||
if (dynamicAlignment_) {
|
||||
// Restore sp value from stack (as stored in setupUnalignedABICall()).
|
||||
ma_lw(StackPointer, Address(StackPointer, stackAdjust));
|
||||
// Use adjustFrame instead of freeStack because we already restored sp.
|
||||
adjustFrame(-stackAdjust);
|
||||
} else {
|
||||
freeStack(stackAdjust);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(inCall_);
|
||||
inCall_ = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABINoProfiler(Register fun, MoveOp::Type result)
|
||||
{
|
||||
// Load the callee in t9, no instruction between the lw and call
|
||||
// should clobber it. Note that we can't use fun.base because it may
|
||||
// be one of the IntArg registers clobbered before the call.
|
||||
ma_move(t9, fun);
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(t9);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result)
|
||||
{
|
||||
// Load the callee in t9, as above.
|
||||
ma_lw(t9, Address(fun.base, fun.offset));
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(t9);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
//}}} check_macroassembler_style
|
||||
|
@ -352,34 +352,8 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
|
||||
MacroAssembler& asMasm();
|
||||
const MacroAssembler& asMasm() const;
|
||||
|
||||
private:
|
||||
// Number of bytes the stack is adjusted inside a call to C. Calls to C may
|
||||
// not be nested.
|
||||
bool inCall_;
|
||||
uint32_t args_;
|
||||
// The actual number of arguments that were passed, used to assert that
|
||||
// the initial number of arguments declared was correct.
|
||||
uint32_t passedArgs_;
|
||||
uint32_t passedArgTypes_;
|
||||
|
||||
uint32_t usedArgSlots_;
|
||||
MoveOp::Type firstArgType;
|
||||
|
||||
bool dynamicAlignment_;
|
||||
|
||||
// Compute space needed for the function call and set the properties of the
|
||||
// callee. It returns the space which has to be allocated for calling the
|
||||
// function.
|
||||
//
|
||||
// arg Number of arguments of the function.
|
||||
void setupABICall(uint32_t arg);
|
||||
|
||||
protected:
|
||||
MoveResolver moveResolver_;
|
||||
|
||||
public:
|
||||
MacroAssemblerMIPSCompat()
|
||||
: inCall_(false)
|
||||
{ }
|
||||
|
||||
public:
|
||||
@ -1418,43 +1392,10 @@ public:
|
||||
ma_cmp_set(dest, lhs, rhs, cond);
|
||||
}
|
||||
|
||||
// Setup a call to C/C++ code, given the number of general arguments it
|
||||
// takes. Note that this only supports cdecl.
|
||||
//
|
||||
// In order for alignment to work correctly, the MacroAssembler must have a
|
||||
// consistent view of the stack displacement. It is okay to call "push"
|
||||
// manually, however, if the stack alignment were to change, the macro
|
||||
// assembler should be notified before starting a call.
|
||||
void setupAlignedABICall(uint32_t args);
|
||||
|
||||
// Sets up an ABI call for when the alignment is not known. This may need a
|
||||
// scratch register.
|
||||
void setupUnalignedABICall(uint32_t args, Register scratch);
|
||||
|
||||
// Arguments must be assigned in a left-to-right order. This process may
|
||||
// temporarily use more stack, in which case sp-relative addresses will be
|
||||
// automatically adjusted. It is extremely important that sp-relative
|
||||
// addresses are computed *after* setupABICall(). Furthermore, no
|
||||
// operations should be emitted while setting arguments.
|
||||
void passABIArg(const MoveOperand& from, MoveOp::Type type);
|
||||
void passABIArg(Register reg);
|
||||
void passABIArg(FloatRegister reg, MoveOp::Type type);
|
||||
void passABIArg(const ValueOperand& regs);
|
||||
|
||||
protected:
|
||||
bool buildOOLFakeExitFrame(void* fakeReturnAddr);
|
||||
|
||||
private:
|
||||
void callWithABIPre(uint32_t* stackAdjust, bool callFromAsmJS = false);
|
||||
void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result);
|
||||
|
||||
public:
|
||||
// Emits a call to a C/C++ function, resolving all argument moves.
|
||||
void callWithABI(void* fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(const Address& fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(Register fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
|
||||
CodeOffsetLabel labelForPatch() {
|
||||
return CodeOffsetLabel(nextOffset().getOffset());
|
||||
}
|
||||
|
@ -255,16 +255,14 @@ MoveEmitterMIPS::emitDoubleMove(const MoveOperand& from, const MoveOperand& to)
|
||||
if (from.isFloatReg()) {
|
||||
if (to.isFloatReg()) {
|
||||
masm.moveDouble(from.floatReg(), to.floatReg());
|
||||
} else if (to.isGeneralReg()) {
|
||||
} else if (to.isGeneralRegPair()) {
|
||||
// Used for passing double parameter in a2,a3 register pair.
|
||||
// Two moves are added for one double parameter by
|
||||
// MacroAssemblerMIPSCompat::passABIArg
|
||||
if(to.reg() == a2)
|
||||
masm.moveFromDoubleLo(from.floatReg(), a2);
|
||||
else if(to.reg() == a3)
|
||||
masm.moveFromDoubleHi(from.floatReg(), a3);
|
||||
else
|
||||
MOZ_CRASH("Invalid emitDoubleMove arguments.");
|
||||
// MacroAssembler::passABIArg
|
||||
MOZ_ASSERT(to.evenReg() == a2 && to.oddReg() == a3,
|
||||
"Invalid emitDoubleMove arguments.");
|
||||
masm.moveFromDoubleLo(from.floatReg(), a2);
|
||||
masm.moveFromDoubleHi(from.floatReg(), a3);
|
||||
} else {
|
||||
MOZ_ASSERT(to.isMemory());
|
||||
masm.storeDouble(from.floatReg(), getAdjustedAddress(to));
|
||||
@ -272,24 +270,15 @@ MoveEmitterMIPS::emitDoubleMove(const MoveOperand& from, const MoveOperand& to)
|
||||
} else if (to.isFloatReg()) {
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
masm.loadDouble(getAdjustedAddress(from), to.floatReg());
|
||||
} else if (to.isGeneralReg()) {
|
||||
} else if (to.isGeneralRegPair()) {
|
||||
// Used for passing double parameter in a2,a3 register pair.
|
||||
// Two moves are added for one double parameter by
|
||||
// MacroAssemblerMIPSCompat::passABIArg
|
||||
if (from.isMemory()) {
|
||||
if(to.reg() == a2)
|
||||
masm.loadPtr(getAdjustedAddress(from), a2);
|
||||
else if(to.reg() == a3)
|
||||
masm.loadPtr(Address(from.base(), getAdjustedOffset(from) + sizeof(uint32_t)), a3);
|
||||
else
|
||||
MOZ_CRASH("Invalid emitDoubleMove arguments.");
|
||||
} else {
|
||||
// Used for moving a double parameter from the same source. See Bug 1123874.
|
||||
if(to.reg() == a2 || to.reg() == a3)
|
||||
masm.ma_move(to.reg(), from.reg());
|
||||
else
|
||||
MOZ_CRASH("Invalid emitDoubleMove arguments.");
|
||||
}
|
||||
// MacroAssembler::passABIArg
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
MOZ_ASSERT(to.evenReg() == a2 && to.oddReg() == a3,
|
||||
"Invalid emitDoubleMove arguments.");
|
||||
masm.loadPtr(getAdjustedAddress(from), a2);
|
||||
masm.loadPtr(Address(from.base(), getAdjustedOffset(from) + sizeof(uint32_t)), a3);
|
||||
} else {
|
||||
MOZ_ASSERT(from.isMemory());
|
||||
MOZ_ASSERT(to.isMemory());
|
||||
|
@ -247,7 +247,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
||||
masm.storePtr(framePtr, Address(StackPointer, sizeof(uintptr_t))); // BaselineFrame
|
||||
masm.storePtr(reg_code, Address(StackPointer, 0)); // jitcode
|
||||
|
||||
masm.setupUnalignedABICall(3, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.passABIArg(BaselineFrameReg); // BaselineFrame
|
||||
masm.passABIArg(OsrFrameReg); // InterpreterFrame
|
||||
masm.passABIArg(numStackValues);
|
||||
@ -374,7 +374,7 @@ JitRuntime::generateInvalidator(JSContext* cx)
|
||||
// Pass pointer to BailoutInfo
|
||||
masm.movePtr(StackPointer, a2);
|
||||
|
||||
masm.setupAlignedABICall(3);
|
||||
masm.setupAlignedABICall();
|
||||
masm.passABIArg(a0);
|
||||
masm.passABIArg(a1);
|
||||
masm.passABIArg(a2);
|
||||
@ -610,7 +610,7 @@ GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass)
|
||||
masm.storePtr(ImmPtr(nullptr), Address(StackPointer, 0));
|
||||
masm.movePtr(StackPointer, a1);
|
||||
|
||||
masm.setupAlignedABICall(2);
|
||||
masm.setupAlignedABICall();
|
||||
masm.passABIArg(a0);
|
||||
masm.passABIArg(a1);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
|
||||
@ -766,7 +766,7 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
||||
masm.reserveStack(outParamOffset);
|
||||
masm.movePtr(StackPointer, doubleArgs);
|
||||
|
||||
masm.setupAlignedABICall(f.argc());
|
||||
masm.setupAlignedABICall();
|
||||
masm.passABIArg(cxreg);
|
||||
|
||||
size_t argDisp = 0;
|
||||
@ -910,7 +910,7 @@ JitRuntime::generatePreBarrier(JSContext* cx, MIRType type)
|
||||
MOZ_ASSERT(PreBarrierReg == a1);
|
||||
masm.movePtr(ImmPtr(cx->runtime()), a0);
|
||||
|
||||
masm.setupUnalignedABICall(2, a2);
|
||||
masm.setupUnalignedABICall(a2);
|
||||
masm.passABIArg(a0);
|
||||
masm.passABIArg(a1);
|
||||
masm.callWithABI(IonMarkFunction(type));
|
||||
|
@ -195,13 +195,8 @@ class MacroAssemblerNone : public Assembler
|
||||
|
||||
template <typename T> void call(T) { MOZ_CRASH(); }
|
||||
template <typename T, typename S> void call(T, S) { MOZ_CRASH(); }
|
||||
template <typename T> void callWithABI(T, MoveOp::Type v = MoveOp::GENERAL) { MOZ_CRASH(); }
|
||||
void callAndPushReturnAddress(Label* label) { MOZ_CRASH(); }
|
||||
|
||||
void setupAlignedABICall(uint32_t) { MOZ_CRASH(); }
|
||||
void setupUnalignedABICall(uint32_t, Register) { MOZ_CRASH(); }
|
||||
template <typename T> void passABIArg(T, MoveOp::Type v = MoveOp::GENERAL) { MOZ_CRASH(); }
|
||||
|
||||
void callWithExitFrame(Label*) { MOZ_CRASH(); }
|
||||
void callWithExitFrame(JitCode*) { MOZ_CRASH(); }
|
||||
void callWithExitFrame(JitCode*, Register) { MOZ_CRASH(); }
|
||||
|
@ -1451,7 +1451,7 @@ CodeGeneratorShared::visitOutOfLineTruncateSlow(OutOfLineTruncateSlow* ool)
|
||||
}
|
||||
#endif
|
||||
|
||||
masm.setupUnalignedABICall(1, dest);
|
||||
masm.setupUnalignedABICall(dest);
|
||||
masm.passABIArg(src, MoveOp::DOUBLE);
|
||||
if (gen->compilingAsmJS())
|
||||
masm.callWithABI(AsmJSImm_ToInt32);
|
||||
|
@ -11,6 +11,7 @@
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
#include "jit/shared/CodeGenerator-shared-inl.h"
|
||||
|
||||
using namespace js;
|
||||
@ -980,7 +981,7 @@ CodeGeneratorX64::visitOutOfLineRandom(OutOfLineRandom* ool)
|
||||
|
||||
masm.loadJSContext(temp);
|
||||
|
||||
masm.setupUnalignedABICall(1, temp2);
|
||||
masm.setupUnalignedABICall(temp2);
|
||||
masm.passABIArg(temp);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE);
|
||||
|
||||
|
@ -183,212 +183,6 @@ MacroAssemblerX64::finish()
|
||||
MacroAssemblerX86Shared::finish();
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::setupABICall(uint32_t args)
|
||||
{
|
||||
MOZ_ASSERT(!inCall_);
|
||||
inCall_ = true;
|
||||
|
||||
args_ = args;
|
||||
passedIntArgs_ = 0;
|
||||
passedFloatArgs_ = 0;
|
||||
stackForCall_ = ShadowStackSpace;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::setupAlignedABICall(uint32_t args)
|
||||
{
|
||||
setupABICall(args);
|
||||
dynamicAlignment_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::setupUnalignedABICall(uint32_t args, Register scratch)
|
||||
{
|
||||
setupABICall(args);
|
||||
dynamicAlignment_ = true;
|
||||
|
||||
movq(rsp, scratch);
|
||||
andq(Imm32(~(ABIStackAlignment - 1)), rsp);
|
||||
push(scratch);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::passABIArg(const MoveOperand& from, MoveOp::Type type)
|
||||
{
|
||||
MoveOperand to;
|
||||
switch (type) {
|
||||
case MoveOp::FLOAT32:
|
||||
case MoveOp::DOUBLE: {
|
||||
FloatRegister dest;
|
||||
if (GetFloatArgReg(passedIntArgs_, passedFloatArgs_++, &dest)) {
|
||||
// Convert to the right type of register.
|
||||
if (type == MoveOp::FLOAT32)
|
||||
dest = dest.asSingle();
|
||||
if (from.isFloatReg() && from.floatReg() == dest) {
|
||||
// Nothing to do; the value is in the right register already
|
||||
return;
|
||||
}
|
||||
to = MoveOperand(dest);
|
||||
} else {
|
||||
to = MoveOperand(StackPointer, stackForCall_);
|
||||
switch (type) {
|
||||
case MoveOp::FLOAT32: stackForCall_ += sizeof(float); break;
|
||||
case MoveOp::DOUBLE: stackForCall_ += sizeof(double); break;
|
||||
default: MOZ_CRASH("Unexpected float register class argument type");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MoveOp::GENERAL: {
|
||||
Register dest;
|
||||
if (GetIntArgReg(passedIntArgs_++, passedFloatArgs_, &dest)) {
|
||||
if (from.isGeneralReg() && from.reg() == dest) {
|
||||
// Nothing to do; the value is in the right register already
|
||||
return;
|
||||
}
|
||||
to = MoveOperand(dest);
|
||||
} else {
|
||||
to = MoveOperand(StackPointer, stackForCall_);
|
||||
stackForCall_ += sizeof(int64_t);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Unexpected argument type");
|
||||
}
|
||||
|
||||
enoughMemory_ = moveResolver_.addMove(from, to, type);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::passABIArg(Register reg)
|
||||
{
|
||||
passABIArg(MoveOperand(reg), MoveOp::GENERAL);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::passABIArg(FloatRegister reg, MoveOp::Type type)
|
||||
{
|
||||
passABIArg(MoveOperand(reg), type);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::callWithABIPre(uint32_t* stackAdjust)
|
||||
{
|
||||
MOZ_ASSERT(inCall_);
|
||||
MOZ_ASSERT(args_ == passedIntArgs_ + passedFloatArgs_);
|
||||
|
||||
if (dynamicAlignment_) {
|
||||
*stackAdjust = stackForCall_
|
||||
+ ComputeByteAlignment(stackForCall_ + sizeof(intptr_t),
|
||||
ABIStackAlignment);
|
||||
} else {
|
||||
*stackAdjust = stackForCall_
|
||||
+ ComputeByteAlignment(stackForCall_ + asMasm().framePushed(),
|
||||
ABIStackAlignment);
|
||||
}
|
||||
|
||||
asMasm().reserveStack(*stackAdjust);
|
||||
|
||||
// Position all arguments.
|
||||
{
|
||||
enoughMemory_ &= moveResolver_.resolve();
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
|
||||
MoveEmitter emitter(asMasm());
|
||||
emitter.emit(moveResolver_);
|
||||
emitter.finish();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
Label good;
|
||||
testPtr(rsp, Imm32(ABIStackAlignment - 1));
|
||||
j(Equal, &good);
|
||||
breakpoint();
|
||||
bind(&good);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
|
||||
{
|
||||
asMasm().freeStack(stackAdjust);
|
||||
if (dynamicAlignment_)
|
||||
pop(rsp);
|
||||
|
||||
MOZ_ASSERT(inCall_);
|
||||
inCall_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::callWithABI(void* fun, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(ImmPtr(fun));
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::callWithABI(AsmJSImmPtr imm, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(imm);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsIntArgReg(Register reg)
|
||||
{
|
||||
for (uint32_t i = 0; i < NumIntArgRegs; i++) {
|
||||
if (IntArgRegs[i] == reg)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::callWithABI(Address fun, MoveOp::Type result)
|
||||
{
|
||||
if (IsIntArgReg(fun.base)) {
|
||||
// Callee register may be clobbered for an argument. Move the callee to
|
||||
// r10, a volatile, non-argument register.
|
||||
moveResolver_.addMove(MoveOperand(fun.base), MoveOperand(r10), MoveOp::GENERAL);
|
||||
fun.base = r10;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!IsIntArgReg(fun.base));
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(fun);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::callWithABI(Register fun, MoveOp::Type result)
|
||||
{
|
||||
if (IsIntArgReg(fun)) {
|
||||
// Callee register may be clobbered for an argument. Move the callee to
|
||||
// r10, a volatile, non-argument register.
|
||||
moveResolver_.addMove(MoveOperand(fun), MoveOperand(r10), MoveOp::GENERAL);
|
||||
fun = r10;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!IsIntArgReg(fun));
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(fun);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX64::handleFailureWithHandlerTail(void* handler)
|
||||
{
|
||||
@ -397,9 +191,9 @@ MacroAssemblerX64::handleFailureWithHandlerTail(void* handler)
|
||||
movq(rsp, rax);
|
||||
|
||||
// Call the handler.
|
||||
setupUnalignedABICall(1, rcx);
|
||||
passABIArg(rax);
|
||||
callWithABI(handler);
|
||||
asMasm().setupUnalignedABICall(rcx);
|
||||
asMasm().passABIArg(rax);
|
||||
asMasm().callWithABI(handler);
|
||||
|
||||
Label entryFrame;
|
||||
Label catch_;
|
||||
@ -608,4 +402,115 @@ MacroAssembler::reserveStack(uint32_t amount)
|
||||
framePushed_ += amount;
|
||||
}
|
||||
|
||||
|
||||
// ===============================================================
|
||||
// ABI function calls.
|
||||
|
||||
void
|
||||
MacroAssembler::setupUnalignedABICall(Register scratch)
|
||||
{
|
||||
setupABICall();
|
||||
dynamicAlignment_ = true;
|
||||
|
||||
movq(rsp, scratch);
|
||||
andq(Imm32(~(ABIStackAlignment - 1)), rsp);
|
||||
push(scratch);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABIPre(uint32_t* stackAdjust, bool callFromAsmJS)
|
||||
{
|
||||
MOZ_ASSERT(inCall_);
|
||||
uint32_t stackForCall = abiArgs_.stackBytesConsumedSoFar();
|
||||
|
||||
if (dynamicAlignment_) {
|
||||
// sizeof(intptr_t) accounts for the saved stack pointer pushed by
|
||||
// setupUnalignedABICall.
|
||||
stackForCall += ComputeByteAlignment(stackForCall + sizeof(intptr_t),
|
||||
ABIStackAlignment);
|
||||
} else {
|
||||
static_assert(sizeof(AsmJSFrame) % ABIStackAlignment == 0,
|
||||
"AsmJSFrame should be part of the stack alignment.");
|
||||
stackForCall += ComputeByteAlignment(stackForCall + framePushed(),
|
||||
ABIStackAlignment);
|
||||
}
|
||||
|
||||
*stackAdjust = stackForCall;
|
||||
reserveStack(stackForCall);
|
||||
|
||||
// Position all arguments.
|
||||
{
|
||||
enoughMemory_ &= moveResolver_.resolve();
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
|
||||
MoveEmitter emitter(*this);
|
||||
emitter.emit(moveResolver_);
|
||||
emitter.finish();
|
||||
}
|
||||
|
||||
assertStackAlignment(ABIStackAlignment);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
|
||||
{
|
||||
freeStack(stackAdjust);
|
||||
if (dynamicAlignment_)
|
||||
pop(rsp);
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(inCall_);
|
||||
inCall_ = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool
|
||||
IsIntArgReg(Register reg)
|
||||
{
|
||||
for (uint32_t i = 0; i < NumIntArgRegs; i++) {
|
||||
if (IntArgRegs[i] == reg)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABINoProfiler(Register fun, MoveOp::Type result)
|
||||
{
|
||||
if (IsIntArgReg(fun)) {
|
||||
// Callee register may be clobbered for an argument. Move the callee to
|
||||
// r10, a volatile, non-argument register.
|
||||
moveResolver_.addMove(MoveOperand(fun), MoveOperand(r10), MoveOp::GENERAL);
|
||||
fun = r10;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!IsIntArgReg(fun));
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(fun);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result)
|
||||
{
|
||||
Address safeFun = fun;
|
||||
if (IsIntArgReg(safeFun.base)) {
|
||||
// Callee register may be clobbered for an argument. Move the callee to
|
||||
// r10, a volatile, non-argument register.
|
||||
moveResolver_.addMove(MoveOperand(fun.base), MoveOperand(r10), MoveOp::GENERAL);
|
||||
safeFun.base = r10;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!IsIntArgReg(safeFun.base));
|
||||
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(safeFun);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
//}}} check_macroassembler_style
|
||||
|
@ -40,15 +40,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
const MacroAssembler& asMasm() const;
|
||||
|
||||
private:
|
||||
// Number of bytes the stack is adjusted inside a call to C. Calls to C may
|
||||
// not be nested.
|
||||
bool inCall_;
|
||||
uint32_t args_;
|
||||
uint32_t passedIntArgs_;
|
||||
uint32_t passedFloatArgs_;
|
||||
uint32_t stackForCall_;
|
||||
bool dynamicAlignment_;
|
||||
|
||||
// These use SystemAllocPolicy since asm.js releases memory after each
|
||||
// function is compiled, and these need to live until after all functions
|
||||
// are compiled.
|
||||
@ -83,11 +74,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
typedef HashMap<SimdConstant, size_t, SimdConstant, SystemAllocPolicy> SimdMap;
|
||||
SimdMap simdMap_;
|
||||
|
||||
void setupABICall(uint32_t arg);
|
||||
|
||||
protected:
|
||||
MoveResolver moveResolver_;
|
||||
|
||||
public:
|
||||
using MacroAssemblerX86Shared::callWithExitFrame;
|
||||
using MacroAssemblerX86Shared::branch32;
|
||||
@ -96,7 +82,6 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
using MacroAssemblerX86Shared::store32;
|
||||
|
||||
MacroAssemblerX64()
|
||||
: inCall_(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1364,40 +1349,7 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
bind(&done);
|
||||
}
|
||||
|
||||
// Setup a call to C/C++ code, given the number of general arguments it
|
||||
// takes. Note that this only supports cdecl.
|
||||
//
|
||||
// In order for alignment to work correctly, the MacroAssembler must have a
|
||||
// consistent view of the stack displacement. It is okay to call "push"
|
||||
// manually, however, if the stack alignment were to change, the macro
|
||||
// assembler should be notified before starting a call.
|
||||
void setupAlignedABICall(uint32_t args);
|
||||
|
||||
// Sets up an ABI call for when the alignment is not known. This may need a
|
||||
// scratch register.
|
||||
void setupUnalignedABICall(uint32_t args, Register scratch);
|
||||
|
||||
// Arguments must be assigned to a C/C++ call in order. They are moved
|
||||
// in parallel immediately before performing the call. This process may
|
||||
// temporarily use more stack, in which case esp-relative addresses will be
|
||||
// automatically adjusted. It is extremely important that esp-relative
|
||||
// addresses are computed *after* setupABICall(). Furthermore, no
|
||||
// operations should be emitted while setting arguments.
|
||||
void passABIArg(const MoveOperand& from, MoveOp::Type type);
|
||||
void passABIArg(Register reg);
|
||||
void passABIArg(FloatRegister reg, MoveOp::Type type);
|
||||
|
||||
private:
|
||||
void callWithABIPre(uint32_t* stackAdjust);
|
||||
void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result);
|
||||
|
||||
public:
|
||||
// Emits a call to a C/C++ function, resolving all argument moves.
|
||||
void callWithABI(void* fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(AsmJSImmPtr imm, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(Address fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(Register fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
|
||||
void handleFailureWithHandlerTail(void* handler);
|
||||
|
||||
void makeFrameDescriptor(Register frameSizeReg, FrameType type) {
|
||||
|
@ -233,7 +233,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
||||
masm.push(framePtr);
|
||||
masm.push(reg_code);
|
||||
|
||||
masm.setupUnalignedABICall(3, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.passABIArg(framePtr); // BaselineFrame
|
||||
masm.passABIArg(OsrFrameReg); // InterpreterFrame
|
||||
masm.passABIArg(numStackValues);
|
||||
@ -362,7 +362,7 @@ JitRuntime::generateInvalidator(JSContext* cx)
|
||||
masm.reserveStack(sizeof(void*));
|
||||
masm.movq(rsp, r9);
|
||||
|
||||
masm.setupUnalignedABICall(3, rdx);
|
||||
masm.setupUnalignedABICall(rdx);
|
||||
masm.passABIArg(rax);
|
||||
masm.passABIArg(rbx);
|
||||
masm.passABIArg(r9);
|
||||
@ -588,7 +588,7 @@ GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass)
|
||||
masm.movq(rsp, r9);
|
||||
|
||||
// Call the bailout function.
|
||||
masm.setupUnalignedABICall(2, rax);
|
||||
masm.setupUnalignedABICall(rax);
|
||||
masm.passABIArg(r8);
|
||||
masm.passABIArg(r9);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
|
||||
@ -714,7 +714,7 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
||||
break;
|
||||
}
|
||||
|
||||
masm.setupUnalignedABICall(f.argc(), regs.getAny());
|
||||
masm.setupUnalignedABICall(regs.getAny());
|
||||
masm.passABIArg(cxreg);
|
||||
|
||||
size_t argDisp = 0;
|
||||
@ -831,7 +831,7 @@ JitRuntime::generatePreBarrier(JSContext* cx, MIRType type)
|
||||
MOZ_ASSERT(PreBarrierReg == rdx);
|
||||
masm.mov(ImmPtr(cx->runtime()), rcx);
|
||||
|
||||
masm.setupUnalignedABICall(2, rax);
|
||||
masm.setupUnalignedABICall(rax);
|
||||
masm.passABIArg(rcx);
|
||||
masm.passABIArg(rdx);
|
||||
masm.callWithABI(IonMarkFunction(type));
|
||||
|
@ -20,6 +20,7 @@
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
#include "jit/shared/CodeGenerator-shared-inl.h"
|
||||
|
||||
using namespace js;
|
||||
@ -1031,7 +1032,7 @@ CodeGeneratorX86::visitOutOfLineTruncate(OutOfLineTruncate* ool)
|
||||
{
|
||||
saveVolatile(output);
|
||||
|
||||
masm.setupUnalignedABICall(1, output);
|
||||
masm.setupUnalignedABICall(output);
|
||||
masm.passABIArg(input, MoveOp::DOUBLE);
|
||||
if (gen->compilingAsmJS())
|
||||
masm.callWithABI(AsmJSImm_ToInt32);
|
||||
@ -1121,7 +1122,7 @@ CodeGeneratorX86::visitOutOfLineTruncateFloat32(OutOfLineTruncateFloat32* ool)
|
||||
saveVolatile(output);
|
||||
|
||||
masm.push(input);
|
||||
masm.setupUnalignedABICall(1, output);
|
||||
masm.setupUnalignedABICall(output);
|
||||
masm.vcvtss2sd(input, input, input);
|
||||
masm.passABIArg(input.asDouble(), MoveOp::DOUBLE);
|
||||
|
||||
@ -1147,7 +1148,7 @@ CodeGeneratorX86::visitRandom(LRandom* ins)
|
||||
|
||||
masm.loadJSContext(temp);
|
||||
|
||||
masm.setupUnalignedABICall(1, temp2);
|
||||
masm.setupUnalignedABICall(temp2);
|
||||
masm.passABIArg(temp);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, math_random_no_outparam), MoveOp::DOUBLE);
|
||||
|
||||
|
@ -204,161 +204,6 @@ MacroAssemblerX86::finish()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::setupABICall(uint32_t args)
|
||||
{
|
||||
MOZ_ASSERT(!inCall_);
|
||||
inCall_ = true;
|
||||
|
||||
args_ = args;
|
||||
passedArgs_ = 0;
|
||||
stackForCall_ = 0;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::setupAlignedABICall(uint32_t args)
|
||||
{
|
||||
setupABICall(args);
|
||||
dynamicAlignment_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::setupUnalignedABICall(uint32_t args, Register scratch)
|
||||
{
|
||||
setupABICall(args);
|
||||
dynamicAlignment_ = true;
|
||||
|
||||
movl(esp, scratch);
|
||||
andl(Imm32(~(ABIStackAlignment - 1)), esp);
|
||||
push(scratch);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::passABIArg(const MoveOperand& from, MoveOp::Type type)
|
||||
{
|
||||
++passedArgs_;
|
||||
MoveOperand to = MoveOperand(StackPointer, stackForCall_);
|
||||
switch (type) {
|
||||
case MoveOp::FLOAT32: stackForCall_ += sizeof(float); break;
|
||||
case MoveOp::DOUBLE: stackForCall_ += sizeof(double); break;
|
||||
case MoveOp::INT32: stackForCall_ += sizeof(int32_t); break;
|
||||
case MoveOp::GENERAL: stackForCall_ += sizeof(intptr_t); break;
|
||||
default: MOZ_CRASH("Unexpected argument type");
|
||||
}
|
||||
enoughMemory_ &= moveResolver_.addMove(from, to, type);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::passABIArg(Register reg)
|
||||
{
|
||||
passABIArg(MoveOperand(reg), MoveOp::GENERAL);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::passABIArg(FloatRegister reg, MoveOp::Type type)
|
||||
{
|
||||
passABIArg(MoveOperand(reg), type);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::callWithABIPre(uint32_t* stackAdjust)
|
||||
{
|
||||
MOZ_ASSERT(inCall_);
|
||||
MOZ_ASSERT(args_ == passedArgs_);
|
||||
|
||||
if (dynamicAlignment_) {
|
||||
*stackAdjust = stackForCall_
|
||||
+ ComputeByteAlignment(stackForCall_ + sizeof(intptr_t),
|
||||
ABIStackAlignment);
|
||||
} else {
|
||||
*stackAdjust = stackForCall_
|
||||
+ ComputeByteAlignment(stackForCall_ + asMasm().framePushed(),
|
||||
ABIStackAlignment);
|
||||
}
|
||||
|
||||
asMasm().reserveStack(*stackAdjust);
|
||||
|
||||
// Position all arguments.
|
||||
{
|
||||
enoughMemory_ &= moveResolver_.resolve();
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
|
||||
MoveEmitter emitter(asMasm());
|
||||
emitter.emit(moveResolver_);
|
||||
emitter.finish();
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
// Check call alignment.
|
||||
Label good;
|
||||
test32(esp, Imm32(ABIStackAlignment - 1));
|
||||
j(Equal, &good);
|
||||
breakpoint();
|
||||
bind(&good);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
|
||||
{
|
||||
asMasm().freeStack(stackAdjust);
|
||||
if (result == MoveOp::DOUBLE) {
|
||||
asMasm().reserveStack(sizeof(double));
|
||||
fstp(Operand(esp, 0));
|
||||
loadDouble(Operand(esp, 0), ReturnDoubleReg);
|
||||
asMasm().freeStack(sizeof(double));
|
||||
} else if (result == MoveOp::FLOAT32) {
|
||||
asMasm().reserveStack(sizeof(float));
|
||||
fstp32(Operand(esp, 0));
|
||||
loadFloat32(Operand(esp, 0), ReturnFloat32Reg);
|
||||
asMasm().freeStack(sizeof(float));
|
||||
}
|
||||
if (dynamicAlignment_)
|
||||
pop(esp);
|
||||
|
||||
MOZ_ASSERT(inCall_);
|
||||
inCall_ = false;
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::callWithABI(void* fun, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(ImmPtr(fun));
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::callWithABI(AsmJSImmPtr fun, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(fun);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::callWithABI(const Address& fun, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(fun);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::callWithABI(Register fun, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
asMasm().call(fun);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerX86::handleFailureWithHandlerTail(void* handler)
|
||||
{
|
||||
@ -367,9 +212,9 @@ MacroAssemblerX86::handleFailureWithHandlerTail(void* handler)
|
||||
movl(esp, eax);
|
||||
|
||||
// Call the handler.
|
||||
setupUnalignedABICall(1, ecx);
|
||||
passABIArg(eax);
|
||||
callWithABI(handler);
|
||||
asMasm().setupUnalignedABICall(ecx);
|
||||
asMasm().passABIArg(eax);
|
||||
asMasm().callWithABI(handler);
|
||||
|
||||
Label entryFrame;
|
||||
Label catch_;
|
||||
@ -589,4 +434,94 @@ MacroAssembler::reserveStack(uint32_t amount)
|
||||
framePushed_ += amount;
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// ABI function calls.
|
||||
|
||||
void
|
||||
MacroAssembler::setupUnalignedABICall(Register scratch)
|
||||
{
|
||||
setupABICall();
|
||||
dynamicAlignment_ = true;
|
||||
|
||||
movl(esp, scratch);
|
||||
andl(Imm32(~(ABIStackAlignment - 1)), esp);
|
||||
push(scratch);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABIPre(uint32_t* stackAdjust, bool callFromAsmJS)
|
||||
{
|
||||
MOZ_ASSERT(inCall_);
|
||||
uint32_t stackForCall = abiArgs_.stackBytesConsumedSoFar();
|
||||
|
||||
if (dynamicAlignment_) {
|
||||
// sizeof(intptr_t) accounts for the saved stack pointer pushed by
|
||||
// setupUnalignedABICall.
|
||||
stackForCall += ComputeByteAlignment(stackForCall + sizeof(intptr_t),
|
||||
ABIStackAlignment);
|
||||
} else {
|
||||
uint32_t alignmentAtPrologue = callFromAsmJS ? sizeof(AsmJSFrame) : 0;
|
||||
stackForCall += ComputeByteAlignment(stackForCall + framePushed() + alignmentAtPrologue,
|
||||
ABIStackAlignment);
|
||||
}
|
||||
|
||||
*stackAdjust = stackForCall;
|
||||
reserveStack(stackForCall);
|
||||
|
||||
// Position all arguments.
|
||||
{
|
||||
enoughMemory_ &= moveResolver_.resolve();
|
||||
if (!enoughMemory_)
|
||||
return;
|
||||
|
||||
MoveEmitter emitter(*this);
|
||||
emitter.emit(moveResolver_);
|
||||
emitter.finish();
|
||||
}
|
||||
|
||||
assertStackAlignment(ABIStackAlignment);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABIPost(uint32_t stackAdjust, MoveOp::Type result)
|
||||
{
|
||||
freeStack(stackAdjust);
|
||||
if (result == MoveOp::DOUBLE) {
|
||||
reserveStack(sizeof(double));
|
||||
fstp(Operand(esp, 0));
|
||||
loadDouble(Operand(esp, 0), ReturnDoubleReg);
|
||||
freeStack(sizeof(double));
|
||||
} else if (result == MoveOp::FLOAT32) {
|
||||
reserveStack(sizeof(float));
|
||||
fstp32(Operand(esp, 0));
|
||||
loadFloat32(Operand(esp, 0), ReturnFloat32Reg);
|
||||
freeStack(sizeof(float));
|
||||
}
|
||||
if (dynamicAlignment_)
|
||||
pop(esp);
|
||||
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(inCall_);
|
||||
inCall_ = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABINoProfiler(Register fun, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(fun);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssembler::callWithABINoProfiler(const Address& fun, MoveOp::Type result)
|
||||
{
|
||||
uint32_t stackAdjust;
|
||||
callWithABIPre(&stackAdjust);
|
||||
call(fun);
|
||||
callWithABIPost(stackAdjust, result);
|
||||
}
|
||||
|
||||
//}}} check_macroassembler_style
|
||||
|
@ -24,14 +24,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
const MacroAssembler& asMasm() const;
|
||||
|
||||
private:
|
||||
// Number of bytes the stack is adjusted inside a call to C. Calls to C may
|
||||
// not be nested.
|
||||
bool inCall_;
|
||||
uint32_t args_;
|
||||
uint32_t passedArgs_;
|
||||
uint32_t stackForCall_;
|
||||
bool dynamicAlignment_;
|
||||
|
||||
struct Double {
|
||||
double value;
|
||||
AbsoluteLabel uses;
|
||||
@ -99,7 +91,6 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
using MacroAssemblerX86Shared::call;
|
||||
|
||||
MacroAssemblerX86()
|
||||
: inCall_(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -1141,40 +1132,7 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
bind(&done);
|
||||
}
|
||||
|
||||
// Setup a call to C/C++ code, given the number of general arguments it
|
||||
// takes. Note that this only supports cdecl.
|
||||
//
|
||||
// In order for alignment to work correctly, the MacroAssembler must have a
|
||||
// consistent view of the stack displacement. It is okay to call "push"
|
||||
// manually, however, if the stack alignment were to change, the macro
|
||||
// assembler should be notified before starting a call.
|
||||
void setupAlignedABICall(uint32_t args);
|
||||
|
||||
// Sets up an ABI call for when the alignment is not known. This may need a
|
||||
// scratch register.
|
||||
void setupUnalignedABICall(uint32_t args, Register scratch);
|
||||
|
||||
// Arguments must be assigned to a C/C++ call in order. They are moved
|
||||
// in parallel immediately before performing the call. This process may
|
||||
// temporarily use more stack, in which case esp-relative addresses will be
|
||||
// automatically adjusted. It is extremely important that esp-relative
|
||||
// addresses are computed *after* setupABICall(). Furthermore, no
|
||||
// operations should be emitted while setting arguments.
|
||||
void passABIArg(const MoveOperand& from, MoveOp::Type type);
|
||||
void passABIArg(Register reg);
|
||||
void passABIArg(FloatRegister reg, MoveOp::Type type);
|
||||
|
||||
private:
|
||||
void callWithABIPre(uint32_t* stackAdjust);
|
||||
void callWithABIPost(uint32_t stackAdjust, MoveOp::Type result);
|
||||
|
||||
public:
|
||||
// Emits a call to a C/C++ function, resolving all argument moves.
|
||||
void callWithABI(void* fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(AsmJSImmPtr fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(const Address& fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
void callWithABI(Register fun, MoveOp::Type result = MoveOp::GENERAL);
|
||||
|
||||
// Used from within an Exit frame to handle a pending exception.
|
||||
void handleFailureWithHandlerTail(void* handler);
|
||||
|
||||
|
@ -20,6 +20,8 @@
|
||||
|
||||
#include "jsscriptinlines.h"
|
||||
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
|
||||
using namespace js;
|
||||
using namespace js::jit;
|
||||
|
||||
@ -222,7 +224,7 @@ JitRuntime::generateEnterJIT(JSContext* cx, EnterJitType type)
|
||||
masm.push(framePtr);
|
||||
masm.push(jitcode);
|
||||
|
||||
masm.setupUnalignedABICall(3, scratch);
|
||||
masm.setupUnalignedABICall(scratch);
|
||||
masm.passABIArg(framePtr); // BaselineFrame
|
||||
masm.passABIArg(OsrFrameReg); // InterpreterFrame
|
||||
masm.passABIArg(numStackValues);
|
||||
@ -353,7 +355,7 @@ JitRuntime::generateInvalidator(JSContext* cx)
|
||||
masm.reserveStack(sizeof(void*));
|
||||
masm.movl(esp, ecx);
|
||||
|
||||
masm.setupUnalignedABICall(3, edx);
|
||||
masm.setupUnalignedABICall(edx);
|
||||
masm.passABIArg(eax);
|
||||
masm.passABIArg(ebx);
|
||||
masm.passABIArg(ecx);
|
||||
@ -585,7 +587,7 @@ GenerateBailoutThunk(JSContext* cx, MacroAssembler& masm, uint32_t frameClass)
|
||||
masm.movl(esp, ebx);
|
||||
|
||||
// Call the bailout function. This will correct the size of the bailout.
|
||||
masm.setupUnalignedABICall(2, ecx);
|
||||
masm.setupUnalignedABICall(ecx);
|
||||
masm.passABIArg(eax);
|
||||
masm.passABIArg(ebx);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, Bailout));
|
||||
@ -733,7 +735,7 @@ JitRuntime::generateVMWrapper(JSContext* cx, const VMFunction& f)
|
||||
break;
|
||||
}
|
||||
|
||||
masm.setupUnalignedABICall(f.argc(), regs.getAny());
|
||||
masm.setupUnalignedABICall(regs.getAny());
|
||||
masm.passABIArg(cxreg);
|
||||
|
||||
size_t argDisp = 0;
|
||||
@ -857,7 +859,7 @@ JitRuntime::generatePreBarrier(JSContext* cx, MIRType type)
|
||||
MOZ_ASSERT(PreBarrierReg == edx);
|
||||
masm.movl(ImmPtr(cx->runtime()), ecx);
|
||||
|
||||
masm.setupUnalignedABICall(2, eax);
|
||||
masm.setupUnalignedABICall(eax);
|
||||
masm.passABIArg(ecx);
|
||||
masm.passABIArg(edx);
|
||||
masm.callWithABI(IonMarkFunction(type));
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "jsobjinlines.h"
|
||||
|
||||
#include "gc/Nursery-inl.h"
|
||||
#include "jit/MacroAssembler-inl.h"
|
||||
#include "vm/Shape-inl.h"
|
||||
|
||||
using mozilla::ArrayLength;
|
||||
@ -160,7 +161,7 @@ UnboxedLayout::makeConstructorCode(JSContext* cx, HandleObjectGroup group)
|
||||
masm.PushRegsInMask(liveVolatileRegisters);
|
||||
|
||||
masm.mov(ImmPtr(cx->runtime()), scratch1);
|
||||
masm.setupUnalignedABICall(2, scratch2);
|
||||
masm.setupUnalignedABICall(scratch2);
|
||||
masm.passABIArg(scratch1);
|
||||
masm.passABIArg(object);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, PostWriteBarrier));
|
||||
|
@ -30,16 +30,19 @@ XDRBuffer::grow(size_t n)
|
||||
MOZ_ASSERT(n > size_t(limit - cursor));
|
||||
|
||||
const size_t MIN_CAPACITY = 8192;
|
||||
const size_t MAX_CAPACITY = size_t(INT32_MAX) + 1;
|
||||
size_t offset = cursor - base;
|
||||
size_t newCapacity = mozilla::RoundUpPow2(offset + n);
|
||||
if (newCapacity < MIN_CAPACITY)
|
||||
newCapacity = MIN_CAPACITY;
|
||||
if (isUint32Overflow(newCapacity)) {
|
||||
MOZ_ASSERT(offset <= MAX_CAPACITY);
|
||||
if (n > MAX_CAPACITY - offset) {
|
||||
js::gc::AutoSuppressGC suppressGC(cx());
|
||||
JS_ReportErrorNumber(cx(), GetErrorMessage, nullptr, JSMSG_TOO_BIG_TO_ENCODE);
|
||||
return false;
|
||||
}
|
||||
size_t newCapacity = mozilla::RoundUpPow2(offset + n);
|
||||
if (newCapacity < MIN_CAPACITY)
|
||||
newCapacity = MIN_CAPACITY;
|
||||
|
||||
MOZ_ASSERT(newCapacity <= MAX_CAPACITY);
|
||||
void* data = js_realloc(base, newCapacity);
|
||||
if (!data) {
|
||||
ReportOutOfMemory(cx());
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user