Merge m-c to b2ginbound, a=merge

This commit is contained in:
Wes Kocher 2015-08-17 17:15:50 -07:00
commit d56847e545
210 changed files with 4088 additions and 2377 deletions

View File

@ -224,7 +224,7 @@ DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
aChildDoc->mParentDoc = this;
if (aCreating) {
ProxyCreated(aChildDoc, 0);
ProxyCreated(aChildDoc, Interfaces::DOCUMENT | Interfaces::HYPERTEXT);
}
return true;

View File

@ -52,7 +52,6 @@ let CustomizationHandler = {
},
_customizationChange: function() {
gHomeButton.updatePersonalToolbarStyle();
PlacesToolbarHelper.customizeChange();
},

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 978 B

View File

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

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

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

View File

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

View File

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

View File

@ -31,3 +31,4 @@ redo.pth:python/redo
requests.pth:python/requests
rsa.pth:python/rsa
futures.pth:python/futures
ecc.pth:python/PyECC

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

@ -53,6 +53,9 @@ public:
void Mute();
void Unmute();
void Suspend();
void Resume();
void StartRendering(Promise* aPromise);
void OfflineShutdown();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -346,6 +346,7 @@ function isOverridableField(initialCSU, csu, field)
function listGCTypes() {
return [
'js::gc::Cell',
'JSObject',
'JSString',
'JSFatInlineString',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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